Skip to main content

What Is LTI® 1.3?

LTI® 1.3 is the current version of Learning Tools Interoperability, the standard that lets a learning management system hand a user over to an external learning tool and lets that tool read and write data back. It is published by 1EdTech Consortium, Inc., and the normative text is the LTI® 1.3 core specification — dense, authoritative, and the thing to check when a vendor's documentation and reality disagree.

The launch is built on two existing standards rather than inventing its own cryptography: OpenID Connect for the handshake, and JSON Web Tokens for the signed payload.

The problem it solves is combinatorial. A tool used by a hundred institutions running six different platforms would otherwise need bespoke integration work for each one. With LTI®, the tool implements the standard once and any conformant platform can launch it.

This page covers what the standard actually does during a launch. If you want the vocabulary first, the terminology map is a better starting point, because 1.3 renamed several things that older documentation still uses the old names for.

What a launch has to establish

When someone clicks a link to a tool inside their LMS, the tool receives a request from a browser it has never seen before. Before showing anything, it needs to establish four things, and none of them can be taken on trust from the browser:

  1. Which platform this is. Anyone can send an HTTP request claiming to be a university's LMS.
  2. Who the user is, and what role they hold in this course.
  3. What they are opening — which course, and which placement of the tool within it.
  4. What it is allowed to do afterwards: read the roster, write grades, neither.

LTI® 1.3 answers all four with a signed token. The signature is what makes the claims trustworthy, and obtaining it is what the handshake is for.

The launch sequence

A launch is five steps. The user sees one page change.

1. The platform starts a login

The platform does not send the payload first. It sends a small request to the tool's login initiation URL saying only that a launch is starting:

POST https://tool.example.com/lti/login
Content-Type: application/x-www-form-urlencoded

iss=https://lms.example.edu
&login_hint=1a2b3c
&target_link_uri=https://tool.example.com/launch
&lti_message_hint=9f8e7d
&client_id=1000000000042
&lti_deployment_id=42:abcdef

iss identifies the platform and client_id identifies this tool's registration with it. Together they are how the tool works out which of its registrations is being used. login_hint and lti_message_hint are opaque values the platform will want back.

This step comes from OpenID Connect, where it is called third-party initiated login. It exists so the tool can create state before any data arrives.

2. The tool asks for the token

The tool replies by redirecting the browser to the platform's authentication endpoint, echoing the hints back and adding two values of its own:

GET https://lms.example.edu/api/lti/authorize_redirect
?scope=openid
&response_type=id_token
&response_mode=form_post
&prompt=none
&client_id=1000000000042
&redirect_uri=https://tool.example.com/launch
&login_hint=1a2b3c
&lti_message_hint=9f8e7d
&state=<tool generated>
&nonce=<tool generated>

state is how the tool recognises the response as belonging to the request it made. nonce is single-use, and rejecting a repeat is what stops a captured launch being replayed later.

redirect_uri must exactly match one the platform has registered. A trailing slash present in one place and absent in the other is enough to fail here, and it is one of the most common setup problems.

3. The platform posts the ID Token

The platform posts back to the tool's redirect URI:

POST https://tool.example.com/launch
Content-Type: application/x-www-form-urlencoded

id_token=eyJhbGciOiJSUzI1NiIsImtpZCI6IjIwMjYtMDgifQ...
&state=<the value from step 2>

The id_token is a JWT. Decoded, its payload carries the claims the tool needs:

{
"iss": "https://lms.example.edu",
"aud": "1000000000042",
"sub": "9a8b7c6d-user-identifier",
"nonce": "<the value from step 2>",
"exp": 1786531200,
"https://purl.imsglobal.org/spec/lti/claim/message_type": "LtiResourceLinkRequest",
"https://purl.imsglobal.org/spec/lti/claim/version": "1.3.0",
"https://purl.imsglobal.org/spec/lti/claim/deployment_id": "42:abcdef",
"https://purl.imsglobal.org/spec/lti/claim/target_link_uri": "https://tool.example.com/launch",
"https://purl.imsglobal.org/spec/lti/claim/roles": [
"http://purl.imsglobal.org/vocab/lis/v2/membership#Learner"
],
"https://purl.imsglobal.org/spec/lti/claim/context": {
"id": "course-2026-cs101",
"label": "CS101",
"title": "Computer Science 101"
},
"https://purl.imsglobal.org/spec/lti/claim/resource_link": {
"id": "placement-88",
"title": "Week 3 exercise"
}
}

The long claim names are not decoration. They are namespaced URIs so that LTI® claims cannot collide with anything else in a JWT.

4. The tool verifies it

This is the step that makes the rest trustworthy, and it is where an implementation is most likely to be quietly wrong. The tool must check:

  • The signature, against the platform's key set. The token's header names a kid; the key with that identifier is fetched from the platform's published JWKS URL.
  • iss and aud match the registration it thinks this is.
  • exp has not passed.
  • nonce has not been seen before.
  • state matches the value it sent in step 2.
  • The message type and version claims are the ones it supports.

Skipping the nonce check leaves the launch replayable. Skipping the aud check means a token minted for a different tool will be accepted.

5. The tool renders

Only now does the tool know who it is dealing with. It maps the platform identifier plus sub onto a user in its own database, creates a session, and renders the right view for the role and the resource link.

A tool should key its users on the platform and the subject together. sub is unique within a platform, not globally, so two platforms can legitimately issue the same one.

What happens after the launch

The launch establishes identity. Three optional services do the rest, and together with the core they make up LTI® Advantage:

ServiceWhat it doesDirection
Names and Role ProvisioningRead the roster of the course and each member's roleTool reads from platform
Assignment and Grade ServicesCreate gradebook columns and post scoresTool writes to platform
Deep LinkingLet a teacher browse the tool and choose content to embedTool returns a selection

These calls are server to server and authenticated with OAuth 2.0 client credentials rather than the launch token: the tool signs a JWT assertion with its own key, exchanges it for an access token at the platform's token endpoint, and calls the service with that.

Availability is granted per course. A tool can have grade access in one course and not another, so it should check what the ID Token says is available for this launch rather than assuming.

What this costs to implement

Every step above is work: an OIDC login endpoint, JWKS fetching with caching and key rotation, JWT verification, nonce storage, state handling, an OAuth 2.0 client credentials flow, and a token cache. Then the same again per service, and then the differences between how each platform interprets the specification.

That is the case for not implementing it yourself. LTIAAS performs the handshake and hands your application the verified result:

// After LTIAAS has completed the launch it redirects to your URL with an ltik.
const headers = { Authorization: `LTIK-AUTH-V2 ${API_KEY}:${ltik}` }
const idtoken = await requests.get('https://your.ltiaas.com/api/idtoken', { headers })

const userId = idtoken.user.id
const courseId = idtoken.launch.context.id
const roles = idtoken.user.roles

There is no JWT in that code, and no key handling, because the verification has already happened.

Common questions

Is LTI® 1.3 the same as LTI® Advantage?

Not quite. LTI® 1.3 is the core specification that defines the launch. LTI® Advantage is that core plus three services — Names and Role Provisioning, Assignment and Grade Services, and Deep Linking. A platform can support the core without offering all three.

Does LTI® 1.3 use OAuth?

It uses OAuth 2.0 client credentials for service calls, and OpenID Connect for the launch itself. It does not use the OAuth 1.0a request signing that LTI® 1.1 relied on, which is the part most older documentation describes.

Do I need a certificate to use LTI® 1.3?

No. Each side publishes a JSON Web Key Set at a URL and signs with the corresponding private key. There is no certificate authority involved and no certificate to buy.

Can one integration work with every LMS?

The protocol is the same everywhere, so the code you write is the same. What differs is registration — where the values are entered in each LMS admin console, and which services that platform grants.

Next

All trademarks, logos, and service marks displayed on this website are the property of their respective owners. LTIAAS is a trademark of GatherAct, LLC, doing business as LTIAAS. Learning Tools Interoperability (LTI)® and LTI® are trademarks of 1EdTech Consortium, Inc. LTIAAS is not affiliated with, endorsed or sponsored by 1EdTech Consortium, Inc. or by any other owners of third-party trademarks used on this website. LTIAAS is not responsible for the content, quality, or accuracy of any websites linked to or from this website that are not owned by LTIAAS. If you have any questions or concerns about the use of any trademarks or content on this website, please contact us.