Authentication — Keycloak
In Keycloak mode users sign in with a branded password form against your own Keycloak realm. The API validates the realm's tokens. Use this when you self-host identity rather than federating to Entra.
Import the realm
edgentia ships a realm export (deploy/keycloak/real/edgentia-realm.json in the
edgentia-core repo). Import it into your Keycloak (mount it at
/opt/keycloak/data/import with --import-realm, or import via the admin console).
It defines:
- Realm
edgentia, self-registration off. - Clients:
edgentia-frontend— public SPA client (PKCE), no secret. Add your public URL to its redirect URIs (https://edgentia.acme.com/*).edgentia-api— confidential client with a service account holding therealm-managementrolesview-realm,view-users,query-users,manage-users(so the directory picker / invites work). Its secret is what you pass as the admin client secret below.
- Realm roles:
platform-admin,workspace-admin,analyst,operator,viewer. - Token mapper
job_title— surfaces the user's job title on/v1/me.
The export seeds one bootstrap platform-admin owner from the BOOTSTRAP_OWNER_*
values — set these for your install (username, email, name, password). Sign in as
that owner first, then create workspaces and members.
Configuration
| Variable | Required | Notes |
|---|---|---|
Auth__Authority | ✅ | Issuer URL the API uses to fetch metadata + signing keys, e.g. https://kc.acme.com/realms/edgentia. App won't start without it. |
Auth__AdminClientId | ✅ | edgentia-api. |
Auth__AdminClientSecret | ✅ | The edgentia-api client secret — must match the realm. |
Auth__ValidIssuer | optional | Set when the browser-facing issuer differs from Auth__Authority (see below). |
Auth__Audience | optional | Leave empty to validate by issuer only. |
Auth__RequireHttpsMetadata | optional (true) | false only if the metadata endpoint is plain HTTP. |
Helm: auth.mode=keycloak, auth.keycloak.authority,
auth.keycloak.adminClientSecret, auth.keycloak.validIssuer. Compose:
KEYCLOAK_AUTHORITY, KEYCLOAK_ADMIN_CLIENT_SECRET.
The browser-vs-internal issuer split
Keycloak is often reachable at one hostname from the API (an in-cluster service,
used for metadata + signing keys) and another from the browser (the public URL,
which the token's iss reflects). When they differ:
Auth__Authority→ the internal URL (keys/metadata), e.g.http://keycloak:8080/realms/edgentia.Auth__ValidIssuer→ the browser-facing URL (theissto validate), e.g.https://edgentia.acme.com/auth/realms/edgentia.
The API fetches keys from Authority but validates the issuer against
ValidIssuer. The SPA derives its Keycloak URL from ValidIssuer. Keycloak should
trust your proxy's X-Forwarded-* headers (KC_PROXY_HEADERS=xforwarded) so it
emits the correct public issuer.
User management
Keycloak supports up to management level 2 (in-app invites + directory). The
edgentia-api service account reads the realm directory; without its client secret
the "add member" picker degrades to adding members by id.