Canvas Integration
Journey runs alongside Canvas LMS as a separate service. Authentication, user identity, and account scoping all originate in Canvas, and Journey is mounted inside a Canvas application that hands users off via a signed JWT. Journey owns its own resources — programs, skills, experiences, learning library — but reads user, course, account, and enrollment data from Canvas via the Canvas REST and GraphQL APIs. This document explains how Journey's API surface relates to Canvas behind the scenes.
Authentication and identity
End-user requests authenticate with a Canvas-issued JWT — see authentication for token format, validation, and the service tokens used for inter-service traffic. The JWT carries the Canvas user global ID (sub), the Canvas user UUID (user_uuid), the Canvas root account UUID (root_account_uuid), and the Canvas domain that issued it. These four values are the only identity Journey ever consumes from the client; Journey never issues its own login session and never stores Canvas passwords or OAuth refresh tokens on behalf of end users.
On every successful JWT validation Journey looks up its internal user record keyed by (canvasUserUuid, rootAccountUuid). If no record exists Journey provisions one, persisting the Canvas user ID, Canvas base URL, root account UUID, and Canvas user UUID. If the record exists but the Canvas user ID or base URL has drifted (for example after a Canvas instance rename), Journey updates the record in place. The resulting Journey-internal UUID is attached to the request as internalId and used everywhere downstream.
User and account model
Journey users mirror Canvas users 1:1, scoped by Canvas root account, so the same Canvas user signing into two root accounts becomes two separate Journey user records. Journey does not maintain a separate account entity — the Canvas root account UUID is itself the account identifier and is carried on every tenant-scoped resource (see permissions).
Journey-issued UUIDs and Canvas-issued IDs coexist on the wire. See object_ids for the full breakdown; the short version is that anything Journey owns has a v4 UUID and anything that originated in Canvas keeps its Canvas ID.
Data ownership
Journey is the system of record for its own resources and a read-mostly client of Canvas for everything else.
Owned by Journey:
Programs, skills, experiences, learning library collections and bookmarks
Dashboards and dashboard snapshots
Alignments between Journey resources and Canvas courses/learn-items
Per-user enrollment state in Journey-owned programs and learning items
HRIS connector state
Read from Canvas (live or cached):
Users, root accounts, sub-accounts, account permissions, admin roles
Courses, course progress, modules, pages, assignments, files, enrollments
Career-enabled status for the signing-in user's root account
Canvas reads are cached opportunistically with a per-call time-to-live; reads that are not eligible for caching go straight to Canvas. The per-request user provisioning lookup is also cached so it does not hit the database on every call.
Writes to Canvas
Journey is not purely read-only against Canvas. A focused set of write operations is used by specific Journey features:
Course lifecycle for the learning library (create, update, delete, and publish courses)
Authoring of pages, assignments, modules, module items, and files
Content migration and sharing
Enrollment, inbox messaging, and file uploads
SIS imports and account reports
Career records (creating and deleting user experiences and account memberships)
These writes always run against the Canvas domain recorded on the acting Journey user, using a Canvas API access token that Journey manages, and typically masquerade as the calling end-user (via as_user_id) so the write is attributed to that user rather than the service account.
ID mapping
Most Journey responses include both kinds of identifiers when both are meaningful — a Journey UUID for the Journey resource and the Canvas global ID (or UUID) for the Canvas object it references. See object_ids for the full conventions and the rules around GraphQL Node IDs.
Last updated
Was this helpful?