LTI for Humans
A goal of this document is to provide a high level view of the data and components involved in performing an LTI launch. The specification itself is pretty heavy on technical minutia, so this doc gives a human readable overview of how things work.
Prerequisite reading: What is LTI?
As a reference, I don’t recommend reading these first:
LTI 1.3 Spec - http://www.imsglobal.org/spec/lti/v1p3/
LTI 1.1 Spec -https://www.imsglobal.org/spec/lti/security-update/v1p0
Overview
LTI provides us with a UI workflow where a user’s browser can be instructed to make a “launch request” to some third party “tool”. This launch includes a "message" containing information, or “claims”, about the user, where in the LMS the launch is occurring (the course, the unit, etc), and information about where in the tool we need to launch to. Finally, the content of this launch message needs to be trusted since LTI is primarily a UI workflow and there is no secure server to server communication in the core specification.*
In sum, a user can click a link in the LMS to some outside application they have never interacted with and that application would know who they are and what experience to show them without any SSO or account linking processes.
The two widely adopted versions of LTI are 1.1 and 1.3. LTI 1.1 is built on top of OAuth 1.0 and a shared secret for signing messages making it much simpler but also less secure. LTI 1.3 extends the approach for handling launch information but with an entirely new security framework based on OAuth 2.0. This adds some extra steps to the launch workflow. Outside the core specification LTI 1.3 has many optional features that are not entirely covered within this document.
*backend APIs are introduced is part of the Advantage specification
Important Message Claims
There are dozens of claims that may be sent along in an LTI launch message. Many of these are optional or have very specific use cases. To make sense of how the basic launch works we only need to understand a few.
context_id: identifies where the launch is occurring within the LMS. In Open edX this typically would be the course key.
resource_id: a unique identifier for each link within the context. For example a course has multiple links out to the same chemistry lab tool for different labs. Each of these links would be given a different id.
user_role: identifies the type of permissions the user would have. For example are they a student or an instructor? This may impact what experience a tool renders. For example an instructor would be prompted to set up a problem and a student would be prompted to answer it.
user_id: unique identifier for the user. This should not include any identifying information such as an email address, username, etc.
LTI 1.1 Core
The 1.1 flow is relatively straightforward. Both the LMS and the tool hold a shared secret for signing and verifying messages. In order to perform a launch the LMS builds a launch message containing all of the necessary parameters/claims and signs it using the shared key. In order to view to the tool the user's browser makes a POST request containing this message which is validated by the tool using the shared key.
Configuration
LMS administrator or course staff obtain a signing key and shared secret from the tool.
An external application or course unit is configured in the LMS using the obtained key/secret and a “launch endpoint” url.
How these keys are stored and associated with course content is outside the scope of the specification and up to the LMS*
In Open edX for example these values can be entered as fields on an lti-consumer xblock in Studio
Launch
When the user visits a page that needs a link to the tool a launch message is generated by the LMS based on current user and course context and signed by the configured secret key.
note: a ‘link’ here may just be in iframe URL
Users browser makes a POST request to the configured launch endpoint containing the constructed message.
The tool will validate that request against its own key and render the application for that user
Initialization / Setup (optional)
This is more of a common use case than part of the specification itself but I think it gives some helpful context to some of the launch parameters
Some tools may require specific set up steps by the instructor before the tool is functional to a learner.
An instructor launches the tool while setting up the course. This is the first time time the tool has seen this resource id.
That instructor can now set up a problem or a lab within the tool and it will be bound to that resource identifier.
A learner launching that same resource would see the tool as configured by the instructor.
LTI 1.3 Core
LTI 1.3 builds on top of this method of using the browser as an intermediary to pass launch info in LTI 1.1 so make sure to read and understand the above section first. There are a few key differences when performing an LTI 1.3 launch.
exchange of secret keys
Instead of a shared secret, OAuth 2.0 uses an asynchronous public/private keypair. The tool need a public key from the LMS to verify messages originating from the LMS.* These keys can either be exchanged manually as in LTI 1.1 or by providing a public keyset endpoint.
*the LMS requires a public key for the tool to handle LTI advantage features that would make a server-to-server callback. This is not required to do a basic launch.
pre-flight login request
short version: As a security measure we make an additional request upfront that authorizes the users browser with the tool prior to requesting the launch.
long version: LTI 1.3, as part of the OIDC third party login flow, must first make a ‘preflight' login request against the tool to protect against XCSRF attacks. This endpoint will validate the issuer of the login request, in this case the LMS, and construct an "authentication request" that will be returned as a redirect to immediately request a launch. This authentication message includes the URL where the actual launch message should be sent (redirect_uri) along with an XSRF nonce that will be set in a cookie to uniquely bind the user’s browser to this specific launch request. This authentication response is used to construct a launch message in the LMS.
JWT messages
A “message” in LTI 1.1 is basically just a set of parameters along with they signature to validate them. In LTI 1.3 that message is now encoded as a JSON Web Token or JWT. JWT is an industry-standard format for encoding a set of signed parameters or ‘claims’ into a URL safe value. See an example LTI launch JWT. Read more about JWTs
LTI 1.3 Advantage Services
LTI Advantage services are additional APIs the LMS may implement allowing a tool to make server side calls directly without a user’s browser acting as an intermediary. A quick example of such a service is posting back grades. An LTI Advantage launch would include additional claims identifying an Assignment and Grades Service (AGS) API along with an identifier for that grade entry, or “line item”, related to this launch. The tool can then interact with this grade based on a standardized interface.
In order to authenticate these service calls, the third-party tool must first obtain an OAuth2 access token. As with the launch request the request for an access token is signed with the third-party tool’s private key and validated by the LMS. This token is used to authenticate API requests and its content indicates to the tool which permissions or “scopes” it will have access to. Ultimately, this isn’t all that different other API integrations with edx-platform LMS.
Now that these service level APIs have their own authentication mechanism, these advantage features don’t technically have to be tied to an individual launch. Depending on configuration, and the permissions granted by the LMS the tool could use its access token to fetch or modify any resource and not just a single item tied to a launch. In our grades example above, maybe the user is able to navigate to and complete other sections within the tool. The tool can use the AGS(Assignment and Grades Service) to find the identifiers for the other sections and post back grades, without further user interactions.
Advantage Features
Deep Linking: When an instructor launches a tool they can choose certain configuration options. The tool is then able to push that launch configuration back into the platform.
Assignment and Grades Service: A standard API for interacting with course grades
Names and Roles Provisioning Service: A standard API for interacting with the course roster.
Helpful Resources
LTI 1.3 and LTI 1.3 Advantage YouTube Series: LTI 1.3 and LTI Advantage Bootcamp
IMS LTI Advantage Webinar: IMS Developer Webinars: LTI Advantage