LTI Advantage Concepts

Copy Markdown View Source

LTI 1.3 defines how learning platforms connect with external tools. Understanding these concepts will help you configure Ltix, implement your storage adapter, and debug launch issues. If you're already familiar with LTI 1.3, skip ahead to How Ltix fits in.

What is LTI?

Learning Tools Interoperability (LTI) connects learning platforms (like Canvas, Moodle, or Blackboard) with external tools (like a quiz engine, coding sandbox, or video player). When a student clicks a link in their course, the platform launches the tool with information about who the user is, what course they're in, and what role they have.

LTI 1.3 uses OpenID Connect (OIDC) for the launch flow and signed JWTs for the data payload.

Launch flow

An LTI launch is a three-step browser redirect:

sequenceDiagram
    participant P as Platform
    participant B as Browser
    participant T as Tool

    P->>B: User clicks LTI link
    B->>T: 1. POST /lti/login (iss, login_hint, target_link_uri)
    T->>B: 2. Redirect to platform auth endpoint (nonce, state)
    B->>P: Follow redirect
    P->>P: Authenticate user, build signed JWT
    P->>B: 3. POST /lti/launch (id_token, state)
    B->>T: Forward POST
    T->>T: Validate JWT, extract claims
    T->>B: Render launch
  1. Login initiation — the platform tells the tool "a user wants to launch." The tool doesn't know who yet — it just gets the platform's identity and a hint. Ltix handles this in handle_login/3.

  2. Authorization redirect — the tool sends the browser to the platform's auth endpoint with a nonce and state parameter. The platform authenticates the user and builds a signed JWT.

  3. Launch — the platform POSTs the signed JWT back to the tool. The tool validates the signature, checks the nonce, and extracts the launch data. Ltix handles this in handle_callback/3.

The state parameter (stored in the session between steps 1 and 3) provides CSRF protection — it proves the launch callback came from the same browser session that initiated the login.

Registrations

A registration is what your tool knows about a platform. It's created out-of-band when a platform administrator sets up your tool, typically through a configuration UI on both sides.

A registration contains:

FieldWhat it is
issuerThe platform's identity URL (e.g. https://canvas.instructure.com)
client_idYour tool's OAuth2 client ID on that platform
auth_endpointWhere to redirect users for authentication
jwks_uriWhere to fetch the platform's public keys
token_endpointWhere to request access tokens for service calls (optional)
tool_jwkYour tool's private signing key for this registration (JOSE.JWK.t())

In Ltix, this is Ltix.Registration. Your Ltix.StorageAdapter looks up registrations by issuer during login initiation.

Deployments

A deployment is a specific installation of your tool on a platform. One registration (platform + client_id) can have many deployments — for example, a tool installed in three different departments of the same university.

A deployment carries a single deployment_id assigned by the platform. It's immutable, case-sensitive, and guaranteed unique within the registration.

In Ltix, this is Ltix.Deployment. Your storage adapter looks up deployments during launch validation, after the JWT's deployment_id is extracted.

Launch claims

The signed JWT in step 3 contains claims — structured data about the launch. Ltix parses these into Ltix.LaunchClaims:

Claim groupExamplesStruct field
User identitysubject, name, emailclaims.subject, claims.name
Rolesinstructor, learner, TAclaims.roles (list of %Role{})
Contextcourse ID, title, labelclaims.context
Resource linklink ID, titleclaims.resource_link
Launch metadatamessage type, version, target URIclaims.message_type, claims.target_link_uri
Service endpointsgradebook, names & rolesclaims.ags_endpoint, claims.memberships_endpoint
Customanything the platform addsclaims.custom, claims.extensions

The full launch result is Ltix.LaunchContext, which wraps the claims together with the matched registration and deployment.

Roles

Platforms send roles as URI strings. A user can have multiple roles simultaneously — for example, an instructor in the course and a staff member at the institution.

Roles have three scopes:

  • Context — course-level: instructor, learner, TA, content developer
  • Institution — org-level: faculty, student, staff, administrator
  • System — platform-level: system admin, account admin

Ltix parses role URIs into Ltix.LaunchClaims.Role structs and provides predicates like Role.instructor?/1 for authorization. See Working with Roles for details.

Nonces

A nonce is a one-time-use random string that prevents replay attacks. The flow:

  1. During login, Ltix generates a nonce and your storage adapter persists it
  2. The nonce is included in the authorization request to the platform
  3. The platform echoes it back in the signed JWT
  4. During launch validation, Ltix asks your adapter to verify the nonce exists and consume it atomically

If someone intercepts a JWT and tries to replay it, the nonce check fails because it was already consumed.

How Ltix fits in

Ltix handles the protocol — OIDC redirects, JWT parsing, signature verification, claim validation. Your application handles the rest:

Ltix's jobYour app's job
Build the authorization redirectStore the OIDC state in the session
Validate the JWT signature and claimsLook up registrations and deployments
Parse roles, context, resource linksManage nonces (store and consume)
Return structured launch dataDecide what to do with the launch