LTI Partner Provisioning
How to register Humans But Guided as an LTI 1.3 tool on a partner's Canvas instance. Covers both the automated API path (preferred) and the manual UI path.
What we give partners
Before they start, share these values with the partner Canvas admin:
| Our endpoint | Value |
|---|---|
| OIDC Initiation URL | https://api.humansbutguided.com/api/lti/oidc-login |
| Redirect URI (Launch URL) | https://api.humansbutguided.com/api/lti/launch |
| JWK Set URL | https://api.humansbutguided.com/api/lti/jwks |
| Target Link URI | https://api.humansbutguided.com/api/lti/launch |
What they give us
After they create the key, we need:
| Field | Where they find it |
|---|---|
| Canvas base URL | e.g. https://canvas.partner.edu |
client_id | Shown on the Developer Key row after creation |
deployment_id | From the installed tool — see finding deployment_id |
Option A — Automated via Canvas REST API (preferred)
Partners can create the developer key without touching the UI. A Canvas admin with an API token runs:
CANVAS_URL="https://canvas.partner.edu"
CANVAS_TOKEN="<their_admin_api_token>"
ACCOUNT_ID="1" # usually 1 for the root account
curl -s -X POST "$CANVAS_URL/api/v1/accounts/$ACCOUNT_ID/developer_keys" \
-H "Authorization: Bearer $CANVAS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"developer_key": {
"name": "Grading Students",
"email": "lti@humansbutguided.com",
"redirect_uris": "https://api.humansbutguided.com/api/lti/launch",
"tool_configuration": {
"settings": {
"title": "Grading Students",
"description": "AI-assisted homework grading",
"target_link_uri": "https://api.humansbutguided.com/api/lti/launch",
"oidc_initiation_url": "https://api.humansbutguided.com/api/lti/oidc-login",
"public_jwk_url": "https://api.humansbutguided.com/api/lti/jwks",
"scopes": [
"https://purl.imsglobal.org/spec/lti-ags/scope/lineitem",
"https://purl.imsglobal.org/spec/lti-ags/scope/score",
"https://purl.imsglobal.org/spec/lti-ags/scope/result.readonly"
],
"extensions": [{
"platform": "canvas.instructure.com",
"settings": {
"placements": [{
"placement": "assignment_selection",
"message_type": "LtiResourceLinkRequest",
"target_link_uri": "https://api.humansbutguided.com/api/lti/launch",
"text": "Grading Students"
}, {
"placement": "homework_submission",
"message_type": "LtiResourceLinkRequest",
"target_link_uri": "https://api.humansbutguided.com/api/lti/launch",
"text": "Grading Students"
}]
}
}]
}
}
}
}'The response JSON contains "id" — that is the internal developer key ID. The global client_id (used in LTI launches) is different; read it from Canvas after creation.
Then enable the key on the account:
KEY_ID="<id from above>"
curl -s -X PUT "$CANVAS_URL/api/v1/accounts/$ACCOUNT_ID/developer_keys/${KEY_ID}/developer_key_account_bindings" \
-H "Authorization: Bearer $CANVAS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"developer_key_account_binding": {"workflow_state": "on"}}'Set OIDC initiation URL on the Developer Key
Canvas uses DeveloperKey.oidc_initiation_url when building assignment launch forms. Tool configuration JSON alone is not enough — if this column is empty, launches fail with Missing state param on HBG.
key = DeveloperKey.find(<KEY_ID>)
key.update!(oidc_initiation_url: "https://api.humansbutguided.com/api/lti/oidc-login")
puts key.global_id # this is the client_id for LTIInstall the app by Client ID
Creating a developer key does not install the tool in courses. Install at account and course level:
CLIENT_ID="<global_id from above>"
COURSE_ID="<course_id>"
curl -sS -X POST "$CANVAS_URL/api/v1/accounts/$ACCOUNT_ID/external_tools" \
-H "Authorization: Bearer $CANVAS_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"client_id\":\"$CLIENT_ID\"}"
curl -sS -X POST "$CANVAS_URL/api/v1/courses/$COURSE_ID/external_tools" \
-H "Authorization: Bearer $CANVAS_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"client_id\":\"$CLIENT_ID\"}"Without this step, assignments show "Couldn't find valid settings for this link".
public_jwk_url(a URL Canvas fetches at launch time) is preferred over pasting the raw JWK, so key rotation doesn't require re-provisioning.
Finding deployment_id
After installing the app, read the deployment ID Canvas will send in launch tokens:
ContextExternalTool.find_by(name: "Grading Students").deployment_idRegister it on HBG:
cd backend
python scripts/seed_lti_platform.py \
--canvas-url "$CANVAS_URL" \
--client-id "$CLIENT_ID" \
--deployment-id "<deployment_id from above>"Option B — Manual Canvas UI
For partners who prefer the UI:
See Canvas admin setup for a screenshot walkthrough.
Summary:
- Admin → Developer Keys → + Developer Key → + LTI Key
- Fill Key Settings (left panel):
| Field | Value |
|---|---|
| Key Name | Grading Students |
| Owner Email | lti@humansbutguided.com |
| Redirect URIs | https://api.humansbutguided.com/api/lti/launch |
- Fill Configure (right panel), Method = Manual Entry:
| Field | Value |
|---|---|
| Title | Grading Students |
| Description | AI-assisted homework grading |
| Target Link URI | https://api.humansbutguided.com/api/lti/launch |
| OpenID Connect Initiation URL | https://api.humansbutguided.com/api/lti/oidc-login |
| JWK Method | Public JWK URL → https://api.humansbutguided.com/api/lti/jwks |
- LTI Advantage Services — enable all four gradebook scopes.
- Placements — remove defaults; add Assignment Selection and Homework Submission with message type
LtiResourceLinkRequest. - Save → toggle key ON → install by Client ID → share
client_idanddeployment_idwith HBG.
Verification checklist
After provisioning, confirm:
# 1. HBG tool JWKS (RSA, alg=RS256)
curl -s https://api.humansbutguided.com/api/lti/jwks | jq '.keys[0] | {kty,alg,use,kid}'
# 2. OIDC login redirects to Canvas (302)
curl -sS -D - -o /dev/null -X POST "https://api.humansbutguided.com/api/lti/oidc-login" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "iss=${CANVAS_URL}&login_hint=1&target_link_uri=https://api.humansbutguided.com/api/lti/launch&client_id=${CLIENT_ID}"Then open an External Tool assignment as a student. The HBG workspace should match Outcome after integration.
If anything fails, see LTI troubleshooting.
For the self-hosted demo stack (canvas-demo.humansbutguided.com), also complete LTI signing keys in the grading-students repo.