Skip to content

Keycloak

Keycloak is the lake’s identity server (OpenID Connect). It checks passwords and issues tokens that carry the person’s role. The web app logs in with it; the API verifies its tokens; JupyterHub uses it for notebook logins. Passwords exist only in Keycloak.

Software /opt/keycloak-<version> with symlink /opt/keycloak (Keycloak 26.x)
Config /etc/lake/keycloak/keycloak.conf, keycloak.env (bootstrap admin)
Service keycloak (step 13), runs kc.sh start --optimized --import-realm
Ports 8180 web and OIDC, 9180 health and metrics (127.0.0.1)
Database PostgreSQL keycloak
Realm chdc, imported from infra/keycloak/realm-chdc.json only on the first start
Item Meaning
Realm roles vendor, analyst, admin
Client chdc-web Public client for the web app. Login with authorization code + PKCE. Redirect http://localhost:5173/* in development
Client chdc-notebook Confidential client for JupyterHub. Created or updated by step 18 on every run (the realm file is only imported once)
Token checks in the API Issuer <keycloak>/realms/chdc, client chdc-web, signature from the realm’s public keys
Terminal window
systemctl is-active keycloak
curl -s http://127.0.0.1:9180/health/ready # {"status":"UP"...}
curl -s http://127.0.0.1:8180/realms/chdc/.well-known/openid-configuration | head -c 200

Through the tunnel: http://localhost:18180/admin. Log in as admin with KEYCLOAK_ADMIN_PASSWORD from cluster.env. Choose the realm chdc (top left), not master.

Task Where
See who exists Users
Reset a password Users > the user > Credentials > Reset password (tick Temporary so they must change it)
Disable a login Users > the user > switch Enabled off
See logins and failures Events (turn on Save events in Realm settings first)
Check a client Clients > chdc-web

Normally you do not create users here. Create vendors and analysts in the web app, which creates the Keycloak user and the matching registry row together and rolls back if either fails. A user made by hand has a login but no registry record: the web app shows an analyst like that as “not registered” and a vendor like that cannot see any data.

node apps/api/scripts/seed-dev-users.js creates dev-vendor, dev-analyst, dev-admin (password DEV_USER_PASSWORD). For development only; never on a production realm.

hostname-strict=false makes the token issuer follow the address the caller used, which is what lets one Keycloak serve both the tunnel (localhost:18180) and the server itself during development. In production set a real hostname and TLS; this setting is for development only.

Build-time options (database, health) are baked in by kc.sh build, which the script runs with the same config file.

Symptom Likely cause
Login redirect is refused Open the app at http://localhost:5173, not 127.0.0.1
Token rejected by the API Issuer mismatch: the token was issued through another address. Use the same address everywhere
Realm changes in the JSON have no effect The import runs only if the realm does not exist; change settings in the console or via a script
Not tested Restart after a server reboot, and production hostname/TLS

The API currently uses the Keycloak master admin password to create users. Replacing it with a realm-limited service account is planned.