Docs
Open the console →
Guides

Staff console SSO (corporate OIDC)

Sign in to the Cushy staff console with your corporate identity provider: configure OIDC on /admin/security, the exact Keycloak client setup, realm separation and the no-JIT rule.

The staff console (/admin) is a separate authorization realm from every customer organization: its own login page, its own cc_staff session cookie, and — with this feature — its own identity provider. A platform admin can point it at the company IdP (Keycloak, Okta, Entra ID, or any OIDC provider that publishes a discovery document) so operators sign in with their corporate account instead of a console password.

SSO never creates a staff account

Staff SSO only AUTHENTICATES an account that already exists and is already a platform admin. An email the platform does not recognise is refused with exactly the same generic message as a wrong password, and nothing is created or promoted. Auto-provisioning here would mean anyone who can obtain an identity in the corporate directory becomes a platform operator.

What you configure, and where

Sign in to /admin with your staff password, open Security & trust (/admin/security), and use the Corporate SSO (OIDC) card at the top. There is no environment variable and no seed — this screen is the only way the staff IdP is configured. The surface needs the SCP action platform.security:manage_sso (Platform Owner, Platform Admin and Trust & Safety carry it); reads need platform.security:read_sso.

FieldWhat it is
Issuer URLThe IdP issuer, e.g. https://idp.snoweasl.com/realms/snoweasl. Saving runs OIDC discovery against <issuer>/.well-known/openid-configuration server-side and stores the resolved authorization, token and JWKS endpoints. A typo fails here, not at an operator's first sign-in.
Client IDThe confidential client you create at the IdP for this console.
Client secretStored as an AES-256-GCM envelope under CC_DATA_KEY and NEVER returned by any API — the config only ever reports whether one is on file. Leave the field blank when editing to keep the stored secret.
Allowed email domainsOptional. When set, only these domains may sign in, whatever the IdP asserts.
Groups claimOptional. The ID-token claim carrying group membership (Keycloak: groups).
Group → staff roleOptional. With at least one mapping, sign-in REQUIRES membership of a mapped group — it is an admission gate as well as a role hint.

The card shows the redirect URI to register at the IdP. It is always <your console origin>/api/admin/auth/oidc/callback.

Keycloak setup, step by step

  1. Create a client in your realm

    In the Keycloak admin console, choose your realm → ClientsCreate client. Client type OpenID Connect, Client ID e.g. cushy-staff-console. Next.

  2. Turn on client authentication

    On the Capability config step, enable Client authentication (this makes it a confidential client, which is what the console's client_secret_post token exchange requires). Enable the Standard flow (authorization code). Leave Direct access grants, Implicit and Service accounts off — none are used.

  3. Set the redirect URI

    Valid redirect URIs: paste the exact value shown on the Corporate SSO card, e.g. https://cloud-control.snoweasl.com/api/admin/auth/oidc/callback. No wildcard is needed. Web origins can stay empty — the console never calls the IdP from the browser with CORS.

  4. Copy the client secret

    Client → Credentials tab → copy the Client secret. This is the only value you paste into the console that is a secret; it is encrypted at rest immediately and never shown again.

  5. (Optional) add the groups claim

    To use group → role mapping: Client → Client scopes<client>-dedicatedAdd mapperBy configurationGroup Membership. Token Claim Name groups, and turn ON Add to ID token. Keycloak emits group paths like /cushy-platform-admins; the console matches with or without the leading slash.

  6. Save it in the console

    Back on /admin/security, enter Issuer https://idp.snoweasl.com/realms/<realm>, the Client ID, the Client secret, optionally your email domain and the groups claim, then Save & run discovery. A successful save enables SSO immediately.

  7. Sign in

    Open /admin/login in a fresh session — a Sign in with corporate SSO button now appears above the password form. It redirects to Keycloak, and a successful authentication of an existing platform admin lands on /admin.

Which claims are read

  • iss — must equal the configured issuer, exactly.
  • aud — must contain the configured client id.
  • exp — must be in the future; nonce must match the one the console generated for this transaction.
  • email — the identity that is matched against existing platform admins. Required.
  • email_verified — if the IdP explicitly says false, sign-in is refused.
  • name — used for display only when present.
  • the configured groups claim — read only when you set one; accepts a string array or a single string.

The ID token must be RS256-signed and is verified against the issuer's published JWKS. The authorization code is exchanged server-side with client_secret_post plus a PKCE S256 verifier that never leaves the server.

Realm separation

The staff realm and the customer realm cannot be crossed, by construction:

  • Each in-flight login transaction carries a realm marker. A state minted by a customer organization's SSO flow is refused at the staff callback, and a staff state is refused at the customer callback — in both directions, and the state is consumed either way.
  • A staff session is only ever minted after the ID token's issuer and audience match the STAFF configuration. A token from a customer's IdP — even a validly signed one, even for an email that belongs to a real platform admin — is refused.
  • The customer callback never sets cc_staff, and the staff callback never sets cc_session.
  • Every failure is the same generic message, so nothing about which emails exist can be learned from it. The staff lockout (5 attempts) is shared with the staff password door.

Password sign-in stays

Staff password login is never disabled by configuring SSO. It is the deliberate break-glass route for the day the IdP is unreachable or misconfigured — including the case where a bad SSO configuration is what you need to sign in and fix. You can also Disable or Remove the SSO configuration from the same card at any time.

What is audited

  • staff.sso_configured / staff.sso_enabled / staff.sso_disabled — the configuration changes, with the matched SCP statement id.
  • staff.sso_started — a sign-in was begun.
  • staff.login_sso — a successful SSO sign-in, with the issuer and any mapped group role.
  • staff.login_sso_failed / staff.login_locked — every refusal, with the real reason (which the user never sees).

All of them appear on Staff · Platform history (/admin/history).

Current limits

OIDC only — staff SAML is not built. The IdP group → staff role mapping is enforced as an ADMISSION gate and recorded on each sign-in; the effective staff role still comes from the account's platform-admin grant until per-staff role assignment ships. There is one staff IdP for the whole platform, and SSO does not yet satisfy a staff MFA requirement on its own.