Sync / roster
Keep LMS course rosters in step with the SIS using LTI Advantage Names & Role Provisioning, without a nightly flat-file dump.
Flat-file roster loads drift the moment a student adds or drops. LTI Advantage Names & Role Provisioning Services (NRPS) lets the LMS pull the authoritative membership for a context on demand, keyed to the SIS section. Map the SIS section identifier to the LTI context_id, expose a memberships endpoint, and let the LMS reconcile.
A working piece from this integration — no sign-up. The full build handles the edge cases, safeguards, and cutover.
{
"id": "https://lms/context/123/memberships",
"context": { "id": "SIS-SECTION-202610-BIOL101-01" },
"members": [
{ "user_id": "…", "roles": ["Learner"], "status": "Active" }
]
}How we'd take this from discovery to a production-safe cutover — the phases, the canonical mapping, and the edge cases that bite.
Keep LMS course rosters in sync with the SIS using LTI 1.3 Advantage Names and Role Provisioning Service (NRPS). This replaces nightly flat-file dumps with real-time membership calls initiated by the LMS against the SIS platform endpoint. The SIS acts as the LTI 1.3 Platform; the LMS acts as the Tool. All calls use OAuth 2.0 bearer tokens with RS256 JWT signatures.
/api/lti/.well-known/jwks.json), redirect URIs, and OIDC login initiation URL. The SIS records the tool's client_id, grants the names_and_roles scope, and issues a platform-level installation ID. Validate that the SIS security document exposes a memberships endpoint before proceeding.aud claim matches its client_id, and exchanges the id_token for an access token via the token endpoint. Store the access token and refresh token securely (AES-256 at rest minimum).memberships service URL. The endpoint follows the pattern {platform_base}/api/lti/courses/{course_id}/names_and_roles. Verify the endpoint accepts a limit pagination parameter and optionally a !update timestamp for delta queries.Bearer {token}). The response contains a context object (course identifier) and a members array. Paginate through all pages using the next link. Map each members[].role value to an internal role constant:
Student / Enrollment → LearnerInstructor → InstructorTA / TeachingAssistant → TeachingAssistantmembers[].status (Active or Inactive) and lis_person_sourcedid as the stable SIS person identifier.lis_person_sourcedid (or create by email with update_on_email_match = true). Compute the delta against the current LMS enrollment table: additions, removals, role changes. Write changes via the LMS enrollments API (e.g., Canvas POST /api/v1/courses/{id}/enrollments). Handle instructors and TAs with enrollment_type = teacher or ta; do not use designer for instruction-capable roles.partial_sync_mode = true after three consecutive failures and halt the batch.| NRPS Field | Description | SIS Source | LMS Target |
|---|---|---|---|
context.id |
Course identifier | Section CRN + term | Canvas course[id] / Moodle course[id] |
members[].user_id |
LTI person identifier (opaque) | Internal person UUID | user[id] cross-reference |
members[].name |
Display name | full_name |
Canvas user[name] |
members[].email |
Primary email address | institutional_email |
Canvas user[login_id] / Moodle user[email] |
members[].status |
Active or Inactive | Enrollment status field |
Canvas enrollment[enrollment_state]: active / inactive |
members[].roles |
LIS role URI list | Role type |
Reading the reference is free. Delivering it under liability — with the safeguards that keep production running through the cutover — is what we do.