flowchart LR
LMS[LMS\nMoodle/Canvas/SF] -->|POST id_token| LTI[QueryBench /lti/launch]
LTI -->|JWT verify + nonce| Provider[(lms_provider)]
LTI -->|map course/resource| Mapping[(lms_assessment_mapping)]
LTI -->|create/fetch user| User[(auth_user)]
LTI -->|create assignment + attempt| Session[(attempts source=lms)]
LTI -->|session cookie + redirect| UI[QueryBench Web UI]
UI --> API[/api/v1/attempts/.../finalize/]
API -->|if source=lms| AGS[LTI AGS submit score]
AGS --> LMS
Validates and processes LTI 1.3 launch token:
- validates JWT signature via LMS JWKS
- verifies
iss,aud,deployment_id - validates nonce replay protection
- validates timestamp freshness
- extracts:
sub(mapped asuser_id)emailnamecontext.idascourse_idresource_link.idasresource_link_id- roles claim
- maps
(provider, course_id, resource_link_id)to QueryBench assessment - creates/loads QueryBench user and session (
attempt.source = lms) - logs in user server-side and redirects to assessment UI
Returns tool public JWK set for LMS registration.
Request body:
{
"session_id": 1,
"score": 82,
"max_score": 100
}Behavior:
- finds LMS-linked attempt/session
- obtains AGS access token from LMS token endpoint
- sends score to lineitem
/scores - returns:
{
"scoreGiven": 82,
"scoreMaximum": 100,
"timestamp": "2026-03-11T10:00:00Z"
}idnameissuerclient_idauth_urltoken_urlkeyset_urldeployment_id
idprovider_idlms_course_idlms_assignment_idquerybench_assessment_id
source(standalone|lms)lms_provider_idlms_assignment_idlti_context_idlti_user_idlti_resource_link_idlti_ags_endpointlti_lineitemlti_ags_scope
Use docker-compose-lti-test.yml:
docker compose -f docker-compose-lti-test.yml up -dAlternative quick container:
docker run -p 8080:80 moodlehq/moodle-php-apacheTest steps:
- Create course in Moodle.
- Add external tool activity.
- Register QueryBench as LTI 1.3 tool.
- Configure launch URL:
https://<querybench-host>/lti/launch. - Configure JWKS URL:
https://<querybench-host>/.well-known/jwks.json. - Launch activity from course.
- Complete assessment and submit.
- Verify grade appears in LMS gradebook.
- JWT signature validation against LMS JWKS
- issuer/client/deployment validation
- nonce one-time-use validation
- timestamp freshness validation (
iat,exp) - HTTPS enforcement for LTI endpoints (strict in non-debug)
LTI launch receivedJWT validateduser provisionedassessment mappedsession createdgrade returned
Standalone flow is unchanged:
- login -> dashboard -> start assessment
LTI launch flow bypasses standalone login and creates LMS-sourced session directly.