Notes on score submission with django-lti-provider and Canvas LMS

django-lti-provider is a Python library for integrating Django apps with an LTI consumer like Canvas. django-lti-provider uses pylti to make LTI oauth requests. The lti library could also be used for this same purpose.

django-lti-provider has documentation on how to set everything up in Django, but I want to document a few challenges I ran into when trying to get grade submission to Canvas working.

You need to learn the Canvas interface and its concepts in order to figure out where you're going to integrate the tool. Integration can be done in Canvas's rich-text editor by defining a toolbar button, and then allowing an asset's iframe to be embedded in the Canvas content. This is a great method for its flexibility, but keep in mind that the LTI authentication step won't occur on the content you embed. The content author will be authenticated when they click the toolbar button, but the student viewing the content won't be. So, if you're expecting to do grade passback, this method isn't a good option. For my purposes, I ended using an Canvas's Assignment model, and connecting my tool to it using the External Tool option. Now, when a student views the assignment, a POST request is made to my tool containing auth credentials for automatic authentication.

Also when you're developing, keep in mind that PyLTI doesn't yet give much detail about why a score submission request failed. So if you see django-lti-provider displaying a "Post grade failed" error, add the pylti logger to your local_settings.py and look at the actual response that Canvas gave:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
        },
    },
    'loggers': {
        'pylti': {
            'handlers': ['console'],
            'level': os.getenv('DJANGO_LOG_LEVEL', 'DEBUG'),
        },
    },
}

There are a few scenarios I've found that cause this to fail:

I expect that we'll improve the behavior of django-lti-provider and PyLTI to make them easier to use, and more aware of these scenarios.