{"id":13833909,"url":"https://github.com/ccnmtl/django-lti-provider","last_synced_at":"2025-05-08T20:57:21.917Z","repository":{"id":39741101,"uuid":"62947699","full_name":"ccnmtl/django-lti-provider","owner":"ccnmtl","description":"django-lti-provider adds LTI functionality for the Django web framework. This work began as a port of MIT's LTI Flask Sample, which demonstrates a sample LTI provider for the Flask Framework based on the Python LTI library, PyLTI.","archived":false,"fork":false,"pushed_at":"2024-04-12T21:16:59.000Z","size":2620,"stargazers_count":45,"open_issues_count":7,"forks_count":28,"subscribers_count":7,"default_branch":"main","last_synced_at":"2024-04-14T05:09:37.505Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","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/ccnmtl.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.txt","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":"AUTHORS.md","dei":null}},"created_at":"2016-07-09T12:07:22.000Z","updated_at":"2024-04-15T15:17:22.929Z","dependencies_parsed_at":"2023-12-14T17:42:29.847Z","dependency_job_id":"adce496e-1bd4-41ce-9b3b-8d1b6045b8ab","html_url":"https://github.com/ccnmtl/django-lti-provider","commit_stats":{"total_commits":586,"total_committers":18,"mean_commits":32.55555555555556,"dds":0.6740614334470989,"last_synced_commit":"43cc206619e085b1cfb5b3b13957a7d0152fb4df"},"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ccnmtl%2Fdjango-lti-provider","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ccnmtl%2Fdjango-lti-provider/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ccnmtl%2Fdjango-lti-provider/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ccnmtl%2Fdjango-lti-provider/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ccnmtl","download_url":"https://codeload.github.com/ccnmtl/django-lti-provider/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238044093,"owners_count":19407128,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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-08-04T13:00:40.641Z","updated_at":"2025-05-08T20:57:21.910Z","avatar_url":"https://github.com/ccnmtl.png","language":"Python","funding_links":[],"categories":["Django"],"sub_categories":["Repositories"],"readme":"[![Actions Status](https://github.com/ccnmtl/django-lti-provider/workflows/build-and-test/badge.svg)](https://github.com/ccnmtl/django-lti-provider/actions)\n\ndjango-lti-provider **only supports LTI 1.1**, which is now deprecated. For\n[LTI 1.3](https://www.imsglobal.org/spec/lti/v1p3) support, see:\n* [PyLTI1p3](https://pypi.org/project/PyLTI1p3/)\n* [django-lti](https://pypi.org/project/django-lti/)\n* [Mediathread's LTI documentation](https://github.com/ccnmtl/mediathread/tree/master/lti_auth#readme) may also be helpful.\n\n# Documentation\n\ndjango-lti-provider provides [Learning Tools Interoperability](https://en.wikipedia.org/wiki/Learning_Tools_Interoperability)\n(LTI) functionality for the Django web framework. This\nwork began as a port of MIT's [LTI Flask Sample](https://github.com/mitodl/mit_lti_flask_sample),\nwhich demonstrates a sample LTI provider for the Flask Framework based on\nthe [Python LTI library, PyLTI](https://github.com/mitodl/pylti).\n\nAdditional work was completed to provide fuller functionality and support the idiosyncrasies of various LMS systems\nsuch as Canvas, Blackboard, Moodle and EdEx.\n\ndjango-lti-provider offers:\n\n* an authentication backend to complete an oAuth handshake (optional)\n* a templated view for config.xml generation\n* a templated landing page view for those LMS who do not have a 'launch in new tab' option, i.e. Canvas\n* support for Canvas' [embedded tool extensions](https://canvas.instructure.com/doc/api/file.editor_button_tools.html)\n* routing for multiple external assignment end points.\n\nThe library is used at Columbia University's [Center for Teaching And Learning](http://ctl.columbia.edu).\n\nSee an example Django app using the library at [Django LTI Provider Example](https://github.com/ccnmtl/django-lti-provider-example).\n\n## Installation\n\nYou can install ```django-lti-provider``` through ```pip```:\n\n```python\n$ pip install django-lti-provider\n```\nOr, if you're using virtualenv, add ```django-lti-provider``` to your ```requirements.txt```.\n\nAdd to ```INSTALLED_APPS``` in your ```settings.py```::\n\n```python\n  'lti_provider',\n```\n\n## Configuration\n\n### Basic setup steps\n\nAdd the URL route:\n\n```python\npath('lti/', include('lti_provider.urls'))\n\n```\n\nAdd the LTIBackend to your AUTHENTICATION_BACKENDS:\n\n```python\nAUTHENTICATION_BACKENDS = [\n  'django.contrib.auth.backends.ModelBackend',\n  'lti_provider.auth.LTIBackend',\n]\n```\n\nComplete a migration\n\n```python\n./manage.py migrate\n```\n\n### Primary LTI config\n\nThe ``LTI_TOOL_CONFIGURATION`` variable in your ``settings.py`` allows you to\nconfigure your application's config.xml and set other options for the library. ([Edu Apps](https://www.edu-apps.org/code.html) has good documentation\non configuring an lti provider through xml.)\n\n```python\nLTI_TOOL_CONFIGURATION = {\n    'title': '\u003cyour lti provider title\u003e',\n    'description': '\u003cyour description\u003e',\n    'launch_url': 'lti/',\n    'embed_url': '\u003cthe view endpoint for an embed tool\u003e' or '',\n    'embed_icon_url': '\u003cthe icon url to use for an embed tool\u003e' or '',\n    'embed_tool_id': '\u003cthe embed tool id\u003e' or '',\n    'landing_url': '\u003cthe view landing page\u003e',\n    'course_aware': \u003cTrue or False\u003e,\n    'course_navigation': \u003cTrue or False\u003e,\n    'new_tab': \u003cTrue or False\u003e,\n    'frame_width': \u003cwidth in pixels\u003e,\n    'frame_height': \u003cheight in pixels\u003e,\n    'custom_fields': \u003cdictionary\u003e,\n    'allow_ta_access': \u003cTrue or False\u003e,\n    'assignments': {\n        '\u003cname\u003e': '\u003clanding_url\u003e',\n        '\u003cname\u003e': '\u003clanding_url\u003e',\n        '\u003cname\u003e': '\u003clanding_url\u003e',\n    },\n}\n```\n\nTo stash custom properties in your session, populate the `LTI_PROPERTY_LIST_EX` variable in your `settings.py`. This is useful for LMS specific `custom_x` parameters that will be needed later. The default value for `LTI_PROPERTY_LIST_EX` is: `['custom_canvas_user_login_id', 'context_title', 'lis_course_offering_sourcedid', 'custom_canvas_api_domain']`.\n\n```python\nLTI_PROPERTY_LIST_EX = ['custom_parameter1', 'custom_parameter2']\n```\n\n### Using a cookie based session\n\nFor simplest scenarios you can store data for the LTI request in a session cookie.\nThis is the quickest way to get up and running, and due to Django's tamper\nproof cookie session (assuming a secure secret key) it is a safe option.\nPlease note that you will need to add the following settings in your\napplications `settings.py` to make use of cookies:\n\n```python\nSESSION_ENGINE = \"django.contrib.sessions.backends.signed_cookies\"\nSESSION_COOKIE_SAMESITE = 'None'\nSESSION_COOKIE_SECURE = True\n```\n\nBecause Canvas sends the information that we are storing in a `POST`\nrequest on the LTI launch, we need to relax the restriction of cookies\nonly being allowed to be set from the same site. For more information on\n`SESSION_COOKIE_SAMESITE` [read here](https://docs.djangoproject.com/en/3.0/ref/settings/#session-cookie-samesite).\n\nFor more information on why `SESSION_COOKIE_SAMESITE` and `SESSION_COOKIE_SECURE`\nare needed, if you are choosing to make use of cookies, please read\n[here.](https://community.canvaslms.com/t5/Developers-Group/SameSite-Cookies-and-Canvas/ba-p/257967)\n\n### Extra LTI Configuration values\n\nTo specify a custom username property, add the `LTI_PROPERTY_USER_USERNAME` variable to your `settings.py`. By default, `LTI_PROPERTY_USER_USERNAME` is `custom_canvas_user_login_id`. This value can vary depending on your LMS.\n\nTo pass through extra LTI parameters to your provider, populate the `LTI_EXTRA_PARAMETERS` variable in your `settings.py`.\nThis is useful for custom parameters you may specify at installation time.\n\n```python\nLTI_EXTRA_PARAMETERS = ['lti_version']  # example\n```\n\nThe ``PYLTI_CONFIG`` variable in your ``settings.py`` configures the\napplication consumers and secrets.\n\n```python\nPYLTI_CONFIG = {\n    'consumers': {\n        '\u003crandom number string\u003e': {\n            'secret': '\u003crandom number string\u003e'\n        }\n    }\n}\n```\n\n### Canvas and LTI iframes\n\nSince LTI tools live within an iframe on Canvas, you **might** need\nadjust your `X_FRAME_OPTIONS` setting to allow for the LTI tool to be\nopened within the iframe. To the best of our knowledge you probably\ndon't have to adjust this setting, as Canvas has built a workaround.\nFor more info [read here](https://github.com/ccnmtl/django-lti-provider/issues/280)\n\nThis ensures that the Django application will allow requests from your\norgs Canvas instance. For more on `X_FRAME_OPTIONS` please\n[consult here](https://docs.djangoproject.com/en/3.0/ref/clickjacking/#module-django.middleware.clickjacking).\n\n### If you are using a load balancer\n\nIf you happen to have a deployment scenario where you have load balancer\nlistening on https and routing traffic to nodes that are listening to HTTP,\nyou will need to add the following line of configuration in `settings.py`:\n\n```python\nSECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')\n```\n\nThis ensures the correct `launch_url` is generated for the LTI tool.\nFor more on this setting, [read here](https://docs.djangoproject.com/en/3.1/ref/settings/#secure-proxy-ssl-header).\n\n## Assignments\n\nTo support multiple assignments:\n\n* Create multiple endpoint views\n* Add the assignment urls to the `LTI_TOOL_CONFIGURATION['assignments']` map\n* Add an assignment, using the External Tool option.\n   * Canvas: https://community.canvaslms.com/docs/DOC-10384-4152501360\n* Update the URL to be `https://\u003cyour domain name\u003e/lti/assignment/\u003cassignment_name\u003e`\n* The `assignment_name` variable should match a landing_url in the LTI_TOOL_CONFIGURATION dict.\n* Full example here: [Django LTI Provider Example](https://github.com/ccnmtl/django-lti-provider-example).\n\nOR\n\n* Create a single named endpoint that accepts an id\n* On Post, django-lti-provider will attempt to reverse the assignment_name/id and then redirect to that view.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fccnmtl%2Fdjango-lti-provider","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fccnmtl%2Fdjango-lti-provider","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fccnmtl%2Fdjango-lti-provider/lists"}