- Microsoft Entra ID (formerly Azure AD)
- Keycloak
ALETYX_OIDC_PROVIDER; defaults to entra. Only one provider is active per Tower instance.
Required claims, scopes, and roles
Regardless of provider, Tower expects the following from the issued ID/access token:Scopes
Configurable via
ALETYX_OIDC_SCOPES as a comma-separated list. The default is openid,profile,email and meets the minimum required set.
Role claim
Tower reads roles from a single configurable claim path in the token. The default path isroles (top-level claim). Override with ALETYX_OIDC_ROLE_CLAIM_PATH if your provider emits roles under a different path (e.g. realm_access.roles for Keycloak realm roles, resource_access.<client>.roles for Keycloak client roles).
Tower recognizes the following role values for authorization decisions:
Users without any of these role values can authenticate but cannot perform meaningful operations in the UI; the app shows an informational screen explaining the missing role.
You may map your organization’s identity-provider roles or groups to these values via the provider’s claim transformation features (see provider-specific sections below).
Microsoft Entra ID
Prerequisites
- An Entra tenant with permissions to create app registrations
- A user account allowed to grant tenant-wide admin consent
App registration steps
-
Register the application
- Azure Portal → Microsoft Entra ID → App registrations → New registration
- Name: e.g.
Decision Control Tower — <env> - Supported account types: Accounts in this organizational directory only (single tenant)
- Redirect URI: select Web and enter
https://<tower-host>/auth/callback - Click Register
-
Record the identifiers
- From the Overview page, note the Application (client) ID and Directory (tenant) ID. These map to
ALETYX_OIDC_CLIENT_IDandALETYX_OIDC_ENTRA_TENANT_IDrespectively.
- From the Overview page, note the Application (client) ID and Directory (tenant) ID. These map to
-
Configure additional redirect URIs (optional)
- Authentication → Web → Add URI: include any additional environments (
http://localhost:8080/auth/callbackfor local dev, additional cluster hostnames, etc.) - Front-channel logout URL (optional):
https://<tower-host>/auth/logout
- Authentication → Web → Add URI: include any additional environments (
-
Generate a client secret
- Certificates & secrets → Client secrets → New client secret
- Provide a description and expiry (24 months is a common default)
- Copy the
Valueimmediately — Azure displays it only once - Store the value securely; it maps to
ALETYX_OIDC_ENTRA_CLIENT_SECRET
-
Grant API permissions
- API permissions → Add a permission → Microsoft Graph → Delegated permissions
- Add:
openid,profile,email,User.Read - Click Grant admin consent for
<tenant>
-
Define app roles
-
App roles → Create app role, repeating for each role:
-
App roles → Create app role, repeating for each role:
-
Assign users to roles
- Azure Portal → Microsoft Entra ID → Enterprise applications → select the application → Users and groups → Add user/group
- Choose users or groups and the corresponding role.
- Group-based assignment requires Microsoft Entra ID P1 or higher; Free tenants must assign individual users.
-
(Optional) Surface group claims
If you prefer to drive Tower’s authorization from existing security groups rather than per-app role assignments, configure the app’s token to include the
groupsclaim and set:Note that Tower compares claim values literally to the role names listed above, so the group display names (or claim mapping) must produce one ofuser,tower-approvers.
Required configuration variables — Entra
Example — environment file
Verifying the configuration
After deploying the application, the OIDC discovery document for Entra ID is available at:/auth/callback. If you need to verify role claims, decode the bearer token with a JWT debugger you trust.
Keycloak
Prerequisites
- A Keycloak realm in which to create the client. Tower targets Keycloak 22+ (which uses the OpenID Connect Authorization Code Flow by default).
- An admin user able to create clients, roles and group mappings in the realm.
Realm and client setup
-
Create or select a realm
- Keycloak admin console → top-left realm selector → Create Realm if needed
- Common naming:
aletyx,tower, or your organization’s realm name
-
Create the client
- Clients → Create client
- Client type: OpenID Connect
- Client ID: e.g.
decision-control-tower - Click Next:
- Client authentication: ON (this is a confidential client)
- Standard flow: ON
- Direct access grants: OFF
- Service accounts roles: OFF
- Valid redirect URIs:
https://<tower-host>/auth/callback(addhttp://localhost:8080/auth/callbackfor local dev runs) - Web origins:
https://<tower-host> - Front-channel logout URL:
https://<tower-host>/auth/logout(optional) - Click Save
-
Capture the client secret
- Open the client → Credentials tab
- Note the Client Secret value; store securely. The client ID maps to
ALETYX_OIDC_KEYCLOAK_CLIENT_IDand the secret to its own dedicated variableALETYX_OIDC_KEYCLOAK_CLIENT_SECRET(the shared OIDC starter decouples the Entra and Keycloak secrets — they are no longer the same variable).
-
Define realm or client roles
- Roles tab on the client (recommended) → Create role for each:
usertower-approvers
- Or define them as realm roles if you already have an existing role taxonomy. Adjust
ALETYX_OIDC_ROLE_CLAIM_PATHaccordingly (see the next step).
- Roles tab on the client (recommended) → Create role for each:
-
Map roles into the token
- Client scopes → select the client → Mappers → Add mapper → By configuration → User Realm Role (for realm roles) or User Client Role (for client roles)
- Token Claim Name:
roles(top level) — leave the default- or
realm_access.rolesfor realm roles emitted under the standard Keycloak structure
- Add to ID token / access token: ON
ALETYX_OIDC_ROLE_CLAIM_PATHto the same path you used here. -
Assign roles to users or groups
- Users → select user → Role mapping → Assign role → choose
userortower-approvers - For group-based assignment: Groups → create a group → Role mapping → assign roles to the group, then add users to the group.
- Users → select user → Role mapping → Assign role → choose
Required configuration variables — Keycloak
Example — environment file
Discovery and verification
The OIDC discovery document for Keycloak is available at:issuer, authorization_endpoint, token_endpoint, jwks_uri, etc. Tower fetches this on first authentication and caches the result.
Additional OIDC settings (shared starter)
As of the unifiedaletyx-oidc-spring-boot-starter, the settings below apply to both Decision Control and Decision Control Tower, and to both providers. They have safe defaults — override only when needed.
Tenant resolution
Server-to-server secrets
Token-client timeouts
Dev identity (provider=none)
Only used when ALETYX_OIDC_PROVIDER=none. The shared starter installs a synthetic authenticated principal from these values so local/dev runs behave like a real OIDC session (audit trail, RBAC checks, tenant resolution all see a real user). Ignored in entra / keycloak mode, where the identity comes from the JWT.
URL-level RBAC (optional)
Disabled by default. When enabled, every request must carry a role from the per-action allow-lists below. An empty list locks everyone out of that action, so populate all of them when you turn RBAC on.
Example (Entra, RBAC on):
Common pitfalls
-
Redirect URI mismatch (
AADSTS50011for Entra,Invalid redirect URIfor Keycloak): the redirect URI in the auth request must exactly match a URI registered in the provider. Common cause: changing the application hostname without updating the registration. Always include the trailing path/auth/callback. -
Roles missing from the token: confirm the user actually has the role assignment, that the role is mapped into the token via a claim mapper (Keycloak) or app role assignment (Entra), and that
ALETYX_OIDC_ROLE_CLAIM_PATHmatches the path in the token. -
Browser redirect loop on
/auth/callback: usually indicates a clock skew between the Tower host and the OIDC provider. Verify NTP is configured. -
Refresh token collisions across environments: Microsoft Entra rotates refresh tokens per
(user × app registration). Two parallel sessions for the same user with the same app registration cause one of them to be invalidated. Either deploy distinct app registrations per environment, or have each user sign in with a per-environment identity. The trade-offs of each approach are environment-specific. -
Disabling authentication for diagnostics: set
ALETYX_OIDC_PROVIDER=none. The shared starter installs a synthetic principal so audit, RBAC, and tenant resolution still see a real user. Intended for local diagnostics only; never use in production.