We run the protocol. You run your product.
LTI 1.3 is five network hops, three signature checks, and a set of replay defenses that only fail in production. LearnPort implements all of it and hands you a JSON object.
The handshake
What happens between the LMS and your callback
This is the flow we own. The only part you implement is step 5.
- LMS → LearnPort
OIDC login
The LMS sends issuer, client ID, and login hint. We verify the registration and resolve the destination from your allowlist, pinning it into the state.
- LearnPort → LMS
Authorization redirect
We redirect back to the platform authorization URL with state and nonce. State is stored once and consumed atomically, so it cannot be replayed.
- LMS → LearnPort
id_token verification
We fetch the platform JWKS, verify the signature, and check nonce, deployment, and required claims. The pinned destination is re-authorized against your current allowlist rather than trusted because it was valid earlier.
- LearnPort → your app
One-time launch token
Your callback receives a short-lived token. It is stored hashed and redeemable exactly once.
- Your app → LearnPort
Redeem
One authenticated POST exchanges the token for a normalized user, course context, and role set.
Your side
One endpoint is the whole integration
Redeem the token, get a normalized session, start yours. If you can write an OAuth callback, you can write this.
// app/lti/callback/route.ts
import { LearnPort } from "@learnport/sdk";
const learnport = new LearnPort({ apiKey: process.env.LEARNPORT_API_KEY! });
export async function GET(request: Request) {
const token = new URL(request.url).searchParams.get("launch_token");
if (!token) return new Response("Missing launch token", { status: 400 });
const launch = await learnport.lti.launches.redeem(token);
// launch.user, launch.context, launch.user.roles — your session starts here.
return createSessionAndRedirect(launch);
}In the dashboard
The surfaces around the launch
Most of the time an LTI integration costs is not the launch itself. It is registration, admin coordination, and debugging failures you cannot reproduce.
Connect wizards
Canvas-specific and generic LTI 1.3 flows that collect what the platform needs and hand back the login, launch, and JWKS URLs the admin has to paste in.
Install packs
A Markdown document generated from your real environment configuration, written for an LMS administrator rather than for you.
Launch simulator
A fake platform provisioned per environment. Launch as a student or an instructor and get the same handoff token a real LMS produces.
Launch debugger
Every attempt, successful or not, with a stable error code plus the expected and received values. Sensitive diagnostics never leave the dashboard.
Environments
Development and production environments per application, each with isolated API keys and platform registrations.
Typed SDK
@learnport/sdk covers the JSON API with types, and the sample customer app shows the whole integration end to end.
Try it against the simulator first.
You can run a complete LTI 1.3 launch without contacting a single university.