LTI 1.3 Proctoring Integration, Explained for Developers

LTI 1.3 connects a proctoring tool to your LMS through a signed OpenID Connect launch: the LMS posts a JWT (the id_token) that the tool verifies against the LMS public keyset, and proctoring then runs in the browser enclave for that attempt. It is one of ProctorLink’s three integration surfaces, alongside the Moodle plugin and the browser SDK. You register the tool once and reuse it across any conformant LMS, instead of hand-wiring credentials per system. Everything ProctorLink-specific below comes from the API reference; the LTI claims come from the 1EdTech standard.

Schedule a Demo

What is LTI 1.3?

LTI (Learning Tools Interoperability) is a 1EdTech standard for connecting an external tool to a learning platform. Version 1.3 rebuilt the launch on OpenID Connect and OAuth 2.0. The LMS acts as the platform and the proctoring tool acts as the tool. When a candidate opens an exam activity, the platform sends the tool a signed launch message, a JWT called the id_token, and the tool trusts the launch only after it verifies that signature.

The important change from LTI 1.1 is the trust model. LTI 1.1 relied on a shared secret and OAuth 1.0 request signing, so both sides held the same key. LTI 1.3 uses asymmetric keys: the platform signs with its private key, and the tool verifies with the platform’s public key published at a keyset (JWKS) URL. That is why old 1.1 credentials do not work with a 1.3 tool, and why a 1.3 launch is safer to build proctoring on. This page explains the standard and how ProctorLink fits it. If you are still choosing between routes, start with Proctoring SDK vs API vs LMS plugin, and if your exams live in Moodle specifically, read the Moodle proctoring plugin comparison.

How does the LTI 1.3 launch work?

The launch is a short handshake. A click in the LMS becomes a signed token the tool can verify, and only then does proctoring start. The steps below are the standard flow, ending with the one ProctorLink call you make on your own backend to read the result.

StepWho actsWhat happens
1. OIDC login initiationLMS to toolA candidate opens the exam activity; the LMS calls the tool login initiation URL to start the flow.
2. Authentication requestTool to LMSThe tool redirects back to the LMS authorization endpoint with the OpenID Connect parameters and a nonce.
3. Signed launch (id_token)LMS to toolThe LMS posts a signed JWT (the id_token) carrying the launch claims to the tool redirect URL.
4. Verify the tokenToolThe tool checks the JWT signature against the LMS public keyset and validates iss, aud, nonce, iat and exp.
5. Proctoring runsBrowserThe cross-origin iframe enclave mounts, the camera is requested, and keyframe capture begins for the attempt.
6. Read the reportYour backendGET /v1/sessions/:id returns the server-side integrity score, face analysis, and evidence for review.

The launch message itself is a JWT. Decoded, a resource link launch carries the claims below. These are defined by the LTI 1.3 specification, so they are the same whatever tool you connect. They tell the tool which platform sent the launch (iss), which registered tool it is for (aud), who the user is (sub), and what was launched (the resource link claim).

// Decoded payload of an LTI 1.3 resource link launch id_token.
// The LMS signs this JWT (RS256); the tool verifies it against the LMS keyset.
{
  "iss": "https://lms.your-university.edu",   // the platform (LMS)
  "aud": "CLIENT_ID_ISSUED_AT_REGISTRATION",  // identifies the tool
  "sub": "9f4a2b7c-user-id-in-the-lms",       // the LMS user id
  "nonce": "n-0S6_WzA2Mj",
  "iat": 1786443180,
  "exp": 1786443480,
  "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": "1:site-a",
  "https://purl.imsglobal.org/spec/lti/claim/roles": [
    "http://purl.imsglobal.org/vocab/lis/v2/membership#Learner"
  ],
  "https://purl.imsglobal.org/spec/lti/claim/resource_link": { "id": "math-101-final" }
}

Verification is the whole security story: check the signature against the platform keyset, then confirm iss, aud, nonce, iat and exp. A launch that fails any of those is rejected before proctoring starts.

How does ProctorLink fit the standard?

LTI 1.3 decides how ProctorLink is connected to your LMS. It does not change how proctoring works once it starts. After a verified launch, the same architecture runs as on every other surface. The SDK is a thin loader that mounts a cross-origin iframe enclave served from ProctorLink’s own domain, and the camera lives inside that enclave. The camera permission binds to the enclave origin, so a candidate who has already granted it is not prompted again on another site that embeds ProctorLink. Keyframes upload from the browser straight to object storage through presigned URLs at a configurable interval (one per minute by default), so image bytes never transit the API and no continuous video is recorded.

The verdict is the same too. The integrity score is computed server-side only, so a candidate cannot influence it from the browser. You read it with one server-to-server call, authenticated with your access-token and secret-token, which never reach the browser:

// Your backend. However the session was created (LTI launch, SDK, or
// Moodle plugin), the report has the same shape and you read it the same way.
GET /v1/sessions/6a7b18df70e4f8ecf2597b6f
access-token: <YOUR_ACCESS_TOKEN>
secret-token: <YOUR_SECRET_TOKEN>

// Response (trimmed). Fetch once status is "validated".
{
  "status": "validated",
  "integrity": {
    "score": 100,
    "level": "low",
    "flagged": false,
    "analysis_complete": true,
    "identity_match": "pass",
    "reasons": []
  }
}

Face analysis is deferred, not real-time, so fetch the report once status is validated, or equivalently when integrity.analysis_complete is true. The score starts at 100 and drops as penalties apply: level is low at 80 or above, medium from 50 to 79, and high below 50, with flagged turning true below 80. A score alone should not fail anyone. Use reasons and evidence to drive human review of anything flagged.

If your page sets a Content-Security-Policy, allow the enclave origin so the camera iframe can mount:

frame-src https://enclave.proctorlink.com;

LTI 1.3 vs the Moodle plugin, SDK, and API

LTI 1.3 is one of four ways to reach the same proctoring backend. The route decides how ProctorLink connects and how much you build, not what the tool can observe. Pick by where your exams already run.

RouteHow it connectsWhat you buildBest when
LTI 1.3 launchA signed OpenID Connect handshake from any conformant LMSRegister the tool; the launch is standards-based, not hand-wiredExams already run in an LMS and you want one integration across systems
Moodle pluginA native plugin installed into MoodleInstall and configure inside Moodle adminYour exams run specifically in Moodle and you want a drop-in
Browser SDKA thin loader you add to your own web appMint a session, call createSession().start(), read the reportYou own the exam application and want direct control
REST APIServer-to-server calls you make yourselfPOST /v1/sessions to mint, GET /v1/sessions/:id to readYou are wiring proctoring into a bespoke backend flow

For a Moodle-only estate, weigh the native plugin against a standards-based launch in the Moodle proctoring plugin comparison, and see the shortlist in Best Moodle proctoring plugin. If you own the exam application rather than launching from an LMS, the SDK and API routes are laid out in Proctoring SDK vs API vs LMS plugin.

What LTI 1.3 does not change

A signed launch is a stronger connection, not a stronger camera. An LTI 1.3 launch still lands in Tier 1 browser proctoring: camera, microphone, focus and blur, fullscreen state, clipboard, and device changes. A browser tab cannot see other applications, a second device, a virtual machine, or a remote-desktop session, no matter how it was launched. That is a property of the web platform, not a gap in the integration, and it is why the browser extension and desktop agent tiers exist for process inspection, display enumeration, and lockdown. For the full picture of what a tab can and cannot observe, read What browser-based proctoring can and cannot detect.

Common mistakes in an LTI 1.3 integration

  • Reusing LTI 1.1 credentials. A 1.1 shared secret does not authenticate a 1.3 launch, which is signed with asymmetric keys. Fix: register the tool as LTI 1.3 and exchange keysets, so each side verifies the other’s signature against a published JWKS URL rather than a shared secret.
  • Clock skew and nonce reuse. The id_token carries iat, exp and a nonce, so a server whose clock has drifted rejects valid launches, and accepting a replayed nonce opens a replay hole. Fix: keep servers on NTP, allow a small leeway on the time claims, and reject any nonce you have already seen.
  • Ignoring deployment_id. One LMS can host several deployments of the same tool, and they share iss and client_id. Fix: key your registration lookup on the trio of iss, aud (client id) and deployment_id so launches from different sites are not confused.
  • Blocking the enclave in your CSP. If the page that hosts the launch sets a Content-Security-Policy without the enclave origin, the camera iframe cannot mount and capture silently never starts. Fix: add frame-src https://enclave.proctorlink.com.
  • Treating the launch as biometric consent. A signed launch says who the LMS thinks the user is; it is not permission to capture their face. Fix: obtain explicit pre-capture consent, set a retention period, and honour deletion requests, because facial images are biometric data under India’s DPDP Act, GDPR Article 9, and Illinois BIPA.

Why the design keeps an LTI launch safe

The trust boundaries survive the launch. Your API key is server-side only, and the browser receives only a short-lived, origin-bound session token that lives inside the cross-origin iframe enclave rather than in host-page JavaScript. The integrity score is computed server-side only, which is the core anti-tamper property: a candidate cannot edit their own verdict from the browser console. Sessions resume by attempt id, so a refresh, a closed tab, or a network drop rejoins the same attempt rather than fragmenting one exam into several reports. Across published deployments, ProctorLink has supported more than one million proctored exam sessions (methodology note below). Full cohort sizes and outcomes are on the case studies page.

What customers say on G2

Institutions evaluating proctoring tools often look for independent feedback outside vendor case studies. ProctorLink is listed on G2, where Moodle administrators and training teams share verified product reviews.

Read ProctorLink reviews on G2 →

Frequently Asked Questions

LTI 1.3 is the current version of the 1EdTech Learning Tools Interoperability standard for connecting an external tool to an LMS. The launch is an OpenID Connect flow, and the LMS signs its launch message as a JWT with an asymmetric key (RS256) that your tool verifies against the LMS public keyset. LTI 1.1 used a shared secret and OAuth 1.0 request signing instead, which is why 1.1 credentials do not work with a 1.3 tool. If your LMS offers both, register ProctorLink as an LTI 1.3 tool so identity arrives in a signed token you can verify rather than a shared secret.

Sources & references

Deployment statistics and product behaviour described in this guide link to the sources below.

Next steps

Connecting ProctorLink to your LMS over LTI 1.3? Sign up at app.proctorlink.com to get your credentials, then talk through the launch registration and read a real integrity report before you commit.

More Proctoring Guides

Connect Proctoring to Your LMS

Register ProctorLink once as an LTI 1.3 tool, verify the signed launch, and read the same server-side integrity score you would from the SDK. Pilot it on a real attempt and check the reviewer workload before you commit.