Single Sign-On (Keycloak)
VeroXM can authenticate dashboard users through Keycloak, an open-source identity provider, as a second login option alongside the built-in email/password login — additive, not a replacement. With Keycloak unconfigured, nothing changes: there's no "Sign in with Keycloak" button and every existing account keeps logging in exactly as it always has.
A real, working integration — with a deliberately scoped surface
This is genuinely wired up (session login, identity matching, and role sync all work end to end), but it's scoped to those three things. It doesn't yet gate VeroXM's own API routes directly, provision brand-new accounts, or sync group membership beyond the two admin-tier roles described below — see "What this doesn't do yet" at the bottom of this page.
Enabling it
Keycloak login is controlled entirely by environment variables — set them and it appears; leave any unset and it doesn't.
NEXT_PUBLIC_KEYCLOAK_ENABLED="true"
KEYCLOAK_CLIENT_ID="mycms-web"
KEYCLOAK_CLIENT_SECRET="..."
KEYCLOAK_ISSUER_EXTERNAL="https://your-keycloak.example.com/realms/your-realm"
KEYCLOAK_ISSUER_INTERNAL="http://keycloak:8080/realms/your-realm"KEYCLOAK_ISSUER_INTERNAL="http://keycloak:8080/realms/your-realm"
KEYCLOAK_ISSUER_EXTERNAL="https://your-keycloak.example.com/realms/your-realm"The internal/external split exists because a browser and the VeroXM server reach Keycloak differently: the browser is redirected to the external URL for the actual sign-in screen, while the server's own token exchange and JWKS verification call Keycloak on the internal network address (container-to-container in a typical deployment). Both must point at the same realm.
How identity resolves
A Keycloak profile has no meaning to VeroXM's own user records on its own — Keycloak identifies a person by an internal UUID (sub), not the numeric id VeroXM's authorization tables use. On a successful Keycloak sign-in, VeroXM resolves the real account by matching the email on the Keycloak profile to an existing VeroXM user.
If no VeroXM account has that email, sign-in still "succeeds" at the identity-provider level, but the resulting session can't reach any role-gated dashboard screen — VeroXM never fabricates an account or grants default access just because Keycloak vouched for an email address.
Syncing admin roles from Keycloak
Beyond identity, a Keycloak token can also carry realm roles named department_admin{id} or tenant_admin{id} — the exact same naming Department Admin and Tenant Admin grants already use internally. On every Keycloak login, VeroXM reads those role names out of the token and writes the matching grant into the same table the rest of the platform already reads — so a Department Admin role assigned in Keycloak takes effect the next time that person signs in, with no separate step in VeroXM's own admin UI.
Additive only — Keycloak can grant, it can't revoke
This sync only ever adds a role grant, never removes one. Taking a realm role away in Keycloak does not by itself revoke that person's Department Admin or Tenant Admin access in VeroXM — remove the grant from the Department or Tenant page (the same place you'd revoke a role granted directly) as well. Keycloak and VeroXM's own admin UI are two independent ways to grant the same role, both landing in the same place, both visible and revocable from the same panels.
Advanced use case: centralizing admin roles in your real identity provider
Keycloak is itself a federation layer — it can sit in front of an organization's actual identity provider (an LDAP/Active Directory directory, a SAML IdP, or an upstream OIDC provider) rather than managing users on its own. For an enterprise customer that already manages "who's an admin" centrally, that means Department Admin and Tenant Admin access in VeroXM can follow the organization's real source of truth — a group membership change upstream flows through Keycloak as a realm role, and takes effect in VeroXM automatically on that person's next login — instead of an operator maintaining the same grants by hand in two places.
Verifying a token directly (API-level)
Separately from the dashboard login flow above, VeroXM includes a standalone guard that verifies a Keycloak-issued access token directly against the realm's JWKS endpoint (RS256), for a caller presenting a bearer token rather than going through NextAuth's session cookie. Today it backs exactly one endpoint, a diagnostic "whoami" route that echoes back the token's verified claims — useful for confirming a realm and client are configured correctly end to end before building anything real on top of it.
GET /auth/keycloak-whoami
Authorization: Bearer <keycloak access token>
→ { "claims": { "sub": "...", "email": "...", "realm_access": { "roles": [...] }, ... } }What this doesn't do yet
- It doesn't gate any of VeroXM's real dashboard-session or Content API routes on a Keycloak token directly — those still authenticate through VeroXM's own session/API tokens; the JWKS-verifying guard above backs only the whoami diagnostic route.
- It doesn't create new VeroXM accounts — a person needs an existing VeroXM user with a matching email before Keycloak login can resolve to anyone.
- It doesn't sync group membership or role kinds beyond Department Admin and Tenant Admin — a custom role is still assigned from within VeroXM.