Skip to content

Keycloak setup

Holotable derives all authorization from the groups claim of the session token. Keycloak does not include group memberships in tokens by default — you must add a group-membership mapper.

  1. Create (or reuse) a realm, e.g. holotable.

  2. Create an OpenID Connect client:

    • Client ID: holotable
    • Client authentication: On (confidential) → copy the client secret.
    • Valid redirect URIs: http://localhost:3000/api/auth/callback (add your production origin too).
    • Standard flow: enabled.
  3. Create the groups that encode roles. Group paths must match exactly:

    /workspaces/{workspaceId}/viewer
    /workspaces/{workspaceId}/editor
    /workspaces/{workspaceId}/source-admin
    /platform-admins

    For a workspace acme: create a top-level group workspaces, a child acme, and children viewer / editor / source-admin. Create a separate top-level group platform-admins for global admins, then assign users.

The mapper puts full group paths into a groups claim.

  1. Client → Client scopes → holotable-dedicated → Add mapper → By configuration → Group Membership.
  2. Configure:
    • Name: groups
    • Token Claim Name: groups
    • Full group path: On — produces /workspaces/acme/editor, which is what Holotable parses.
    • Add to ID token: On
    • Add to access token: On
    • Add to userinfo: On
  3. Save.

Set these in .env (see .env.example):

Terminal window
OIDC_ISSUER=http://localhost:8080/realms/holotable
OIDC_CLIENT_ID=holotable
OIDC_CLIENT_SECRET=<client secret>
OIDC_JWKS_URL=http://localhost:8080/realms/holotable/protocol/openid-connect/certs
OIDC_GROUPS_CLAIM=groups
OIDC_SCOPE=openid profile email groups
  • OIDC_JWKS_URL enables RS256 verification of Keycloak-issued tokens.
  • The profile and email scopes put name and email in the id_token. The account menu and Settings → Account display them; they are never used for authorization, and a token without them still signs in.
  • OIDC_ACCOUNT_URL (optional) is linked from Settings → Account so people can manage what Keycloak owns. For Keycloak it is the issuer followed by /account, e.g. http://localhost:8080/realms/holotable/account.
  • The login flow lives at /api/auth/login → Keycloak → /api/auth/callback, which verifies the token and mints a first-party session cookie.

Decode an issued token and confirm it contains:

{
"sub": "…",
"groups": ["/workspaces/acme/editor", "/platform-admins"]
}

If groups is missing or contains bare names rather than paths, revisit step 2. How those paths become roles is described in Authorization model.