SSO pages
Every UI surface involved in the SSO flow. For the mental model see Identity and SSO; for setup see Admin → Configure global SSO or Admin → Configure per-org SSO.
/login — the picker
Anonymous users land here. The page asks how to sign in.
| Element | Behaviour |
|---|---|
| Email + password form | Local-password path. Available unless require_sso=true blocks it. |
| Sign in with SSO button | Opens the realm picker (below) |
| Register link | Visible only when public registration is enabled and the license allows new users |
The page does NOT show org-specific SSO buttons up front — those require a realm slug, which the next step asks for.
/login realm picker (modal)
Click Sign in with SSO → small dialog:
| Field | Notes |
|---|---|
| Organization realm | Type your org slug (e.g. acme). Leave blank to use global SSO. |
| Continue button | POSTs to /api/auth/discovery with the slug |
Discovery response shapes the next step:
oidcbutton → org's IdP found, click to start redirectoidc (global)→ no per-org IdP, falling back to globallocalbutton → no SSO at all, you're back at password- No button at all → "No SSO provider for that realm" error (slug doesn't exist OR exists but has no SSO and no global is configured)
/sso — start
URL: /sso?slug=<org-slug>&redirect=<post-login-path>
This route is short-lived. The browser hits it, the backend
builds an encrypted state token, redirects you to the IdP's
authorization URL. You shouldn't see this page in normal flow —
it's a server-side bounce.
If you DO see it (white screen, no redirect): the SSO config has a malformed issuer URL or the discovery call failed. Check the backend logs.
IdP redirect
Your browser is now at the IdP (Auth0, Keycloak, Okta, Azure AD, …). The dtedge UI has no visibility here. You authenticate however the IdP requires — password, MFA, hardware token, whatever.
On success the IdP redirects back to /sso/callback?code=...&state=....
/sso/callback — server-side
Like /sso, this is short-lived. The backend:
- Decrypts
state, verifies freshness (10 min window) - Exchanges the
codefor ID + access tokens - Verifies the ID token signature against the IdP's JWKS
- Verifies the
noncematches what we put instate - Extracts claims (email, name, sub, groups)
- Links / provisions the user
- Reconciles roles from group mapping (if configured)
- Issues a dtedge JWT
- Redirects to
/sso/finish?token=<jwt>
/sso/finish — token landing
The page that receives the freshly minted dtedge JWT. It stores
the token in localStorage and redirects to the original destination
(or / by default).
In a normal flow you see this page for a fraction of a second. If you see it stuck, JavaScript or storage may be disabled.
/sso/error — failure landing
Where SSO failures end up. The URL carries an error code as a query param:
| Code | Meaning |
|---|---|
INVALID_STATE | The state token was missing, expired, or tampered with. Try logging in again. |
STATE_EXPIRED | The state token was older than 10 minutes (you sat on the IdP login page too long). Try again. |
NONCE_MISMATCH | The ID token's nonce doesn't match what we sent. Tampering or stale browser tab. |
ID_TOKEN_INVALID | The IdP returned a malformed token. Check the IdP side. |
PROVIDER_GONE | The SSO config was deleted between when you started login and when you came back. Admin issue. |
EMAIL_CLAIM_MISSING | The IdP didn't include an email claim. Fix the IdP scope. |
NOT_PROVISIONED | Auto-provision is off and you're not in dtedge yet. Admin needs to invite you. |
LINK_FAILED | Internal failure during identity link. Backend log has details. |
Organizations → <org> → SSO tab
Org admin's per-org SSO config page. The form has:
| Section | Fields |
|---|---|
| Provider | Issuer URL, Client ID, Client secret |
| Scopes + claims | Scopes (space-separated), Claim mappings (email/name/groups) |
| Provisioning | Auto-provision toggle, Default role dropdown |
| Group → role mapping | Add row (IdP group name → org role dropdown) |
| Policy | Require SSO toggle |
| URIs | Redirect URI, Back-Channel Logout URI, Post-Logout Redirect URI (read-only; for pasting into the IdP app config) |
| Actions | Save / Remove |
Each save runs PingIssuer (discovery URL must respond) and
validates each mapping row's role exists.
Admin → Settings → Global SSO
Super-admin's install-wide SSO. Same shape as per-org, plus:
| Section | Fields |
|---|---|
| Org-role assignments | Grid of (IdP group, org, role) rows; the role dropdown is filtered to the picked org's roles |
The Default role field is hidden on this surface (less meaningful for global SSO — the org-role assignment grid usually handles role placement).