Keycloak¶
Keycloak works with Workflow in three independent ways: as the OpenID Connect provider people sign in with, as a directory Workflow syncs people and groups from, and as an issuer of access tokens for the API. Nothing in the sign-in code is Keycloak-specific; directory sync uses Keycloak's Admin REST API. The full reference is on the Identity page.
1. Sign-in client¶
In your realm, create an OpenID Connect client:
| Setting | Value |
|---|---|
| Client ID | workflow |
| Client authentication | On (confidential) |
| Authentication flow | Standard flow only |
| PKCE method | S256 |
| Valid redirect URIs | https://<workflow-host>/auth/keycloak/callback |
| Valid post-logout redirect URIs | https://<workflow-host>/login |
| Back-channel logout URL | https://<workflow-host>/auth/keycloak/backchannel-logout |
| Back-channel logout session required | On |
The keycloak in those paths is the provider id you configure in step 5. With back-channel logout, signing out in Keycloak (or an admin ending a session there) ends the Workflow session at once; with single logout on, signing out of Workflow signs out of Keycloak too.
2. Groups in the sign-in token (optional)¶
To bring people's Keycloak groups into Workflow at each sign-in, add a Group Membership mapper to the client's dedicated scope:
| Setting | Value |
|---|---|
| Token claim name | groups |
| Full group path | On or off (a leading / is trimmed either way) |
| Add to ID token | On |
The groups appear under Administration → Groups as keycloak/<group>, where you map them to organisation roles. Realm roles can be read the same way from realm_access.roles once the realm roles mapper also adds them to the ID token (by default they are only in access tokens). If you also turn on directory sync with groups (step 3), the sync provides the groups instead and the claim is ignored.
3. Directory sync (optional)¶
To create accounts before people first sign in, and to deactivate leavers without waiting, give Workflow a second, service-only client:
| Setting | Value |
|---|---|
| Client ID | workflow-sync |
| Client authentication | On |
| Service accounts roles | On; every other flow off |
| Service account roles | realm-management → view-users and query-groups |
Workflow reads the realm through the Admin REST API on a schedule (Keycloak's SCIM support only receives users from elsewhere, so it cannot push them). It only reads:
- people in the access group (and its subgroups) get accounts, matched by their Keycloak user id, then by verified email;
- people disabled in Keycloak or removed from the access group are deactivated, with their sessions and API tokens revoked; people deleted in Keycloak are marked deleted;
- groups whose name starts with the prefix are mirrored with their members, keeping their identity (and role mappings) when renamed or moved.
4. API tokens (optional)¶
So scripts and CI can call Workflow's API with Keycloak tokens instead of personal access tokens, create a client named workflow-api with no flows (it only names the audience), add an Audience mapper for workflow-api to the calling clients, and create client scopes wfm:read, wfm:write and wfm:admin. A client-credentials client listed in API_CLIENTS acts as a Workflow service account; other tokens act as the person who signed in with that subject.
5. Configure Workflow¶
Every setting is an environment variable. In the Helm chart, put plain values in config and secrets in secrets.values (or an existing Secret):
config:
WFM_OIDC_PROVIDERS: keycloak
WFM_OIDC_KEYCLOAK_ISSUER: https://sso.example.com/realms/acme
WFM_OIDC_KEYCLOAK_CLIENT_ID: workflow
WFM_OIDC_KEYCLOAK_DISPLAY_NAME: Keycloak
WFM_ALLOWED_DOMAINS: acme.example
WFM_OIDC_KEYCLOAK_GROUPS_CLAIM: groups # step 2
WFM_OIDC_KEYCLOAK_SINGLE_LOGOUT: "true" # sign out of Keycloak too
WFM_KEYCLOAK_ENABLED: "true" # step 3
WFM_KEYCLOAK_URL: http://keycloak.keycloak.svc:8080
WFM_KEYCLOAK_REALM: acme
WFM_KEYCLOAK_CLIENT_ID: workflow-sync
WFM_KEYCLOAK_PROVIDER: keycloak
WFM_KEYCLOAK_SYNC_GROUP: /workflow-users # who gets an account
WFM_KEYCLOAK_GROUP_PREFIX: wfm- # which groups are mirrored
WFM_OIDC_KEYCLOAK_API_AUDIENCE: workflow-api # step 4
WFM_OIDC_KEYCLOAK_API_CLIENTS: ci-pipeline=ci-bot@service.example
secrets:
values:
WFM_OIDC_KEYCLOAK_CLIENT_SECRET: "<workflow client secret>"
WFM_KEYCLOAK_CLIENT_SECRET: "<workflow-sync client secret>"
WFM_KEYCLOAK_URL may be an in-cluster address; it is set by an administrator, so the outbound guard for user-supplied URLs does not apply. Only one directory (Google Workspace or Keycloak) can sync at a time. Runs, their counts and a Run now button are under Administration → Sign-in & provisioning. See Configuration for every variable.
Testing¶
The app repository's k3d setup (deploy/k3d/keycloak) runs Keycloak 26.4 with a development realm: the sign-in, sync, API and CLI clients above, and test users inside and outside the access group. The CI end-to-end job deploys it, checks that sign-in redirects to Keycloak, and runs a directory sync against it; the sync is also tested against a real Keycloak with an opt-in integration test. See Contributing for its clients and users.