Skip to content
Open the app

The OIDC flow

First Six authenticates students and staff through your institution's identity provider using OpenID Connect. The flow is implemented server-side (authorization code with PKCE), so there is no third-party auth SDK in the browser and no password ever reaches us.

The flow

/auth/sso/{slug}/start
  → set state + nonce + PKCE verifier (httpOnly cookies)
  → redirect to your IdP's /authorize
your IdP authenticates the user
  → redirect back to /auth/sso/{slug}/callback?code=...
callback:
  → validate state (CSRF), exchange code (PKCE + client secret)
  → verify id_token against your IdP's JWKS (issuer + audience)
  → link the verified email/subject to a First Six record
  → mint an HttpOnly session cookie

The session cookie is the only thing that persists. Every subsequent database read is authorized by it through row-level security.

Per-tenant configuration

Each institution has an sso_config object holding the public parts of the connection:

  • issuer — your IdP's issuer URI
  • client_id — the application registration id
  • discovery_url — your .well-known/openid-configuration endpoint; when set, it resolves the authorize, token, and JWKS URLs for you
  • scopes — must include openid
The client secret is never in the config row

Only the public connection details live in the tenant config. The OIDC client secret is held in server-side environment configuration, not in the database, so it is never readable by the application clients that can read the rest of the config.

Microsoft Entra

For Microsoft Entra ID, the connection is:

  • discovery_url: https://login.microsoftonline.com/{tenant-id}/v2.0/.well-known/openid-configuration
  • client_id: your Entra application's Application (client) ID
  • a client secret, which you provide to us to store server-side
  • PKCE is mandatory (Entra requires it for confidential clients)

You register First Six as an app in Entra, add the callback URL as a redirect URI, and hand us the client id, secret, and tenant id.

Linking, not creating

This is the key behaviour to understand: a successful login links an identity to an existing record. It does not create one.

claim_sso_identity matches the verified email (or IdP subject) to a student or staff row that already exists, and binds the auth identity to it. If there is no matching row, the login fails. So the roster has to be in place first, which is what SIS sync is for. Provision the roster, then turn on SSO.

Testing before you go live

You do not need your real IdP wired up to exercise this end to end. First Six ships a gated test identity provider (FakeU) that mints valid tokens against demo personas. See Testing SSO before launch.

Was this helpful?
Need more help?

The fastest answer is usually one question away.

Edit this page on GitHub