{"id":21258482,"url":"https://github.com/ubc/lti-shim","last_synced_at":"2026-04-25T18:32:19.040Z","repository":{"id":37529761,"uuid":"211153234","full_name":"ubc/lti-shim","owner":"ubc","description":null,"archived":false,"fork":false,"pushed_at":"2023-12-05T20:15:40.000Z","size":3676,"stargazers_count":3,"open_issues_count":6,"forks_count":0,"subscribers_count":3,"default_branch":"prototype4","last_synced_at":"2026-01-01T21:51:35.106Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ubc.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-09-26T18:13:06.000Z","updated_at":"2024-11-17T10:35:32.000Z","dependencies_parsed_at":"2023-11-23T11:36:26.599Z","dependency_job_id":"d401434a-ef36-4a10-9b81-9094c54f7dad","html_url":"https://github.com/ubc/lti-shim","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ubc/lti-shim","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ubc%2Flti-shim","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ubc%2Flti-shim/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ubc%2Flti-shim/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ubc%2Flti-shim/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ubc","download_url":"https://codeload.github.com/ubc/lti-shim/tar.gz/refs/heads/prototype4","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ubc%2Flti-shim/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32273213,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-25T18:29:39.964Z","status":"ssl_error","status_checked_at":"2026-04-25T18:29:32.149Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-21T04:09:05.128Z","updated_at":"2026-04-25T18:32:19.025Z","avatar_url":"https://github.com/ubc.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"## LTI Shim Overview\n\nThe LTI Shim acts like a Learning Tools Interoperability (LTI) 1.3 proxy with\nthe goal of protecting student privacy. A Platform (such as Canvas) will add\nthe LTI Shim as a Tool. A Tool, such as math homework system Webwork, adds the\nLTI Shim as a Platform. The LTI Shim can then be configured to connect these\ntwo Platform and Tool together.  LTI requests is first passed through a privacy\nfilter that replaces real personal information with an anonymized identity (or\nvice versa in reverse), then forwarded to the target Platform or Tool.\n\n![LTI Shim Overview](doc/img/lti_shim_overview.png)\n\nThe LTI Shim implements the LTI 1.3 spec and aims to be compatible with any LTI\n1.3 compliant implementations for both Platform and Tool. LTI service specs such as the LTI Advantage suite is implemented (NRPS, AGS, Deep Linking).\n\nMore technical detail is available in the [Wiki](https://github.com/ubc/lti-shim/wiki).\n\n## Development\n\n### Develop in Docker\n\n#### Initial setup:\n\n```\ngit clone --recurse-submodules -b prototype1 https://github.com/ubc/lti-shim.git\ncd lti-shim/\ncp .env.example .env\ncd laradock-lti-shim/\n```\n\nEdit `laradock-lti-shim/docker-compose.yml` and set `PLATFORM_AUTH_ENDPOINT` to point to your own IP address.\n\n```\ndocker-compose up -d nginx postgres workspace adminer ltijs-demo-server\ndocker-compose exec -u laradock workspace bash\n  workspace$ composer install\n  workspace$ artisan key:generate\n  workspace$ artisan migrate:refresh --seed\n  workspace$ npm install\n  workspace$ npm run development\n```\n\n* The main app is accessible from http://localhost:8300/#/\n  * See routes/web.php for valid locations\n  * App log is located in `storage/logs/`, they are named by date. Note that the containers seems to be on UTC though.\n  * Development admin user login (added as part of seeded data):\n    * Email: admin@example.com\n    * Password: password\n* Workspace is a container for executing composer/artisan commands on your project. This means you don't need to have composer/artisan installed locally.\n* Adminer provides a simple front-end to the database and is accessible at http://localhost:8081/\n  * System: PostgreSQL\n  * Server: postgres\n  * Username: default\n  * Password: secret\n  * Database: default\n* Ltijs Demo Server is used for development testing as a target tool.\n  * OAuth client id: CLIENTID\n  * LTI launch OIDC login URL: http://localhost:4000/login\n  * LTI launch authorization response URL: http://localhost:4000/\n  * LTI launch target (target_link_uri): http://localhost:4000/\n  * JWKS url\n    * inside Laradock: http://ltijs-demo-server:4000/keys\n    * outside Laradock: http://localhost:4000/keys\n\nAfter the initial setup, you can bring up the containers and access the workspace with just the docker-compose commands.\n\n#### Database Setup\n\nDatabase migration needs to be run manually whenever new migrations are added or when starting a fresh instance. These migrations needs to be run in the workspace container.\n\n```\ndocker-compose exec -u laradock workspace bash\n  workspace$ artisan migrate\n```\n\nMigrations can be rolled back in bulk (`artisan migrate:rollback`) or with the addition of the `--step=N` option for finer control, rolling back N number of migration files.\n\nThe database can be completely blown away and rebuilt from scratch using `artisan migrate:refresh`.\n\n##### Seeded Data\n\nTest data for development use can be seeded using `artisan db:seed`. This can be combined with rebuilding the database from scratch as `artisan migrate:refresh --seed`.\n\nThe current seeded data works with this Reference Implemention platform: https://lti-ri.imsglobal.org/platforms/643\n\nIt should direct a launch from that RI platform to the Ltijs demo server brought up locally with docker-compose.\n\n#### UI Setup\n\nLaravel has its own configuration built on top of webpack, which means some setup is needed to start development. We need to install all the UI packages and then call webpack to compile all the new assets:\n\n```\nnpm install\nnpm run development\n```\n\nChanges to UI files requires us to recompile assets. In order to do this automatically, leave this command running:\n\n```\nnpm run watch\n```\n\nThe watch command still requires you to hit refresh in the browser. This can be a chore for vue development, so we can enable hot-module-replacement where assets are automatically updated without having to hit refresh. The command is:\n\n```\nnpm run hot\n```\n\nLaravel uses VueJS for JavaScript framework and Bootstrap 4 for CSS.\n\n#### Run Tests\n\nMake sure you're in workspace, run `phpunit` or `artisan test` to run all the tests.\n\n```\ndocker-compose exec -u laradock workspace bash\n  workspace$ phpunit\n  workspace$ artisan test\n```\n\nYou can limit the test you run with the `--filter` parameter, for example, to run only the NrpsTest:\n\n```\n $ artisan test --filter NrpsTest\n $ phpunit --filter NrpsTest\n```\n\n`artisan test` provides a fancier output and will stop on the first test failure. It should also pass all parameters to the underlying `phpunit`. But the option to call `phpunit` directly might be valuable in some circumstances.\n\n#### LTI Module\n\nLTI processing code is located in `lti/`. Different LTI functionalities are split into different specs, so we've organized them in the same way in `lti/Specs/`. The core spec is in `lti/Specs/Launch/`. Taking the launch as an example, it's been divided up into the Tool side and the Platform side in the form of `ToolLaunch` and `PlatformLaunch`.\n\nThe initial launch we receive from Canvas is processed by `ToolLaunch` since we're acting as a tool. When we pass the launch to the target tool, it is processed by `PlatformLaunch` since we're acting as a platform.\n\n##### Configuration\n\nSome LTI configuration is not stored in the database but uses Laravel's built in configuration system located at `config/lti.php`.\n\n* *iss* - the iss parameter can just be the app's url\n* *platform_id* - the shim's own platform information is stored in the `platforms` table, we need the id to that row.\n* *tool_id* - the shim's own tool information is stored in the `tools` table, we need the id to that row.\n\n##### RSA Key Storage\n\nThe JSON Web Token (JWT) spec uses RSA public/private keys. Keys are all stored as in the JSON Web Key (JWK) format. There are two types of keys, one used for signatures and one used for encryption.\n\nSigned JWT (JWS) are used on both platform and tool side for the `id_token` parameter. As such, our platform and tool sides each have their own set of public/private keys. This is stored in the `platform_keys` and `tool_keys` table.\n\nEncrypted JWT (JWE) is used for session state (see below). The keys are stored in the `encryption_keys` table.\n\nNote that the Reference Implementation uses PEM formatted keys, so you'll have to use a JWK/PEM converter.\n\nVisiting [http://localhost/lti/keygen](http://localhost/lti/keygen) will output a public/private keypair in JWK format in the logs as debug messages.\n\n##### Session State\n\nDue to SameSite cookie enforcement coming into effect, we're trying to avoid using cookies for the LTI requests. This means we can't use stock Laravel sessions, as those use cookies to store session IDs. The alternative is to the various state parameters specified by LTI to store the session ID. When acting as a Tool, this is the `state` param. When acting as a Platform, this is the `lti_message_hint` param.\n\nTo preserve privacy and to protect against CSRF, the state string is an encrypted JWT (JWE). This does result in a rather long string, about 1000 characters. We will need to be careful that it doesn't get too long that it doesn't fit into a GET request. Not an issue for the POST only `state` param, but the spec does require that `lti_message_hint` be both GET and POST compatible.\n\n##### Data Filters\n\nEach implemented spec has their own set of filters. For example, the LTI launch filters are located in `lti/Specs/Launch/Filters`. Each launch filters implements the `FilterInterface` in `lti/Specs/Launch/Filters/FilterInterface.php`. The `filter()` method takes an array and a `LtiSession` model. The array needs to be filtered, removing/renaming key/values as necessary, and then returned. To apply a new filter, add it to the `$filters` list in `PlatformLaunch`.\n\n#### Troubleshooting\n\n* If you're not the first user in the system (i.e.: uid/gid is not 1000/1000). You will have to edit `laradock-lti-shim/.env` and  change WORKSPACE_PUID, WORKSPACE_PGID, PHP_FPM_PUID, and PHP_FPM_PGID to your uid/gid. This is to avoid permission issues with the files created inside docker containers. E.g.: if you `composer install` a library while in the workspace container, the files downloaded by composer will be corrected own by you and not some other user.\n\n* If dependencies seem out of date, you might need to rebuild the relevant docker images while avoiding the docker cache (where the outdated dependencies are stored), so something like: `docker-compose build --no-cache nginx postgres workspace adminer php-fpm`\n\n* If Laradock has issues after an update from upstream Laradock:\n  * You probably need to merge new entries in `env-example` into `.env`\n  * You probably need to rebuild the docker images. Just in case, you should tell docker to attempt to pull newer versions of the images too while building, something like: `docker-compose build --pull nginx postgres workspace adminer php-fpm`\n\n* If you just added a class, e.g. a database seeder, and composer complains its missing/autoloader doesn't seem to pick it up, you might need to regenerate the autoloader: `composer dump-autoload`\n\n* LTI launch/NRPS calls end up on a 404 page: Edit Laradock's `docker-compose.yml`, set ltijs-demo-server.environment.PLATFORM_AUTH_ENDPOINT to your own IP address.\n\n## Deployment\n\nIt would be advisable to run `artisan key:generate` to generate a different `APP_KEY` from development.\n\nRun `artisan config:cache` to combine all configuration files into a single file for faster loading. This shouldn't be used during development as configuration files can change.\n\nDatabase credentials in `.env` should be replaced with production values.\n\nUI assets needs to be compiled and minified, this is done with: `npm run production`\n\n## Contributing\n\n## License\n\nThe LTI-Shim project is open-source software licensed under the [AGPL-3.0](https://opensource.org/licenses/AGPL-3.0).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fubc%2Flti-shim","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fubc%2Flti-shim","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fubc%2Flti-shim/lists"}