System Purpose
Safe Online Exam is an LTI 1.3 tool for requiring Safe Exam Browser on Canvas Classic Quizzes and New Quizzes. It has four connected responsibilities:- Give instructors a course-scoped interface for discovering Canvas assessments and managing SEB policy.
- Give verified root-account administrators a Canvas-embedded, school-wide recovery interface with controlled password reveal, active-course connection, and bulk tool rollout.
- Generate protected SEB configurations and establish a Canvas session inside SEB without transferring a normal-browser session cookie.
- Release the Canvas access code and approved web-tool capability only when SEB proves that it is using the current configuration.
Runtime Shape
The application is one Node.js process. NestJS controllers expose HTTP endpoints, services own protocol and business behavior, repositories provide PostgreSQL storage in deployed environments and in-memory storage for local or test work, and React renders page views supplied by the server app shell. The detector is a separately served browser asset that runs on Canvas quiz pages.Code Ownership
Identity and Authorization
LTI Launch Validation
Canvas initiates OIDC at/lti/login. The service verifies the issuer, requested target link URI, configured client ID, and configured deployment ID before creating encrypted state. State is valid for ten minutes and is additionally bound to a short-lived, HttpOnly, secure browser transaction cookie.
Canvas posts an ID token to /lti/launch. The service validates:
- RS256 signing against the configured Canvas JWKS.
- Issuer, audience, nonce, token age, issued/expiry timestamps, LTI version, message type, and deployment ID.
- The target link URI and initiation state tuple.
- The initiating browser transaction cookie.
- A durable, atomic PostgreSQL state claim to prevent replay.
Canvas OAuth Flow
An LTI launch authenticates a person but does not authorize Canvas API calls. The application uses a separate Canvas OAuth authorization for API access:Initiate from a verified launch
/api/oauth2authorize or /api/oauth2reauthorize from the same-origin tool UI created by an existing verified launch. Browser requests whose Fetch Metadata identifies any other site relationship are rejected.Record state and redirect
Exchange the authorization code
/api/oauth2callback verifies state and exchanges the authorization code for access and refresh tokens.Persist one grant per Canvas user
CanvasApiService refreshes it when necessary.Complete in a popup or return through Canvas
/api/admin/oauth2authorize to upgrade their existing user grant with administrator scopes. Every admin mutation also requires a short-lived HMAC action token bound to the LTI subject, Canvas user, root account, deployment, and current Express session.
Assessment and Course Model
Identifiers
All persisted assessment records use a canonical public content ID:assessments table stores Canvas discovery data, availability verification, and SEB state. courses stores course-level defaults and its exam-tool catalog. Course defaults can provide URL policy, start/exit password policy, and selected exam tools; an assessment may inherit defaults, retain an explicit list of course tool IDs, and add quiz-only tool definitions.
Canvas Discovery and Availability
Instructor discovery refreshes Classic and New Quiz data from Canvas. A learner can use an assessment only when its cached Canvas verification is current, explicitly verified, published, and within its global unlock/lock window. The verification window is 24 hours. Missing records are retained for instructor reconciliation but fail closed for learners; a failed refresh marks the cached discovery stale. Assessment updates use short-lived PostgreSQL operation locks while Canvas and database state are changed. Administrator course resets take a course-level lease and then the same per-assessment leases, so ordinary assessment mutations cannot overlap a reset. Course refreshes, administrator connection-count writes, school-preset assignment writes, and instructor tool copies use the same course fence so they cannot recreate state after a reset. Atomic compare-and-delete/insert operations prevent overlapping workers from owning the same lease and help keep Canvas access codes aligned with persisted SEB settings. Each workflow carries a shared lease guard across nested locks and checks it after external reads and before later Canvas or PostgreSQL mutations; a failed background renewal makes the guard reject those later side effects immediately. After final ownership verification, releasing a lease is best-effort: a cleanup failure cannot replace the verified action result, and the bounded lease expires automatically. An administrator course reset performs read-only, strict Classic Quiz and New Quiz discovery and reads every assessment’s current Canvas access-code state before making the first destructive call. The discovery result is assembled in memory instead of changing cached learner-verification state that would need recovery if the preflight aborts. The reset then removes each Canvas access code with the account-administrator grant and only afterward deletes course-related transient state, assessments, the course policy, and per-course school-tool preset assignments in one PostgreSQL transaction. That transaction also stores an operation-specific reset receipt on the retained root-account course connection; the shared OAuth grant is deliberately retained. If a Canvas response is lost, a later Canvas mutation fails, or the database transaction definitively fails, the service restores the exact pre-reset Canvas state for every assessment that may have changed and restores its prior local assessment record in reverse order. If the transaction commit response is ambiguous, the service verifies the durable reset receipt before compensating. An unavailable receipt check, failed compensation, or lost lease is reported as an indeterminate result that requires refresh and verification rather than blindly restoring Canvas state.Exam Tools and URL Policy
Course-owned exam tools have an exact HTTPS launch URL and typed resource rules: one exact page or file, an address and related links, or an explicitly confirmed whole website. Instructors explicitly approve both tool start pages and resources, including a different HTTPS website such as a CDN asset; the instructor UI calls out cross-site access before saving. A saved instructor-owned tool can be duplicated into active Canvas courses where the same OAuth user is a teacher. The browser can only choose from a Canvas-filtered course list, and the server retrieves that list again before every target write; target IDs alone never authorize a copy. The server also snapshots each target’s durable reset generation before those external reads and rejects the copy if a reset completed in the meantime or if reset-deleted course setup has not yet been recreated by a teacher launch. The copy appends a local tool without replacing the target catalog, preserves an existing equivalent definition on retry, and propagates the target course defaults so relevant configuration fingerprints are invalidated. A dedicated YouTube video tool accepts a watch, share, Shorts, or embed link and turns it into one embedded public video with a server-owned player page and bounded media policy. The server-owned page supplies YouTube’s required embedding identity while deliberately excluding YouTube browsing and Google sign-in. User-entered general rules remain restricted to safe HTTPS URLs or concrete domains; wildcards, credentials, arbitrary regular expressions, and unsafe historical patterns are rejected or quarantined. Root administrators can create reusable school presets inadmin_tool_presets and assign them to individual courses. An assigned definition is synchronized into the course catalog as school-managed: instructors may enable or disable it but cannot silently change its launch URL or resource access. Updating or deleting the preset synchronizes every assigned course and invalidates affected configuration fingerprints. Quiz-only definitions remain on the assessment record and never become course defaults.
SEB Lifecycle
Instructor Configuration
When an instructor enables SEB,AssessmentService creates an access code, mutates the appropriate Canvas assessment, and persists SEB state only after the mutation is successful. Enabling requires an effective exit password: assessment override, course default, or configured managed default. Optional start passwords protect the inner configuration payload. Password responses are redacted by default; an instructor can make a narrowly bound, short-lived reveal request.
Student Configuration Download
Request a configuration grant
Obtain a fresh Canvas session URL
Build and encrypt the .seb file
Deliver on grant consumption
GET /seb/config/:courseId/:contentId.seb consumes the one-time capability and streams the encrypted configuration to the student’s browser.Config Key Proof and Access-Code Release
Detector reads the Config Key
Request a proof token
POST /api/seb/access-proof/:courseId/:quizId. The server verifies the assessment, current settings fingerprint, URL family, and Config Key hash before returning a one-time proof token valid for two minutes.Redeem the proof for the access code
POST /api/seb/access-code/:courseId/:quizId consumes the proof token and returns the access code, approved tools, and an exit grant with sensitive response headers. A proof can be consumed exactly once.Fill the Canvas access-code prompt
GET /api/seb/requirement/:courseId/:quizId before showing the SEB-required prompt. That endpoint performs one exact assessments primary-key lookup and returns sebRequired: true only when the stored course/content relationship matches and the SEB configuration is enabled, required, and usable. An absent, mismatched, disabled, malformed, or unverifiable result does not produce a launch prompt.Completion and Exit
The detector waits for Canvas-authored completion evidence. Classic Quiz completion requires a successful final submission and the matching Canvas result structure; New Quiz completion requires the authoritative result UI. On confirmed completion, the detector uses a settings-bound exit grant to display a quit link. Unbound manual and automatic quit paths intentionally return410 rather than accepting a general-purpose quit request.
Setup Check
/seb/check/config.seb generates a separate configuration for testing certificate decryption, SEB runtime detection, connectivity, storage, and Config Key proof. It never releases an assessment access code and does not establish device trust. It should be part of pre-exam readiness testing, not a substitute for device management.
Configuration Security Boundary
Generated assessment configurations include a strict Canvas and approved-resource URL filter, SEB Config Key proof setup, session-monitoring and kiosk-related policy, exit protection, and optional start-password protection. The exact plist is built bySebConfigurationService.
Certificate Encryption Model
Certificate encryption is enabled by default, including in hardened runtimes. The public X.509 certificate or public key permits wrapping the file; the matching private identity belongs only on approved client devices. An instance that cannot distribute that identity may explicitly setSEB_CONFIG_ENCRYPTION_ENABLED=false; in that mode the configuration is plaintext unless an instructor sets a start password.
Assessment configurations use the SEB exam-start purpose and include the assessment start URL, an HMAC-bound quit URL, URL filter rules, a derived Browser Exam Key, and a Config Key salt. If an instructor sets a start password, the inner configuration is password-protected before certificate wrapping. The outer encrypted file uses SEB’s public-key-hash (pkhs) format when a public certificate is configured.
The setup-check configuration is deliberately different from an assessment configuration: it starts at /seb/check, has no assessment access code, allows quit without an assessment exit password, and cannot redeem an access-code proof.
macOS lockdown policy details
macOS lockdown policy details
enableMacOSAAC and lockdownModePolicy, requires installation from the system Applications location, and sets a macOS 12.1 floor through explicit version-number settings plus the coarse version field. The overlapping AAC keys cover supported SEB client generations; they do not replace device management. AAC may block third-party assistive technology, so an accommodation that requires it needs a separate approved assessment or proctoring arrangement rather than a weakened common configuration.Windows lockdown policy details
Windows lockdown policy details
Persistence and Expiration
PostgreSQL transactions and row locks implement atomic state claims, one-time token consumption, rate-budget increments, and operation-lock ownership. Claim/consume operations use conditional mutations so two app instances cannot both win the same one-time claim. Cleanup selects bounded batches withFOR UPDATE SKIP LOCKED, allowing safe overlap without long table locks. This is why multiple app instances can share runtime state without sticky sessions.
schema_migrations. The application never mutates schema on ordinary startup; /ready fails until all checked-in migrations are applied. A migration job must complete before traffic reaches a new image.
HTTP and Security Controls
- Security headers are applied before application routes; Express disables
x-powered-byand trusts one proxy hop. - Sessions use
HttpOnlycookies and useSecure; SameSite=Nonewhen the configured tool URL is HTTPS or the profile is production. - Sensitive proof, access-code, and password-reveal responses are
no-storeand are bound to the verified session/principal. - LTI initiation and token validation use process-local and PostgreSQL-backed admission budgets. Configuration-grant minting is rate-limited per principal and IP.
- Canvas API calls are constrained to the configured Canvas origin and
/api/v1base. Responses have size limits and upstream deadlines; a401triggers at most one safe token refresh/retry. - The public detector script has two stable paths. Debug or diagnostic modes serve a readable, non-cacheable asset; normal production mode serves the built minified asset from the same public path.
- Public JavaScript and CSS responses are compressed; user-specific HTML and API responses remain outside that compression middleware.
Route Reference
The application exposes six groups of public HTTP routes: LTI and health routes, Canvas OAuth routes, SEB student and configuration routes, the Canvas detector and diagnostics routes, instructor assessment routes, and root-account administrator routes. The route handlers are the source of truth for parameters and response schemas; unlisted query parameters and output fields are implementation details.LTI Routes
OAuth Routes
SEB Student Routes
.seb download, Config Key proof, access-code redemption, setup check, and exit flows.