Skip to content

Guest identity

Keycloak holds every guest account: passwords, registration, sign-in sessions, and any social or second-factor login FINNS turns on. Every channel that signs guests in (the app, the booking website, future channels) is an OpenID Connect client of the same realm, which is what makes “one FINNS account” true.

Version
Keycloak 26.8
Realm
finns
Hosting
DigitalOcean droplet keycloak-1Docker ComposeCaddy (TLS)Its database lives in the same managed Postgres cluster as core. Operators reach the droplet over Tailscale.
Public URL
test-auth.finnsbeachclub.com/realms/finns
FINNS extension
finns-core event listener (Java jar)
flowchart LR
  classDef ours fill:#13686C,stroke:#0B4A4D,color:#ffffff
  classDef ext fill:#F3ECDF,stroke:#B9A88B,color:#12191B

  app["Guest app<br/>client trident-app"]:::ours
  book["Booking website<br/>client poc-booking"]:::ext
  kc["<b>Keycloak</b><br/>realm finns"]:::ext
  core["Core"]:::ours

  app -- "OIDC code + PKCE" --> kc
  book -- "OIDC code + PKCE,<br/>silent SSO, fresh login" --> kc
  kc -- "back-channel logout" --> book
  kc -- "finns-core listener:<br/>user changed {userId}" --> core
  core -- "client finns-core-sync:<br/>read users (view-users)" --> kc
  core -- "validate JWTs (JWKS)" --> kc
Client Type Notes
trident-app Public, PKCE Core accepts only access tokens with azp=trident-app. Mobile uses offline_access.
poc-booking Public, PKCE Back-channel logout URL set, “session required” on. A real booking vendor gets its own client.
finns-core-sync Confidential, service account only One role: realm-management → view-users. Its secret lives only in core.
Setting Value Effect
SSO session idle / max 30 min / 10 h How long a browser stays signed in (web app, booking site)
Offline session idle ~30 days How long the mobile app stays signed in without use

The finns-core extension listens for user events (registration, login, profile and email changes, account deletion, identity-provider links) and admin changes to users. After Keycloak commits, it sends core only the user’s id; core fetches the user itself with finns-core-sync. Core also reconciles every 10 minutes to catch anything missed. Setup is scripted (setup-realm.py) and described in core/keycloak-extension/manual-keycloak.md.

  • High availability: today one node on one droplet. Keycloak clusters well (Infinispan), but needs its own database sizing and a load balancer.
  • Email delivery: verification and password-reset emails need an SMTP relay.
  • Social login and passwordless: Keycloak supports Google, Apple and WebAuthn natively; the brief’s activation goals argue for the lowest-friction sign-up.
  • Consent and data rights (PDP Law, GDPR): terms acceptance and account deletion flows belong here.

Internal and confidential. Share partner sections only as partner builds (pnpm build:partner).