Found this content helpful? Log in or sign up to leave a like!
LTI 1.3 Lti Deep Linking Response returns 200 but no link appears
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi all — I’m implementing LTI 1.3 Deep Linking. When I POST the Deep Linking Response to the deep_link_return_url, Canvas returns 200 OK, but:
-
the selection window stays open, and
- no assignment/resource appears in the course.
Environment
-
Canvas cloud
-
Tool issuer:
<TOOL_ISSUER> (e.g.,
https://tool.example.com)
-
Client ID:
<CLIENT_ID>
-
Deployment ID:
<DEPLOYMENT_ID>
-
JWKS URL:
<JWKS_URL>
Request I’m sending
URL (exact): https://<canvas-domain>/courses/<COURSE_ID>/deep_linking_response?data=<OPAQUE_DATA_FROM_LAUNCH>
Method: POST (application/x-www-form-urlencoded)
Form fields:id_token=<JWT> (no state present in this DL flow)
Deep Linking Response (JWT){
"iss": "<TOOL_ISSUER>", "aud": "<CLIENT_ID>", "azp": "<CLIENT_ID>", "sub": "<TOOL_USER_ID>", "iat": <unix>, "exp": <unix>, "https://purl.imsglobal.org/spec/lti/claim/message_type": "LtiDeepLinkingResponse", "https://purl.imsglobal.org/spec/lti/claim/version": "1.3.0", "https://purl.imsglobal.org/spec/lti/claim/deployment_id": "<DEPLOYMENT_ID>", "https://purl.imsglobal.org/spec/lti-dl/claim/data": "<OPAQUE_DATA_FROM_URL>", "https://purl.imsglobal.org/spec/lti-dl/claim/content_items": [ { "type": "ltiResourceLink", "title":...
Expected
Canvas closes the chooser and adds the LTI link (assignment/resource) to the course.
Actual
POST returns 200, but no UI change and chooser stays open.
Questions
-
Are there additional required fields for ltiResourceLink in Canvas for the assignment_selection placement?
-
Must content_items[0].url exactly equal the registered target_link_uri in the Developer Key?
-
Any course/role/placement settings that could accept the response (200) but not place content?
-
Known cases where Canvas returns 200 but silently discards the DL response (schema, roles, or deployment mismatch)?
Checks done-
RS256 signature verifies;
kid matches JWKS at <JWKS_URL>
-
iss = tool issuer; aud = <CLIENT_ID>
-
deployment_id matches the request
-
data round-tripped exactly
-
Single
content_item (Canvas sent accept_multiple: false)
-
Posting via form-encoded (not JSON)
Thanks for any pointers
-