Skip to main content
CYPEX Documentation
Support
v2.0.0 Latest stable release View changelog ->

SSO (OIDC & LDAP)

6 min read

CYPEX federates login to an external identity provider in two ways. OIDC and OAuth2 logins go through a standalone SSO Gateway service; LDAP is handled inside CYPEX itself and does not involve the gateway. Both paths end the same way: a successful federated login issues a PostgREST-compatible JWT, and the organization and role claims on that token drive the same PostgreSQL Row-Level Security (RLS) policies as local username/password auth. There is no separate SSO security path.

Google and Microsoft Entra have their own provider types with pre-filled endpoints. Auth0, Keycloak, JumpCloud and any other spec-compliant provider are configured as Generic OIDC — you supply the issuer URL and CYPEX discovers the rest. LDAP remains available for directory-backed deployments.

Pages in this section

  1. This page — the conceptual overview: architecture, and how SSO fits alongside local auth and LDAP.
  2. Signing in — the login screen from the user’s side: the organization picker, provider buttons, and what the pending-approval message means.
  3. OIDC setup guide — the hands-on walkthrough: add a provider, sign in, approve the first user, and the JWT claim / RLS trace behind it.
  4. LDAP — directory connection settings, the three role-mapping modes, Active Directory notes, and coexistence with local auth and OIDC.
  5. Pending and rejected users — the full pending/active/rejected state diagram, admin approve/reject/un-reject actions, and the audit trail each transition leaves.

Architecture

flowchart LR
    idp["OIDC provider<br/>Google / Entra / Keycloak / Auth0"]
    dir["LDAP directory"]
    spa["CYPEX frontend"]
    gw["SSO Gateway"]
    be["CYPEX backend"]
    db["PostgreSQL<br/>sso_gateway schema"]
    redis["Redis<br/>PKCE state, pending exchange"]

    spa <-->|"/auth/*, /sso/* — proxied"| gw
    spa <-->|"local and LDAP login"| be
    gw <--> idp
    be <--> dir
    gw <--> redis
    gw <--> db
    be <--> db

The gateway is a separate Node.js/Fastify service, not a module inside the CYPEX backend. It uses its own sso_gateway schema in the same PostgreSQL database, so there is no second database to provision. The frontend never addresses it by port — both /auth/* and /sso/* are proxied from the browser-visible origin (Vite in development, nginx in production) to the gateway.

Redis is a hard dependency, not a cache you can omit: the gateway stores PKCE state across the identity provider round-trip and the single-use code exchange there, and refuses to start without it.

Coexistence with local auth

SSO does not replace local username/password login — it sits next to it. The login page always shows the local form; picking an organization that has an enabled provider reveals an extra sign-in button for that provider, scoped to that organization only:

Login — organization picker

Selecting an organization is what reveals its SSO button — the button is per-organization, not global.

Selecting an organization is what reveals its SSO button — the button is per-organization, not global.

Login — provider button

One organization can have more than one enabled provider; each gets its own button.

One organization can have more than one enabled provider; each gets its own button.

You do not always have to pick an organization first. If you type an email address into the login field and its domain is claimed by exactly one provider, that provider’s button appears without touching the organization picker. Typing a plain username triggers no lookup, so usernames cannot be probed for provider existence.

A user can always fall back to local credentials if they have them. Turning off the Enabled toggle on the provider form hides its button immediately and preserves everything else — the configuration, the linked identities, and any sessions already issued. Sessions are not revoked, so disabling a provider stops new logins rather than ending current ones. Deleting a provider is a different matter: it removes the identity links of every user who signed in through it, and those users must be approved again.

Multi-provider, per-organization

Unlike a single global OIDC config, CYPEX lets one organization enable more than one provider at once — Google for one business unit and Entra for another, both live simultaneously. Give each provider a distinct type or a distinct set of email domains; two enabled providers of the same type in the same organization are ambiguous on the sign-in path, and two providers claiming the same email domain are reported as a misconfiguration rather than guessed at.

Provider rows are RLS-protected and carry an organization_id, but note that the policy admits any organization administrator, not only the one that owns the row — treat provider configuration as an administrator-wide surface. Client secrets are AES-256-GCM encrypted at rest under the deployment’s SSO_KEK key and are never returned by the API or shown again after creation; the form offers rotation instead.

First login has no implicit role

A successful identity provider authentication does not grant CYPEX access. A brand-new SSO identity is always parked as pending, and an administrator must approve it and assign a role before the user can do anything — this holds even when a role mapping rule already matches, because the rule decides which role, not whether to admit. There is no silent default role: if no rule matches at approval time, the sign-in fails closed.

Role mapping rules live in sso_gateway.t_sso_role_mapping and match on the external role or group claim using one of five modes — exact, prefix, suffix, contains, regex. Every group the identity provider asserts is tried first; only if none matches are the role claims tried.

Warning
One provider setting bypasses approval. With auto-link by email enabled, a user whose verified email address already belongs to a CYPEX account in the same organization is linked to that account immediately and signs in without review. The linked account keeps its existing role — no new user is created and no role is granted — but the pending queue is skipped. Leave auto-link off unless you trust the provider’s email_verified assertion.

If the provider has an allowed-domains list, it is checked before any of this. Matching is exact and case-insensitive with no wildcards and no subdomain matching, so example.com does not admit eu.example.com. An address outside the list is refused at sign-in.

See the OIDC setup guide for the first-login walkthrough, and Pending and rejected users for the full state diagram, admin actions, and audit trail.

See also

  • CYPEX Glossary — the one-line SSO, OIDC, and IdP definitions.
  • SSO Providers (admin GUI) — the field-by-field reference for this page’s form, under the enterprise-gated Authentication section of the sidebar.
  • LDAP — the other federated auth path, directory-backed rather than OIDC, including Active Directory notes.
  • Organizations & Row-Level Security — the JWT tenant claim and RLS model every authenticated request rides on, SSO-issued tokens included.
  • What is an Organization? — the JWT claim table this section’s claim mapping reuses verbatim.
  • Users — the Pending SSO / Rejected SSO tabs where approvals happen.
  • Upgrade to CYPEX v2.0.0 — the operator upgrade guide, including what changes for SSO in this release.