# School sign-in for staff and students

ClassGuard supports Google Workspace, Microsoft Entra ID, Clever, ClassLink and compatible OpenID Connect (OIDC) providers. Staff sign in to their existing ClassGuard account. Students connect to an existing, active school roster record. SSO does not create teachers, grant administrator privileges or import rosters; use [roster integrations](integrations-setup.md) for class lists.

## Set up a school

1. Host the school service behind HTTPS. Use that school backend origin, such as `https://classguard.school.example`. The public `classguard.org` product Site is a separate service and does not serve your school's SSO callback.
2. Register a confidential web application with the provider. Register the exact callback `https://classguard.school.example/api/sso/callback/PROVIDER`, replacing PROVIDER with `google`, `microsoft`, `clever`, `classlink` or `oidc`. Choose only the intended school tenant/district and complete the provider's app approval and agreements. Connector code does not establish an official partnership or certification.
3. Run `npm run setup`, then `npm run configure:sso` on the school server. The helper asks for the client ID, a hidden client secret, approved tenant/domain/district, staff/student audiences and approved Chrome extension IDs. It writes `classguard-server/private/sso.json` with owner-only permissions. Only its path (`CLASSGUARD_SSO_FILE`) is added to `.env`; other school settings are preserved. Do not put secrets in Chrome policy, source control, chat or the public Site.
4. Run `npm run configure:sso -- --check`, then restart the school service. This validates local settings; it does not verify a live provider connection. Configured providers appear on the school's staff and student sign-in pages.
5. Approve staff identities and student mappings below. Test one teacher and one enrolled student with the real provider before district rollout. Keep an administrator's local password available for recovery.

The callback uses authorization codes. OIDC providers must return signed RS256 or ES256 ID tokens with the expected issuer, audience, nonce and expiry. School sign-in requests are browser-bound and one-use. Generic OIDC endpoints must be public HTTPS and on the issuer origin or explicitly approved additional origins. Redirects and private-network endpoints are rejected. SAML is not implemented.

## Staff accounts and roles

An administrator first creates the staff account and assigns its ClassGuard role and classrooms in **Staff & classrooms**. Then either:

- The staff member signs in with their ClassGuard password, opens **School sign-in**, confirms their current password and completes the provider sign-in to link their identity. Staff must finish changing any temporary password before self-linking.
- An administrator opens **Staff & classrooms → School single sign-on**, selects the provider and existing staff account, and approves its verified immutable identifier from the school's identity system. For Microsoft use the tenant's **object ID (`oid`)**; for Google/ClassLink/generic OIDC use the app's `sub`; for Clever use the Clever user ID. Identifiers may be app-specific. Never substitute an email address or display name.

Signing in with a matching email alone does not link an account. Provider role claims never grant ClassGuard permissions. An administrator-approved SSO identity can sign in without first using a temporary local password; the temporary-password flag remains in place for password sign-in. Removing a staff link signs that account out of ClassGuard. Disabled staff cannot use SSO. Staff SSO sessions last at most one hour and no longer than the verified ID token.

## Student enrollment and Chrome setup

Import the roster first. SSO only matches an existing active record; it does not admit unknown students. Choose one of these matching methods:

| Provider | Student identity match |
| --- | --- |
| Google Workspace | Google-synced roster's immutable Google ID equals `sub`, with the enrolled email still matching. The ID token must have a verified email and an explicitly approved Workspace `hd` value. |
| Clever | Verified Clever user ID matches the imported Clever record in the configured district. The OAuth identity must be district-authorized. |
| ClassLink | Signed `classLink_sourcedId` matches the imported ClassLink record from the configured roster connection. The signed ClassLink tenant must match. |
| Microsoft Entra ID | Private mapping from the tenant's immutable `oid` to a ClassGuard roster ID, or a school-configured signed immutable SIS claim. Email and UPN are not identity matches. |
| Other OIDC | Private mapping from the app's `sub` to a ClassGuard roster ID, or a signed immutable SIS claim. |

A provider's optional `studentBindingsFile` is an absolute path to a private JSON object mapping provider subject to ClassGuard `studentId`, for example `{"provider-immutable-id":"S123"}`. Keep it owner-readable only; up to 100,000 mappings and 32 MiB are accepted. For Microsoft, the key is the lowercase `oid` GUID. Explicit mappings take priority over automatic provider matching. ClassGuard rejects missing/disabled records.

Instead of a mapping file, advanced configuration can use `"studentMatch":{"claim":"student_number","field":"studentId","source":"csv"}` on the provider. IT must ensure the claim is signed, immutable and unique within the configured school. Supported fields are `studentId` and `externalId`; external IDs must also match the configured roster connection. Email, UPN and names are rejected. Do not use a student-editable profile claim.

For managed Chrome, set `SchoolServerURL` to the school backend and `SchoolSSOProvider` to the provider ID. Add the actual installed **extension ID** to the server's approved `extensionIds` list. Enable this policy only after testing the provider. Example policy entries:

```json
{"SchoolServerURL":"https://classguard.school.example","SchoolSSOProvider":"microsoft"}
```

The extension's handoff is `https://EXTENSION_ID.chromiumapp.org/school-sso`. The identity provider registers the **school backend callback**, not this handoff. After sign-in, the extension verifies its own request state, then redeems a short-lived, one-use ticket with its PKCE verifier. Enrollment credentials stay in Chrome session storage, expire within one hour, and are renewed when the provider can sign in silently. A student may need to sign in again when silent renewal needs interaction. Managed SSO does not fall back to a manual setup code or a different provider.

The web student portal also offers school sign-in, but the installed managed extension is still required for automatic active-tab screenshots and website enforcement. SSO does not start a class or capture a screenshot. Only authorized teacher-started classes can request visible active-tab screenshots under the existing classroom rules.

## Provider registration notes

- **Google Workspace:** configure a web OAuth client and exact callback, request `openid profile email`, and configure the approved Workspace hosted domains. Restrict app availability through the school's Google controls as needed. A domain-like email is insufficient; ClassGuard checks signed `hd`. The older Google enrollment path remains available, but use `SchoolSSOProvider: "google"` for the unified staff/student path. [Google OIDC documentation](https://developers.google.com/identity/openid-connect/openid-connect).
- **Microsoft Entra ID:** register a single-tenant web app with the exact tenant GUID, client secret and callback. ClassGuard uses the tenant-specific v2 issuer, checks `tid`, and binds staff to `oid`. `common` and `organizations` are rejected. For students configure a private mapping or immutable SIS claim as above. [Microsoft OIDC documentation](https://learn.microsoft.com/en-us/entra/identity-platform/v2-protocols-oidc).
- **Clever:** obtain an approved district-authorized SSO app and register its school callback. The confidential OAuth code flow uses Basic client authentication, then verifies `/v3.0/me` and the matching user record. Configure the approved district ID. Secure Sync roster credentials are separate. IdP-initiated launches without ClassGuard's request state restart at school sign-in. [Clever OAuth implementation](https://dev.clever.com/docs/oauth-implementation).
- **ClassLink:** obtain the school-approved OIDC app, exact tenant ID, client credentials and callback. ClassGuard uses [ClassLink's published discovery metadata](https://launchpad.classlink.com/.well-known/openid-configuration), checks the signed tenant and uses `classLink_sourcedId` for roster matching. Use the app's actual `sub` for staff links. Roster Proxy access is separate from SSO approval. PKCE can be enabled in private configuration if supported by the approved app.
- **Other OIDC:** configure the exact issuer, preserving a meaningful trailing slash. Discovery is read from the issuer's `/.well-known/openid-configuration`. Set additional HTTPS endpoint origins only when documented by the school-approved provider. Optional `tenantClaim` and `tenantId` can pin a signed school identifier. PKCE is on by default. Canvas/OneRoster roster access does not itself configure an identity provider.

## Recovery, retention and limits

Staff identity links persist in the accounts SQLite database and its backups. Provider client secrets remain in the separate private configuration; back them up separately with encrypted, access-controlled recovery storage. ID/access tokens are not persisted. Student SSO sessions and incomplete browser flows are temporary and are lost on school-server restart. Multiple server instances need shared session storage before a distributed deployment; this release runs one school service.

Disable the local staff/student record to revoke ClassGuard access, unlink a staff identity, or disable/remove the provider and restart. Provider-only account revocation is not immediate backchannel logout; existing ClassGuard sessions may last until their bounded expiry. Signing out of ClassGuard does not globally sign the user out of Google, Microsoft, Clever or ClassLink. SCIM provisioning and SAML are not implemented. Test provider approval, session renewal, account disabling and recovery in the district pilot. Roster size is not a promise of simultaneous classroom capacity.

## No student portal

For managed Google Chrome profiles, enable [managed student mode](managed-students.md). IT preapproves the Google connection and force-deploys the extension; student identity is verified against the active primary Chrome profile. No setup code, login portal, account picker or consent prompt is opened for students. Classroom viewing notices remain visible. Force installation alone does not configure Google authorization.
