LTI Launch Endpoints
These endpoints are called by the LMS during an LTI 1.3 launch. They are public endpoints and do not require an API key. The LMS redirects the student's browser to these URLs as part of the OIDC third-party login flow.
For a full walkthrough of the launch process, see the LTI Integration Guide.
GET /v1/platform/lti/login
OIDC login initiation endpoint. The LMS redirects the student's browser here to start
the LTI launch. TutorFlow validates the parameters, generates a state and nonce,
and redirects the browser back to the LMS authorization endpoint.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
iss | string | Yes | Issuer identifier of the LMS (must match a registered issuer) |
login_hint | string | Yes | Opaque value from the LMS identifying the user |
target_link_uri | string | Yes | The URL the LMS wants to launch (TutorFlow's launch URL) |
lti_message_hint | string | No | Opaque value from the LMS passed through to the authorization request |
client_id | string | No | The client ID of the tool registration. Required when the same issuer has multiple registrations. |
Example
The LMS constructs a URL like this and redirects the student's browser to it:
https://api.tutorflow.io/v1/platform/lti/login
?iss=https://canvas.instructure.com
&login_hint=user-id-12345
&target_link_uri=https://api.tutorflow.io/v1/platform/lti/launch
<i_message_hint=assignment-context-hint
&client_id=10000000000001Response
This endpoint does not return a JSON body. It responds with an HTTP 302 redirect to the
LMS authorization endpoint. The redirect URL includes the following query parameters:
| Parameter | Description |
|---|---|
scope | Always openid |
response_type | Always id_token |
response_mode | Always form_post |
client_id | The registered client ID |
redirect_uri | TutorFlow's launch URL |
state | CSRF protection token (stored server-side) |
nonce | Replay protection token |
login_hint | Passed through from the original request |
lti_message_hint | Passed through from the original request (if provided) |
prompt | Always none (SSO, no re-authentication) |
Error Responses
| Status | Cause |
|---|---|
400 | Missing required parameters (iss, login_hint, or target_link_uri) |
400 | No LTI registration found for the given iss and client_id |
POST /v1/platform/lti/launch
Launch callback endpoint. After the LMS authenticates the user, it POSTs a form to this
URL containing the signed id_token (JWT) and the state value. TutorFlow validates
the JWT signature, checks the state and nonce, extracts LTI claims, and creates
a launch session.
Request Body (form-encoded)
| Field | Type | Required | Description |
|---|---|---|---|
id_token | string | Yes | The signed JWT from the LMS containing LTI launch claims |
state | string | Yes | The CSRF state token generated during the login step |
Content Type
Content-Type: application/x-www-form-urlencodedExample
The LMS auto-submits a form to this endpoint:
<form method="POST" action="https://api.tutorflow.io/v1/platform/lti/launch">
<input type="hidden" name="id_token" value="eyJhbGciOiJSUzI1NiIs..." />
<input type="hidden" name="state" value="csrf-state-token" />
</form>JWT Claims
The id_token JWT contains standard LTI 1.3 claims:
| Claim | Description |
|---|---|
iss | LMS issuer |
sub | User identifier in the LMS |
aud | Client ID (must match the registration) |
nonce | Must match the nonce from the login step |
https://purl.imsglobal.org/spec/lti/claim/message_type | LtiResourceLinkRequest or LtiDeepLinkingRequest |
https://purl.imsglobal.org/spec/lti/claim/version | Always 1.3.0 |
https://purl.imsglobal.org/spec/lti/claim/roles | Array of LTI role URIs |
https://purl.imsglobal.org/spec/lti/claim/resource_link | Resource link details (id, title) |
https://purl.imsglobal.org/spec/lti-ags/claim/endpoint | AGS endpoint for grade passback (if available) |
Response
On success, TutorFlow creates an LTI launch session and redirects the student's browser
to the tool UI. The response is an HTTP 302 redirect (or an HTML page rendered inside the
LMS iframe).
Validation Steps
TutorFlow performs the following validation on every launch:
- State check: The
stateparameter must match a valid, unexpired login session. - JWT signature: The
id_tokenis verified against the LMS JWKS (fetched from the registeredjwksEndpoint). - Issuer check: The
issclaim must match theissuerin the registration. - Audience check: The
audclaim must include the registeredclientId. - Nonce check: The
noncemust match the value generated during the login step. - Expiry check: The token must not be expired (
expclaim). - Message type: Must be a supported LTI message type.
Error Responses
| Status | Cause |
|---|---|
400 | Missing id_token or state |
400 | Invalid or expired state token |
401 | JWT signature verification failed |
401 | Issuer, audience, or nonce mismatch |
401 | Token expired |
POST /v1/platform/lti/deep-linking/response
Processes the deep linking content items returned from the tool selection UI. When the
LMS sends a LtiDeepLinkingRequest message type instead of a LtiResourceLinkRequest,
TutorFlow presents a content selection UI. After the user selects content, this endpoint
receives the selections and returns a signed JWT that the LMS uses to create resource links.
Authentication
None. This endpoint is called from the tool selection UI using an active deep linking session.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
sessionId | string | Yes | The deep linking session ID from the launch |
contentItems | array | Yes | Array of content item objects selected by the user |
Example Request
curl -X POST https://api.tutorflow.io/v1/platform/lti/deep-linking/response \
-H "Content-Type: application/json" \
-d '{
"sessionId": "dl-session-uuid",
"contentItems": [
{
"type": "ltiResourceLink",
"title": "Math Evaluation",
"url": "https://api.tutorflow.io/v1/platform/lti/launch"
}
]
}'Response
{
"success": true,
"jwt": "eyJhbGciOiJSUzI1NiIs..."
}| Field | Type | Description |
|---|---|---|
success | boolean | Whether the deep linking response was created |
jwt | string | Signed JWT containing the content items for the LMS to process |
GET /v1/platform/lti/.well-known/jwks.json
Returns TutorFlow's public JSON Web Key Set (JWKS). The LMS uses this endpoint to retrieve the public keys needed to verify JWTs signed by TutorFlow (used during deep linking responses and other tool-initiated messages).
Authentication
None. This is a public endpoint.
Example Request
curl https://api.tutorflow.io/v1/platform/lti/.well-known/jwks.jsonResponse
{
"keys": [
{
"kty": "RSA",
"kid": "tutorflow-lti-key-1",
"use": "sig",
"alg": "RS256",
"n": "0vx7agoebGcQSuu...",
"e": "AQAB"
}
]
}Response Fields
| Field | Type | Description |
|---|---|---|
keys | array | Array of JWK objects |
keys[].kty | string | Key type (always RSA) |
keys[].kid | string | Key ID used to match the kid header in JWTs |
keys[].use | string | Key usage (always sig for signature verification) |
keys[].alg | string | Algorithm (always RS256) |
keys[].n | string | RSA modulus (Base64url-encoded) |
keys[].e | string | RSA exponent (Base64url-encoded) |
Caching
This endpoint supports HTTP caching. The response includes Cache-Control headers.
Keys may be rotated periodically. LMS platforms should re-fetch the JWKS if JWT
verification fails with a kid mismatch.