Writing LTI Stuff

This page goes over the basics of creating an app that leverages LTI. There's a lot of great links at the bottom that may help out, but it's probably a good idea to at least read the intro first to get a feel for what LTI does exactly.

ruby | java | php | python | .NET

Introduction

Identity assertion is a one-way "handshake" coming from the learning platform (consumer) to the app (provider).

The main thing with LTI is the identity assertion. LTI is a way for one system (the tool consumer, typically an LMS) to send a user to another system (the tool provider, some service that integrates with the LMS -- sorry, I know the names are confusing. I've tried using colors to help make things clearer, but that may just make it worse...) in a trusted way. The most common reason for the trust assertion is to allow the user to be automatically signed in and directed to a specific course or module when the provider renders content.

Tools (providers) are launched from within the learning platform (consumer) in an iframe so they feel like a native part of the platform.

The consumer and provider have some predefined relationship via a consumer key and shared secret that are used to sign any messages passed between systems. All messages are signed with an OAuth signature that can be verified by either party. For the most part information only travels one way, from the consumer to the provider.

The identity assertion happens through an HTTP POST request from the consumer to the provider. The POST request must happen in the user's browser, which means it needs to be launched by submitting a form. Most of the time the form is submitted via JavaScript to an iframe rendered on a page within the consumer, so the user doesn't have an extra step when trying to launch an app.

Below are a list of parameters that can be sent as part of the POST request. Some are required, some are optional. Most apps shouldn't need more than the first set of parameters and can probably just ignore the rest.

Building an LTI App

If you want to build an LTI-compliant app or provider then there's really only a couple things you need to worry about: how users can configure your app, how to accept a launch from a consumer, and potentially handling some of the extra goodies LTI makes possible.

App Configuration

App configuration is different for every LMS right now, but we're working on that. The best way to provide a standard configuration for your app is by providing a url that returns an xml configuration for your app. There's a lot of examples of app configurations in the Canvas API documentation. Remember, if there's custom values you want to make sure come across with every user, this is the place to include them. The only really crucial piece to specify is the url endpoint that will accept the POST requests, blti:launch_url.

Typically users will either copy the url to your xml configuration, or copy and paste the configuration itself. Notice that the configuration does not include the consumer key or shared secret. These are account-specific values, and if they were included they'd prevent the xml from being reusable. Admins will still have to enter the key and secret values that a provider gives them into the consumer manually.

App Launch

Once an app is configured, it will be added by one or more instructors into their material as some sort of link or button in the consumer. Any time a student, instructor, administrator, or random internet passersby clicks the link they will be directed to the provider via a signed POST request. It is the provider's responsibility to confirm the signature on the POST request. If the signature is invalid then none of the information should be trusted.

If the signature is valid then you should accept the identity assertion provided by the consumer and log the user in to your service. Many services have their own registration flow, so it's not uncommon to require an additional registration step the first time a user launches your app.

Signatures are generated using the OAuth signing process. Google provides a nice tool for generating OAuth signatures that you can use to test your signing code, although you'll probably save yourself some trouble if you can find a library to do the work for you.

Extras

This page has described the most basic type of LTI integration. There's a number of other things you can do on top of this, including passing scores from the provider back to the gradebook of the consumer, or adding buttons to the rich editor in the consumer to insert rich content generated or curated by the provider. Check out the extensions demos page or the Canvas API documentation on external tools for more detail on these extensions and how they work.

POST Parameters

These are all of the known values that can be passed from the consumer to the provider when a user clicks a link to launch the app.

Most Common Parameters

Parameter Status Notes
lti_message_type required set to basic-lti-launch-request
lti_version required set to LTI-1p0
resource_link_id required unique id referencing the link, or "placement", of the app in the consumer. If an app was added twice to the same class, each placement would send a different id, and should be considered a unique "launch". For example, if the provider were a chat room app, then each resource_link_id would be a separate room.
user_id recommended unique id referencing the user accessing the app. providers should consider this id an opaque identifier.
user_image optional if provided, this would be a url to an avatar image for the current user. We recommend that these urls be 50px wide and tall, and don't expire for at least 3 months.
roles recommended

there's a long list of possible roles, but here's the most common ones:

  • Learner
  • Instructor
  • ContentDeveloper
  • urn:lti:instrole:ims/lis/Observer
  • urn:lti:instrole:ims/lis/Administrator
lis_person_name_full recommended Full name of the user accessing the app. This won't be sent if apps are configured to launch users anonymously or with minimal information.
lis_outcome_service_url optional If this url is passed to the provider then it means the app is authorized to send grade values back to the consumer gradebook for any students that access the app. There's more information available in the Canvas API documentation.
selection_directive optional If this parameter is passed to the provider then it means the consumer is expecting the provider to return some piece of information such as a url, an html snippet, etc. There's more information available in the Canvas API documentation.

Additional Parameters

Parameter Status Notes
lis_person_name_given recommended First name of the user accessing the app. This won't be sent if apps are configured to launch users anonymously or with minimal information.
lis_person_name_family recommended Last name of the user accessing the app. This won't be sent if apps are configured to launch users anonymously or with minimal information.
lis_person_contact_email_primary recommended Email address of the user accessing the app. This won't be sent if apps are configured to launch users anonymously or with minimal information.
resource_link_title recommended name of the link that launched the app
resource_link_description optional description of the link that launched the app
context_id recommended unique id of the course from which the user is accessing the app. If a app were added multiple times to the same course, this id would be the same regardless of which link was used to launch the app.
context_type optional this is the type of context from which the user is accessing the app. If it's provided, this will most likely be CourseSection
context_title recommended name of the course from which the user is accessing the app
context_label recommended short name or course code of the course from which the user is accessing the app
launch_presentation_locale recommended locale (i.e. en-US) for the user accessing the app
launch_presentation_document_target recommended if provided, this value will be either (if the app has been launched in a new window) or iframe.
launch_presentation_css_url optional css file that could be included by the provider to help its styling better match the consumer styling. This isn't well-documented, so I typically pretend it doesn't exist.
launch_presentation_width recommended width of the frame or window in which the app is launched. This is only a starting point, since the frame could change if the user resizes their window.
launch_presentation_height recommended height of the frame or window in which the app is launched. This is only a starting point, since the frame could change if the user resizes their window.
launch_presentation_return_url recommended

url to send the user to when they're finished with the provider. The provider can optionally send one of four values as query parameters appended to the url:

  • lti_errormsg - error message to show to the user
  • lti_errorlog - error message for the consumer to optionally store without showing the user
  • lti_msg - success message to show to the user
  • lti_log - success message for the consumer to optionally store without showing the user
tool_consumer_info_product_family_code recommended product name for the consumer. This could be something like moodle, sakai or canvas
tool_consumer_info_version recommended version number of the consumer product.
tool_consumer_instance_guid strongly recommended unique id referencing the instance from which the user is accessing the app. This mostly makes sense only in a multi-tenant environment.
tool_consumer_instance_name recommended name of the instance from which the user is accessing the app.
tool_consumer_instance_description optional description of the instance from which the user is accessing the app.
tool_consumer_instance_url optional url of the instance from which the user is accessing the app.
tool_consumer_instance_contact_email recommended email address of a contact at the instance from which the user is accessing the app.
custom_* optional any number of custom values can optionally be sent across. The key for any custom values should start with custom_ and should be in snake case. Custom values can optionally be defined on the consumer side as part of the app configuration process.

Other Resources