Complete Deployment and confirm that the service’s public
TOOL_URL is final before creating any Canvas registrations. For Docker/VPS deployments, establish DNS and TLS before this step. The Cloud Run bundle reserves the stable URL before it pauses for the Canvas steps.Prerequisites
You need a Canvas root-account administrator who can manage Developer Keys, external apps, account themes, and OAuth scopes. You also need the deployed service URL and access to the deployment’s secret store. Before changing Canvas, confirm these service endpoints respond:/setup and /setup/guide pages on the service provide a public role-oriented checklist. They confirm that the service responds, not that Canvas has stored the intended registration or loaded the detector.
Values to Record
Keep a record of these values as you progress through the steps:Installation Steps
1
Create the Canvas API OAuth Developer Key
The application uses user-scoped Canvas OAuth tokens for assessment discovery and access-code changes. Do not replace this with a personal access token.In Canvas, open Admin, select the root account, open Developer Keys, and create an API Key. Use a recognizable name, owner email, and purpose, then set this exact redirect URI:If the Canvas instance supports enforced scopes, allow this complete application scope set:For the root-account administrator dashboard, also allow this administrator scope set on the same OAuth key:Every Canvas connection requests the complete scope set regardless of the user’s role. This prevents a person who is an instructor in one course and a student in another from holding an incompatible role-specific grant. Canvas continues to enforce the authorizing user’s actual account and course permissions.Store the API key’s client ID and secret in the deployment’s secret store as
CANVAS_API_CLIENT_ID and CANVAS_API_CLIENT_SECRET.2
Create the LTI 1.3 Developer Key
Return to the root account’s Developer Keys, create an LTI Key, and choose Canvas’s JSON configuration URL option. Enter:The configuration document supplies the title, course-navigation and root-account-navigation placements, OIDC initiation URL, target link URI, public JWKS URL, and signed custom fields. Prefer this URL over manually copying fields — the deployed service remains the registration source of truth.For reference, the individual values the configuration document provides are:
Enable the key and record its client ID as
LTI_CLIENT_ID.3
Install the External App
At the root account (or desired account scope), open Settings → Apps → View App Configurations. Add an app By Client ID, paste the LTI client ID from the previous step, approve the registration, and record the deployment ID Canvas assigns as Use a root-account-level installation for a broad rollout and for the administrator dashboard. Use a course-level installation only for an isolated instructor/student pilot; a course-level installation does not provide the root-account navigation surface.
LTI_DEPLOYMENT_ID.Set the deployment ID in LTI_DEPLOYMENT_ID, update the LTI client ID in the deployment’s secret store, and deploy a new service revision before testing. On Cloud Run, add numbered Secret Manager versions and re-run the setup or upgrade. On Docker/VPS, update the protected environment or mounted secret and recreate the application container.For a controlled self-service rollout where instructors may add the app to their own courses, set
LTI_DEPLOYMENT_ID_CHECKING_ENABLED=false on the service. This accepts any non-empty deployment ID in a Canvas-signed launch from the configured issuer and client ID. Only use it if everyone able to install this client ID in Canvas is trusted to grant access to the tool.4
Load the Detector Script Through the Canvas Theme
The detector runs on Canvas quiz-taking pages. It treats a Canvas access-code field only as a challenge signal, verifies the exact course/assessment against the service, fills an access code only after Config Key proof, shows approved web tools, and detects Canvas-confirmed completion.For a Cloud Run bundle deployment, generate the upload-ready loader file first:This writes a From Admin, select the intended account, open Themes, edit or create the active theme, and upload the loader as its desktop JavaScript. Preview, save, and apply the theme.
canvas-theme-loader.js file containing the exact configured public origin. Upload that generated file rather than manually transcribing the URL.The stable loader URL is:Some self-hosted Canvas deployments reject uploaded theme JavaScript with Do not disable Canvas CSRF protection globally to work around this. See the Canvas Setup source documentation for a Rails runner workaround for root-account recovery.
ActionController::InvalidCrossOriginRequest (HTTP 422). If you see that error in the browser console, configure the account theme’s js_overrides value to the externally hosted loader URL instead:5
Verify the Integration
Use separate administrator, instructor, and student accounts.
- As a root-account administrator, retrieve
/lti/config, confirm Canvas has the intended client and deployment IDs, and confirm both the Safe Online Exam Admin root-account navigation entry and the course app in a target course. - Open Safe Online Exam Admin, complete Canvas authorization, verify school courses load, create and assign a school tool preset, refresh a test course, reveal and rotate a test exit password, and confirm each operation appears in recent administrator activity.
- As an instructor, launch the tool from Canvas, complete OAuth, refresh assessments, enable the assigned school tool, create a quiz-only tool, set an exit-password policy, and enable one Classic Quiz and one New Quiz.
- In a normal browser, open each assessment page and verify that the theme loaded the detector script without console errors.
- As a student, launch the course-navigation tool, complete the one-time Canvas connection, and run the optional setup check.
- Hide the course-navigation placement from students, revisit both assessment pages in a normal browser, and confirm Open Safe Exam Browser still starts the signed LTI launch.
- Download a fresh configuration. On an approved SEB client, verify the configuration opens, reaches Canvas, proves its Config Key, fills the access-code prompt, and makes only selected exam tools available.
- For each assessment type, cancel one Canvas submission confirmation and ensure no exit occurs. Then submit successfully and ensure the exit flow begins only after Canvas shows the authoritative completed state.
Deployment Boundary
Why Each Canvas Instance Needs Its Own Deployment
The service has one active LTI platform configuration:CANVAS_DOMAIN, LTI_ISSUER, LTI_KEY_SET_URL, LTI_AUTH_URL, LTI_CLIENT_ID, and LTI_DEPLOYMENT_ID. Canvas cloud values are the defaults. If a service configured with cloud defaults is registered in a self-hosted Canvas, /lti/login redirects the embedded tool frame to sso.canvaslms.com — a page that is intentionally not embeddable by a self-hosted Canvas — and the browser shows sso.canvaslms.com refused to connect.
Deploy a separate service for each independent Canvas instance. Keep separate client IDs, deployment IDs, OAuth credentials, PostgreSQL databases, secrets, and service URLs for environments that must remain isolated (production, test, beta).
Self-Hosted Canvas Signing Keys
LTI Launch Recovery
Use the visible error state to choose the next diagnostic step:Common Integration Failures
LTI Deployment Configuration Required
LTI Deployment Configuration Required
Deployment-ID checking is enabled and Canvas installed the app with an ID not yet allowed by the service. Retrieve the
deployment_id from Canvas’s External Tools API for that course or account app, append it to LTI_DEPLOYMENT_ID without replacing existing IDs, deploy a new revision, then reopen the tool. For an intentional self-service rollout, an administrator can instead set LTI_DEPLOYMENT_ID_CHECKING_ENABLED=false.Canvas reports an LTI configuration or identity error
Canvas reports an LTI configuration or identity error
Refresh the registration from
/lti/config. Confirm the launch includes the signed numeric Canvas user custom field and that LTI_DEPLOYMENT_ID matches the installed app.Administrator dashboard is missing or denied
Administrator dashboard is missing or denied
Install the LTI app at the root account from the current
/lti/config. Use an actual root-account administrator. Confirm Canvas expands the account/root-account/root-admin custom fields and that the administrator OAuth scopes are allowed. A course installation or instructor enrollment is intentionally insufficient.Student cannot connect Canvas or configuration download fails
Student cannot connect Canvas or configuration download fails
Confirm the exact
url:GET|/api/v1/login/session_token scope is allowed in the OAuth key and that the student is authorizing the same Canvas environment as the LTI launch.Access code is not filled in SEB
Access code is not filled in SEB
Confirm a fresh configuration was downloaded, the detector loaded on the actual assessment route, Config Key proof succeeded, and the Canvas prompt is not ambiguous.
Detector never loads
Detector never loads
Check the active account theme, inherited theme behavior, browser console, CSP headers, and that the public detector URL returns JavaScript content.