Simple LTI Tool Consumer in HTML and JavaScript
What is LTI?
From Recipe for Making LTI 1 Tool Providers | IMS Global Learning Consortium:
LTI (Learning Tools Interoperability®) provides a standard mechanism for authorizing users accessing a web-based application (Tool Provider) from another web-based application (Tool Consumer, typically an LMS). It can be seen as replacing a login page which a Tool Provider may otherwise have provided and avoids the need to distribute a username and password to each user. Instead a signed launch message is received from the Tool Consumer which can be verified and then trusted. This message should contain sufficient data from which to create user accounts and relevant resources (or resource mappings) “on-the-fly”. Users gain a seamless experience without the need for any pre-provisioning, involvement of any other servers (for example, identity providers), or changing of any firewalls (message is sent through the user’s browser). LTI works best when the Tool Provider delegates full responsibility for authorizing users to the Tool Consumer and does not allow users to directly access their system, thereby bypassing this authorization. This means that there is no need for the two systems to be synchronized with any changes to user privileges, so there is no risk of a user being given access to resources to which they are no longer entitled.
Example Code
For this example, I’ve implemented a simple LTI 1.0 Tool Consumer (TC) within a static HTML page, using JavaScript to generate the non-static form post parameters: Simple LTI Launch Test
This TC includes the bare minimum required fields to construct a valid LTI launch. In this case, the generated launch will post to the saLTIre LTI Tool Provider emulator, which is capable of validating our launch request.
If you open the developer tools on the Simple LTI Launch Test page, you’ll see that both the form and the script have been logged to the console.
Expanding <script>
tag in the console shows the script used to generate <form>
above, as well as the logic that generates the values for the oauth_nonce
, oauth_timestamp
and oauth_signature
fields. For convenience, the script is also included here:
This script uses the oauth-sign npm module to generate a valid HMAC-SHA1 signature from the params
collection, then adds the signature value to a new property in params, called oauth_signature
. Then, the entire collection of params is used to populate the action
attribute and the <input>
nodes in the form with id ltiForm
, as we can see by expanding the <form>
in the console. For convenience, an example is included below:
OAuth 1.0a
Basic LTI uses the OAuth protocol (http://www.oauth.net) to secure its message interactions between the TC and TP. OAuth requires a key and shared secret to sign messages. The key is transmitted with each message, as well as an OAuth-generated signature based on the key. The TP looks up the secret based on the provided key and re-computes the signature and compares the recomputed signature with the transmitted signature to verify the sender’s credentials.
Per section 4.2 of the LTI 1.0 specification Basic LTI Message Signing and the OAuth 1.0a specification, the following OAuth fields are required for a valid OAuth 1.0a request:
oauth_consumer_key
oauth_nonce
oauth_signature_method
oauth_timestamp
oauth_version
oauth_signature
LTI 1.0
The parameters required for a valid LTI request are a superset of those required for a valid OAuth request. In other words, you will need at least the fields listed above, as well as the required LTI fields listed below:
Minimum required fields for LTI launch request
lti_message_type
(always:basic_lti-launch-request
)lti_version
(always:LTI-1p0
)resource_link_id
While these fields are indeed the minimum required fields for a valid LTI launch request, the following additional fields are recommended by the specification, with some of the following fields being required by certain LTI Tool Providers:
resource_link_title
user_id
roles
context_id
context_title
context_label
launch_presentation_document_target
launch_presentation_width
launch_presentation_height
launch_presentation_return_url
tool_consumer_instance_guid
tool_consumer_instance_name
tool_consumer_instance_contact_email
The following additional fields are recommended unless they are suppressed because of privacy settings:
lis_person_name_given
lis_person_name_family
lis_person_name_full
lis_person_contact_email_primary
Looking Forward: LTI Advantage
In a future post (after the LTI 1.3 spec is finalized), I’ll be reviewing the new OAuth 2 + JWT authentication and signature methods required in LTI 1.3 and LTI Advantage.
- LTI Advantage | IMS Global Learning Consortium
- LTI Advantage Overview | IMS Global Learning Consortium
- LTI Advantage FAQ | IMS Global Learning Consortium
- LTI Adoption Roadmap | IMS Global Learning Consortium
Issues with LTI 1.x’ OAuth 1.0a signature method
(tl;dr — SHA1 is insecure, OAuth 1.0a is outdated)
LTI 1.3+ OAuth 2 / JWT
IMS Global Learning Consortium Contributing Members who are leading the evolution of LTI have responded to market concerns about student data privacy and security by adopting the industry standard protocol OAuth2 for authenticating services along with JSON Web Tokens (JWT) for secure message signing.
New certification requirements in 2018
Additional Reading
- Writing LTI Stuff
- Edu App Center — Basics — POST Parameters
- Understanding Request Signing For Oauth 1.0a Providers
- Authorizing Twitter API Calls in Javascript
- Learning Tools Interoperability as a SSO Mechanism | IMS Global Learning Consortium
- Recipe for Making LTI 1 Tool Providers | IMS Global Learning Consortium
- Learning Tools Interoperability: Sample Code | IMS Global Learning Consortium
- Learning Tools | Learning tools interoperability is not just a specification