Connect Camunda to any OIDC provider
This guide shows you how to configure Camunda 8 Self-Managed to authenticate with any OpenID connect (OIDC)-compliant identity provider.
Earlier releases bundled PostgreSQL through Bitnami subcharts (identityPostgresql, webModelerPostgresql). As of Camunda 8.10 (Helm chart 15.x), the bundled Bitnami subcharts are removed: provide PostgreSQL with the CloudNativePG operator or a managed database, as shown in the examples below.
Before proceeding, since this is a general guide, refer to External OIDC provider to see the available provider-specific guides, as they include detailed setup instructions tailored to provider's interface.
Prerequisites
Before you begin, ensure you have:
- An OIDC-compliant provider already deployed and accessible.
- Administrative access to create and configure OIDC clients in your provider.
- Access to your provider's discovery document to obtain endpoint URLs.
- A Kubernetes cluster with a supported Helm CLI version installed.
- kubectl configured to access your cluster.
- When you connect Management Identity to an OIDC provider, you need a database regardless of feature flags. Chart
15.xno longer bundles one, so provision it with the CloudNativePG operator or a managed database and connect it throughidentity.externalDatabase, as shown in the examples below. See also use external PostgreSQL.
This guide assumes your OIDC provider is already operational. It does not cover provider installation or basic OIDC configuration.
If your provider presents a certificate signed by a private or internal certificate authority (common with Entra hybrid setups, Okta on-premises, or an internal Keycloak), Camunda components won't trust it by default. Configure TLS trust to avoid PKIX path building failed errors when components connect to the issuer.
Create OIDC clients
Create the following OIDC clients in your provider. The exact process varies by provider; consult your provider's documentation for client creation procedures.
| Client name | Type | Purpose |
|---|---|---|
| Management Identity | Confidential | User login and API authentication |
| Orchestration Cluster | Confidential | User login and machine-to-machine authentication |
| Optimize | Confidential | User login |
| Web Modeler API | Confidential | Programmatic API access |
| Web Modeler UI | Public | User login |
| Console | Public | User login |
For each client, record:
- Client ID
- Client secret (for confidential clients only)
Assign a unique audience to each component
Camunda components can trust tokens from the same OIDC issuer while using the aud claim to identify the intended resource. Each component validates this claim against its configured audience and accepts any token that carries it.
Management Identity controls access to Camunda Hub and Optimize. The Orchestration Cluster manages its own roles and authorizations through Admin. Both subsystems can use the same OIDC provider, but their authorization checks remain independent.
Decide a distinct audience for each component before you configure Helm, then configure your provider to issue it.
| Component | Helm value | Chart default |
|---|---|---|
| Management Identity | global.identity.auth.identity.audience | camunda-identity-resource-server |
| Orchestration Cluster | orchestration.security.authentication.oidc.audience | orchestration-api |
| Optimize | global.identity.auth.optimize.audience | optimize-api |
| Web Modeler client API | global.identity.auth.webModeler.clientApiAudience | web-modeler-api |
| Web Modeler public API | global.identity.auth.webModeler.publicApiAudience | web-modeler-public-api |
| Connectors | Inherits the Orchestration Cluster audience | orchestration-api |
If two components accept the same audience, a token intended for one can also pass the other's audience validation. Keep the resource audiences in this table distinct unless a supported integration requires one component to accept another's token.
Do not derive these values by inspecting whatever token your provider returns by default. If several components are registered against one client or API identifier, inspection returns the same aud for all of them, so configuring what you find reproduces the collision instead of revealing it. Decide the values first, then use token inspection to confirm your provider issues them.
The following integrations intentionally cross this audience boundary:
- Connectors calls the Orchestration Cluster as a client and uses the Orchestration Cluster's audience. See Configure Connectors.
- Camunda Hub deployments that use
BEARER_TOKENauthentication forward the user's Hub token to the Orchestration Cluster. Configure the cluster to accept the Camunda Hub UI audience in addition to its own audience. See connect Admin to an identity provider.
Configure redirect URIs
For each OIDC client you have created, configure the redirect URIs that correspond to where Camunda components will be accessible from users' browsers.
Redirect URI table
| Component | Redirect URI pattern | Example (localhost) | Example (Ingress) |
|---|---|---|---|
| Management Identity | <IDENTITY_URL>/auth/login-callback | http://localhost:8084/auth/login-callback | https://camunda.example.com/identity/auth/login-callback |
| Orchestration Cluster | <OC_URL>/sso-callback | http://localhost:8080/sso-callback | https://camunda.example.com/orchestration/sso-callback |
| Optimize | <OPTIMIZE_URL>/api/authentication/callback | http://localhost:8083/api/authentication/callback | https://camunda.example.com/optimize/api/authentication/callback |
| Web Modeler UI | <WEB_MODELER_URL>/login-callback | http://localhost:8070/login-callback | https://camunda.example.com/modeler/login-callback |
| Console | <CONSOLE_URL>/ | http://localhost:8087/ | https://camunda.example.com/ |
Replace <*_URL> with the actual base URL where each component will be accessible. Use the localhost examples if testing locally with port forwarding, or the Ingress examples if exposing components via Ingress.
Redirect URIs are security-critical. Only the URIs you configure in your OIDC provider are permitted as redirection targets after authentication. Ensure these values match the redirectUrl parameters you'll set in the Helm configuration.
Some OIDC providers support wildcard redirect URIs (e.g., https://camunda.example.com/*). Check your provider's documentation to see if this can simplify your configuration.
Discover provider configuration
Since OIDC providers vary in their implementation details, you need to obtain the specific values from your provider.
Find OIDC endpoints
Most OIDC providers expose a discovery document at:
https://your-provider.example.com/.well-known/openid-configuration
Access this URL (replacing your-provider.example.com with your provider's domain) to retrieve a JSON document containing endpoint URLs.
Example discovery document
{
"issuer": "https://your-provider.example.com",
"authorization_endpoint": "https://your-provider.example.com/oauth/authorize",
"token_endpoint": "https://your-provider.example.com/oauth/token",
"jwks_uri": "https://your-provider.example.com/.well-known/jwks.json",
...
}
Record these values for Helm configuration
issuer→ Used for:publicIssuerUrlauthorization_endpoint→ Used for:authUrltoken_endpoint→ Used for:tokenUrljwks_uri→ Used for:jwksUrl
Identify token claims
Camunda needs to know which claims in access tokens identify users and clients. Claim names vary by provider.
You need to identify:
- User identification claim (
usernameClaim): Identifies users during web login (for example,email,preferred_username). - Client identification claim (
clientIdClaim): Identifies calling applications for M2M authentication (for example,client_id,azp). - Audience claim (
audience): The expectedaudvalue in tokens.
For detailed instructions on obtaining and decoding tokens to identify these claims, see JWT token claims reference.
Scopes requested by Camunda
Camunda components request OIDC scopes when authenticating users. The default scopes vary by component:
| Scope | Description | Management Identity, Optimize, Web Modeler, Console | Orchestration Cluster applications (Identity, Operate, Tasklist) |
|---|---|---|---|
openid | Required for OIDC authentication. | ✔ | ✔ |
profile | Access to user profile information. | ✔ | ✔ |
email | Access to user email address. | ✔ | |
offline_access | Enables refresh token issuance. | ✔ |
If your provider supports the offline_access scope, components will receive refresh tokens. This allows sessions to remain active longer without requiring users to re-authenticate.
If offline_access is not available or not granted, users will be redirected to your OIDC provider for re-authentication when their access token expires.
For more information, see OpenID Connect Core specification.
Handle separate access token and ID token signing keys
Most OIDC providers sign access tokens and ID tokens with the same key, published at the single jwks_uri in the discovery document. Some enterprise identity provider deployments sign access tokens with a different key than ID tokens. Camunda validates access tokens on every API request and ID tokens only during the login callback, so if you configure only the discovery document's jwksUrl, access token validation fails even though login succeeds.
To check whether this applies to your provider, compare the jwks_uri in the discovery document against the JWKS endpoint listed for access tokens (or API and runtime tokens) in your provider's admin console. If both are the same URL, skip this section.
If the URLs differ, configure both endpoints:
-
Set
global.identity.auth.jwksUrlto the access token JWKS endpoint. Management Identity validates access tokens using this single URL only, and doesn't call the userinfo endpoint or fall back to any other source. -
Add the same URL as an additional JWKS source for the Orchestration Cluster, which otherwise fetches only the primary JWKS from the discovery document:
orchestration:
env:
- name: CAMUNDA_SECURITY_AUTHENTICATION_OIDC_ADDITIONALJWKSETURIS_0_
value: "<access-token-jwks-url>"This setting has no dedicated Helm value. It maps to the Spring Boot list property
camunda.security.authentication.oidc.additionalJwkSetUris, set throughorchestration.envusing Spring's relaxed-binding convention for list properties: one environment variable per index, with the index surrounded by underscores (..._0_,..._1_, and so on).
The Orchestration Cluster merges keys from the primary JWKS endpoint and all additional endpoints, then selects whichever key matches the kid in the incoming token. Both ID tokens and access tokens then validate correctly, regardless of which key set signed them.
Create secrets
Create a secret in your Kubernetes namespace that contains all OIDC client secrets:
kubectl create secret generic oidc-credentials \
--from-literal=identity-client-secret="<identity-client-secret>" \
--from-literal=orchestration-client-secret="<orchestration-client-secret>" \
--from-literal=optimize-client-secret="<optimize-client-secret>" \
--from-literal=webmodeler-api-client-secret="<web-modeler-api-client-secret>"
The secret key webmodeler-api-client-secret is not used elsewhere in this guide. This client is intended for your own use if you want to access the Web Modeler API programmatically.
The PostgreSQL credentials for Management Identity and Camunda Hub are no longer created here. They are provided by the operator (or managed database) that hosts each database, such as the pg-identity-secret and pg-hub-secret created by the CloudNativePG operator.
For production deployments, consider using external secret management solutions. See External Kubernetes secrets for more options.
Configure Camunda components
Configure Camunda components to use your OIDC provider through Helm values.
Global OIDC configuration
Start with the global configuration that applies to all components:
global:
security:
authentication:
method: oidc
identity:
auth:
enabled: true
type: "GENERIC"
publicIssuerUrl: <issuer-url>
issuerBackendUrl: <issuer-url>
authUrl: <authorization-endpoint-url>
tokenUrl: <token-endpoint-url>
jwksUrl: <jwks-endpoint-url>
Parameter descriptions
| Parameter | Description | Example |
|---|---|---|
publicIssuerUrl | Issuer URL accessible from users' browsers | https://login.example.com |
issuerBackendUrl | Issuer URL accessible from Kubernetes pods | https://login.example.com or http://oidc-internal.svc.cluster.local |
authUrl | Authorization endpoint (must be accessible from browsers) | https://login.example.com/oauth/authorize |
tokenUrl | Token endpoint (must be accessible from pods) | https://login.example.com/oauth/token |
jwksUrl | JWKS endpoint for token signature verification | https://login.example.com/.well-known/jwks.json |
For generic OIDC providers, the Issuer URL must be accessible from both:
- Users' browsers: To redirect users to the login page.
- Camunda components (backend): To fetch the provider's configuration and validate tokens.
Split-horizon DNS setups (where the provider has different URLs for internal and external access) are not supported for generic OIDC providers. Ensure your OIDC provider is exposed via a URL that is resolvable and reachable from both locations.
Configure Management Identity
Add configuration for Management Identity:
global:
identity:
auth:
identity:
clientId: <identity-client-id>
audience: <identity-audience>
secret:
existingSecret: oidc-credentials
existingSecretKey: identity-client-secret
initialClaimName: <user-claim-name>
initialClaimValue: <admin-user-claim-value>
identity:
fullURL: <identity-base-url>
enabled: true
externalDatabase:
enabled: true
host: pg-identity-rw
port: 5432
database: identity
username: identity
secret:
existingSecret: pg-identity-secret
existingSecretKey: password
Management Identity requires an externally managed PostgreSQL database. Provision the database before you deploy, and adapt the connection values and secret references to your setup. For the full parameter list, see Use external PostgreSQL.
Identity-specific parameters
| Parameter | Description | How to Determine |
|---|---|---|
clientId | Client ID from your OIDC provider | From your Identity client configuration |
audience | Expected audience in access tokens | The unique value you assigned in Assign a unique audience to each component |
initialClaimName | Claim that identifies the initial admin user | email, sub, or another user claim from token inspection |
initialClaimValue | Value granting initial admin access | Your admin user's value for the specified claim (e.g., admin@example.com) |
The initialClaimName and initialClaimValue parameters are used only during the first startup to grant initial admin access. Once Management Identity has started, these values are stored in the database and cannot be changed via Helm values.
Configure Orchestration Cluster
Add configuration for the Orchestration Cluster (Zeebe, Operate, Tasklist, Identity):
orchestration:
enabled: true
security:
authentication:
method: oidc
oidc:
clientId: <orchestration-client-id>
audience: <orchestration-audience>
redirectUrl: <orchestration-base-url>
secret:
existingSecret: oidc-credentials
existingSecretKey: orchestration-client-secret
# Claim mapping - uncomment and adjust if your provider doesn't use defaults
# usernameClaim: <user-claim-name> # Default: preferred_username
# clientIdClaim: <client-claim-name> # Default: client_id
authorizations:
enabled: true
initialization:
defaultRoles:
admin:
users:
- <admin-user-claim-value>
connectors:
clients:
- <orchestration-client-id>
Orchestration-specific parameters
| Parameter | Description | Value |
|---|---|---|
clientId | Orchestration client ID | From your provider |
audience | Expected audience in tokens | The unique value you assigned in Assign a unique audience to each component |
redirectUrl | Full URL for Orchestration Cluster | http://localhost:8080 (local) or https://your-domain.com/orchestration (Ingress) |
usernameClaim | Claim identifying users | Default: preferred_username. Override if your provider uses email, sub, or another claim |
clientIdClaim | Claim identifying clients | Default: client_id. Override if your provider uses azp or another claim |
In Helm deployments, the default OIDC username claim is preferred_username, which often maps to an email address.
If you want Web Modeler to display usernames based on a different claim (for example name), set CAMUNDA_IDENTITY_USERNAMECLAIM=name for the Web Modeler restapi environment.
For available Web Modeler environment variables, see Identity/Keycloak configuration.
Default roles
admin.users: List of user claim values that should have admin access.connectors.clients: List of client IDs that should have Connectors role (typically the orchestration client ID itself).
The admin user specified in defaultRoles.admin.users should match the value used for initialClaimValue in Management Identity configuration, so that the same user has admin access to both Management Identity and the Orchestration Cluster.
Configure Connectors
Add configuration for Connectors:
connectors:
enabled: true
security:
authentication:
method: oidc
oidc:
clientId: <orchestration-client-id>
audience: <orchestration-audience>
secret:
existingSecret: oidc-credentials
existingSecretKey: orchestration-client-secret
Connectors calls the Orchestration Cluster as a client, so it deliberately reuses the Orchestration Cluster's OIDC client and audience. This is a scoped exception to the unique audience guidance. If you prefer a separate OIDC client for Connectors, you must also configure the Orchestration Cluster to accept that client's audience.
Configure Optimize
Add configuration for Optimize:
global:
identity:
auth:
optimize:
clientId: <optimize-client-id>
audience: <optimize-audience>
redirectUrl: <optimize-base-url>
secret:
existingSecret: oidc-credentials
existingSecretKey: optimize-client-secret
optimize:
enabled: true
Optimize parameters
| Parameter | Value |
|---|---|
clientId | Optimize client ID from your provider |
audience | The unique value you assigned in Assign a unique audience to each component |
redirectUrl | http://localhost:8083 (local) or https://your-domain.com/optimize (Ingress) |
Configure Web Modeler
Web Modeler requires two OIDC clients: one for the UI (public) and one for the API (confidential).
If your IdP provides user-friendly names in the name claim, and you want Web Modeler to use that claim, configure the Web Modeler restapi environment variable CAMUNDA_IDENTITY_USERNAMECLAIM=name. Without this override, Helm defaults typically resolve usernames from preferred_username.
global:
identity:
auth:
webModeler:
clientId: <web-modeler-ui-client-id>
redirectUrl: <web-modeler-base-url>
clientApiAudience: <web-modeler-ui-audience>
publicApiAudience: <web-modeler-api-audience>
camundaHub:
enabled: true # Deploys both Console and Web Modeler
restapi:
mail:
fromAddress: noreply@example.com # Update with your email address
# Additional SMTP configuration may be required - see Web Modeler docs
externalDatabase:
host: pg-hub-rw
port: 5432
database: hub
username: hub
secret:
existingSecret: pg-hub-secret
existingSecretKey: password
Web Modeler parameters
| Parameter | Description | Value |
|---|---|---|
clientId | Web Modeler UI client ID (public client) | From your provider |
redirectUrl | Full URL for Web Modeler | http://localhost:8070 (local) or https://your-domain.com/modeler (Ingress) |
clientApiAudience | Audience for UI-to-API communication | A unique value for the Web Modeler client API. Must differ from every other component's audience. |
publicApiAudience | Audience for external API access | The API client ID or custom audience |
Email configuration
Web Modeler requires email configuration for notifications. Update restapi.mail.fromAddress with an appropriate sender address.
For full SMTP configuration, see Web Modeler configuration.
Configure Console
Add configuration for Console:
global:
identity:
auth:
console:
clientId: <console-client-id>
audience: <console-audience>
redirectUrl: <console-base-url>
Console is deployed as part of Camunda Hub, which you enable with camundaHub.enabled: true in the Web Modeler step. Replace <console-base-url> with the base URL where Console will be accessible. For local deployment, use http://localhost:8087.
Complete configuration example
Below is a complete Helm values file with all components configured:
global:
security:
authentication:
method: oidc
identity:
auth:
enabled: true
type: "GENERIC"
# OIDC Provider Endpoints
publicIssuerUrl: <issuer-url>
issuerBackendUrl: <issuer-url>
authUrl: <authorization-endpoint-url>
tokenUrl: <token-endpoint-url>
jwksUrl: <jwks-endpoint-url>
# Management Identity
identity:
clientId: <identity-client-id>
audience: <identity-audience>
secret:
existingSecret: oidc-credentials
existingSecretKey: identity-client-secret
initialClaimName: <user-claim-name>
initialClaimValue: <admin-user-claim-value>
# Optimize
optimize:
clientId: <optimize-client-id>
audience: <optimize-audience>
redirectUrl: <optimize-url>
secret:
existingSecret: oidc-credentials
existingSecretKey: optimize-client-secret
# Web Modeler
webModeler:
clientId: <web-modeler-ui-client-id>
redirectUrl: <web-modeler-url>
clientApiAudience: <web-modeler-ui-audience>
publicApiAudience: <web-modeler-api-audience>
# Console
console:
clientId: <console-client-id>
audience: <console-audience>
redirectUrl: <console-url>
# Orchestration Cluster
orchestration:
enabled: true
security:
authentication:
method: oidc
oidc:
clientId: <orchestration-client-id>
audience: <orchestration-audience>
redirectUrl: <orchestration-url>
secret:
existingSecret: oidc-credentials
existingSecretKey: orchestration-client-secret
# The following claim mappings use Camunda defaults and usually don't need to be changed.
# Only uncomment if your decoded access token uses different claim names:
# usernameClaim: email # Use if tokens identify users with 'email' instead of 'preferred_username'
# clientIdClaim: azp # Use if tokens identify clients with 'azp' instead of 'client_id'
authorizations:
enabled: true
initialization:
defaultRoles:
admin:
users:
- <admin-user-claim-value>
connectors:
clients:
- <orchestration-client-id>
# Connectors
connectors:
enabled: true
security:
authentication:
method: oidc
oidc:
clientId: <orchestration-client-id>
audience: <orchestration-audience>
secret:
existingSecret: oidc-credentials
existingSecretKey: orchestration-client-secret
# Management Identity
identity:
fullURL: <identity-base-url>
enabled: true
externalDatabase:
enabled: true
host: pg-identity-rw
port: 5432
database: identity
username: identity
secret:
existingSecret: pg-identity-secret
existingSecretKey: password
# Optimize
optimize:
enabled: true
# Console and Web Modeler (Camunda Hub)
camundaHub:
enabled: true # Deploys both Console and Web Modeler
restapi:
mail:
fromAddress: <your-email-address>
externalDatabase:
host: pg-hub-rw
port: 5432
database: hub
username: hub
secret:
existingSecret: pg-hub-secret
existingSecretKey: password
Placeholders to replace:
| Placeholder | Replace with |
|---|---|
https://your-provider.example.com | Your OIDC provider's issuer URL |
identity, orchestration, optimize, etc. | Your actual client IDs |
identity, orchestration, optimize (audience values) | The unique audience you assigned to each component |
admin@example.com | Your admin user's claim value |
Verify before deploying
- All
<placeholders>replaced with actual values. - All client secrets stored in the
oidc-credentialssecret. - Database credentials provided by the operator-managed database secrets (for example,
pg-identity-secretandpg-hub-secret). - Redirect URIs in OIDC provider match
redirectUrlvalues. - Each component has a distinct resource audience by default. Any cross-component audience acceptance supports a documented integration.
- Verify tokens contain
preferred_usernameandclient_idclaims, or uncomment and configure alternative claim names.
Connect to the cluster
After deploying Camunda with this configuration, use the following kubectl port-forward commands to access the APIs and UIs:
# Management Identity
kubectl port-forward svc/camunda-identity 8084:80
# Orchestration Cluster (Operate/Tasklist)
kubectl port-forward svc/camunda-zeebe-gateway 8080:8080
# Zeebe Gateway (gRPC for clients)
kubectl port-forward svc/camunda-zeebe-gateway 26500:26500
# Optimize
kubectl port-forward svc/camunda-optimize 8083:80
# Web Modeler
kubectl port-forward svc/camunda-web-modeler-restapi 8070:80
kubectl port-forward svc/camunda-web-modeler-websockets 8085:80
# Console
kubectl port-forward svc/camunda-console 8087:80
Once port forwarding is active, access each component through http://localhost:<port>.
For example, Management Identity at http://localhost:8084 or the Orchestration Cluster at http://localhost:8080 (which redirects to your OIDC provider for login).
Ensure your redirect URIs in your OIDC provider match how you're accessing Camunda. If you configured redirect URIs for localhost testing (e.g., http://localhost:8080/sso-callback), the port-forward commands above will work. If you configured redirect URIs for Ingress (e.g., https://camunda.example.com/orchestration/sso-callback), you'll need to access via Ingress instead.
For production deployments, configure Ingress to expose components. See Ingress configuration for more details.
Grant access to components
After deployment, you must configure access for the following components.
To grant a user access to the Web Modeler UI:
- Create a mapping rule in Management Identity for the
Web Modelerrole that matches the user's access token.
To grant a client access to the Web Modeler API:
- Create a role in Management Identity for the Web Modeler API.
- Assign Web Modeler API permissions to that role in Management Identity.
- Create a mapping rule in Management Identity for that role that matches the client's access token.
To grant a user access to Optimize:
- Create a mapping rule in Management Identity for the
Optimizerole that matches the user's access token.
When using an OIDC provider, the following Optimize features are not currently available:
- The User permissions tab in collections.
- The Alerts tab in collections.
- Digests.
- Accessible user names for resource owners (the value of the
subclaim is displayed instead).