Operate 8.7 + Identity + Microsoft Entra ID (Azure AD): login succeeds but Operate redirects to /noPermission — what’s the exact config?

Environment

  • Camunda 8 Operate self-managed (Docker), version 8.7.12

  • Identity enabled, IdP = Microsoft Entra ID (Azure AD)

  • Reverse proxy + TLS in front of the UIs

  • SPRING_PROFILES_ACTIVE=identity-auth

What I did

  1. In Entra ID I created two app registrations:

    • Identity application.

    • Operate application (confidential client).

    • I added the Operate redirect URI:
      https://<OPERATE_HOST>/identity-callback

  2. In Identity, I added mapping rules for my user (by oid and by azp) and granted the Operate role (and tested other roles too).

  3. Login flow works (I’m redirected to Microsoft, sign in, and get redirected back).
    But after the callback, Operate shows /noPermission.

  4. Identity is reachable and healthy. In the browser, GET https://<IDENTITY_HOST>/api/roles returns the roles list.

  5. I tried both spring profiles oidc and identity-auth. identity-auth is the only one that got me this far (even though I’ve seen oidc mentioned in parts of the docs).

Current (sanitized) Operate config

# Profiles / logs
SPRING_PROFILES_ACTIVE=identity-auth
LOGGING_LEVEL_ROOT=INFO
LOGGING_LEVEL_IO_CAMUNDA_OPERATE_WEBAPP_SECURITY_IDENTITY=DEBUG
LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_SECURITY=DEBUG

# Core wiring
CAMUNDA_OPERATE_ZEEBE_GATEWAYADDRESS=zeebe:26500
CAMUNDA_OPERATE_ZEEBE_SECURE=false
CAMUNDA_OPERATE_ELASTICSEARCH_URL=http://elasticsearch:9200
CAMUNDA_OPERATE_ZEEBEELASTICSEARCH_URL=http://elasticsearch:9200
CAMUNDA_OPERATE_MULTITENANCY_ENABLED=false
CAMUNDA_OPERATE_IDENTITY_RESOURCEPERMISSIONSENABLED=false
CAMUNDA_OPERATE_IDENTITY_REDIRECT_ROOT_URL=https://<OPERATE_HOST>
SERVER_FORWARD_HEADERS_STRATEGY=FRAMEWORK

# Identity / Entra (sanitized)
CAMUNDA_OPERATE_IDENTITY_BASEURL=https://<IDENTITY_HOST>
CAMUNDA_OPERATE_IDENTITY_CLIENTID=<OPERATE_APP_ID>
CAMUNDA_OPERATE_IDENTITY_CLIENTSECRET=<SECRET>
# I have tried both of these values for audience over different attempts:
#  - api://<IDENTITY_APP_ID>
#  - <OPERATE_APP_ID>
CAMUNDA_OPERATE_IDENTITY_AUDIENCE=api://<IDENTITY_APP_ID>

# Issuer and explicit Azure v2 endpoints
CAMUNDA_OPERATE_IDENTITY_ISSUER_URL=https://login.microsoftonline.com/<TENANT_ID>/v2.0
CAMUNDA_OPERATE_IDENTITY_ISSUER_BACKEND_URL=https://login.microsoftonline.com/<TENANT_ID>/v2.0
CAMUNDA_OPERATE_IDENTITY_AUTHORIZATION_URL=https://login.microsoftonline.com/<TENANT_ID>/oauth2/v2.0/authorize
CAMUNDA_OPERATE_IDENTITY_TOKEN_URL=https://login.microsoftonline.com/<TENANT_ID>/oauth2/v2.0/token

Symptoms / logs

  • Operate logs show the typical lines:

    • Try to access protected resource /operate. Save it for later redirect

    • IdentityController - Called back by identity with /identity-callback code=...

  • No stack trace now; I simply land on /noPermission in the UI.

Token notes (sanitized)

A decoded user token (authorization_code) during testing includes:

{
  "iss": "https://login.microsoftonline.com/<TENANT_ID>/v2.0",
  "aud": "<IDENTITY_APP_ID or api://<IDENTITY_APP_ID>>",
  "azp": "<OPERATE_APP_ID>",
  "oid": "<MY_USER_OID>"
}

I also created Identity mapping rules for my user (by oid) and for the azp client, assigning Operate (and other product) roles.

What I’ve already tried

  • Swapping AUDIENCE between the Identity app ID and the Operate app ID.

  • Confirmed the Operate redirect URI matches the Entra registration.

  • Verified that Identity endpoints are reachable; mapping rules are visible.

Questions

  1. What is the minimal, exact set of env vars to wire Operate → Identity → Entra ID on Docker Compose for Camunda 8.7?

  2. For CAMUNDA_OPERATE_IDENTITY_AUDIENCE, should this be the Identity app ID (e.g. api://<IDENTITY_APP_ID>) or the Operate app ID?

  3. After the callback, does Operate expect the user’s JWT to already contain an Operate role claim? Or does Operate call Identity’s API (e.g. /api/me) to resolve roles — and if so, what scope/role must the user token have to call that successfully?

  4. Is identity-auth the correct profile for this scenario (Operate behind Identity with Entra as IdP)? Any doc that shows a complete example with Entra?

  5. Given that I’m consistently landing on /noPermission even though Identity mapping rules grant my user the Operate role: what else could be missing (tenants? additional claims? different audience)?

Any guidance or a known-good Compose snippet for Entra ID would be greatly appreciated!

Hi @tlmouden,

Based on your configuration and the symptoms you’re describing, I can help you troubleshoot this /noPermission issue. This is a common problem when the authentication succeeds but the authorization (role assignment) fails.

Answers to Your Specific Questions

1. Minimal Environment Variables for Operate → Identity → Entra ID:

Your configuration looks mostly correct, but here are the key variables you need:

# Spring Profile
SPRING_PROFILES_ACTIVE=identity-auth

# Identity Integration
CAMUNDA_OPERATE_IDENTITY_BASEURL=https://<IDENTITY_HOST>
CAMUNDA_OPERATE_IDENTITY_CLIENTID=<OPERATE_APP_ID>
CAMUNDA_OPERATE_IDENTITY_CLIENTSECRET=<SECRET>
CAMUNDA_OPERATE_IDENTITY_AUDIENCE=<OPERATE_APP_ID>  # This should be your Operate app ID
CAMUNDA_OPERATE_IDENTITY_REDIRECT_ROOT_URL=https://<OPERATE_HOST>

# Entra ID Endpoints
CAMUNDA_OPERATE_IDENTITY_ISSUER_URL=https://login.microsoftonline.com/<TENANT_ID>/v2.0
CAMUNDA_OPERATE_IDENTITY_ISSUER_BACKEND_URL=https://login.microsoftonline.com/<TENANT_ID>/v2.0

2. CAMUNDA_OPERATE_IDENTITY_AUDIENCE Setting:

The audience should be set to your Operate app ID (not the Identity app ID). This ensures that the JWT token’s audience matches what Operate expects.

3. Role Resolution Process:

After the callback, Operate doesn’t expect the JWT to contain role claims directly. Instead, it calls Identity’s API to resolve roles based on the mapping rules you’ve configured. The user token needs to be valid for Identity to process the role mapping.

4. Spring Profile:

Yes, identity-auth is the correct profile for this scenario.

5. Most Likely Issue - Mapping Rules:

The /noPermission error typically indicates that your user’s JWT claims don’t match any mapping rules in Identity, or the mapping rules aren’t assigning the correct roles.

Troubleshooting Steps

Step 1: Verify Your JWT Token Claims

Decode your JWT token (you can use jwt.io) and confirm it contains the claims you’re trying to map against. From your example:

  • oid: Your user’s object ID
  • azp: Your Operate app ID

Step 2: Check Identity Mapping Rules

  1. Log into your Identity UI at https://<IDENTITY_HOST>
  2. Go to the Mappings tab
  3. Verify you have mapping rules that:
    • Match the oid claim with your user’s object ID
    • Assign the Operate role
    • Use the correct operator (Equals for string claims)

Step 3: Enable Debug Logging

Add these environment variables to get more detailed logs:

LOGGING_LEVEL_IO_CAMUNDA_IDENTITY=DEBUG
LOGGING_LEVEL_IO_CAMUNDA_OPERATE_WEBAPP_SECURITY=DEBUG

Step 4: Verify Identity Configuration

Make sure your Identity service has the correct configuration for Entra ID and can properly validate tokens from your tenant.

Configuration Fix

Based on your setup, try changing your audience setting:

# Change this:
CAMUNDA_OPERATE_IDENTITY_AUDIENCE=api://<IDENTITY_APP_ID>
# To this:
CAMUNDA_OPERATE_IDENTITY_AUDIENCE=<OPERATE_APP_ID>

Additional Resources

Let me know what you find in the Identity mapping rules and the debug logs - that should help us pinpoint the exact issue!

Hey everyone, sharing the root cause and fix for the 403 right after Microsoft (Entra ID) login with Camunda 8 (Operate/Optimize via Identity).

What was wrong (in simple terms)

  • After switching to MICROSOFT/Entra ID, I set:

    • CAMUNDA_OPERATE_IDENTITY_AUDIENCE=<Operate Entra App (client) ID>

    • (and similarly for Optimize/Tasklist)

  • Identity now checks permissions by that audience (the GUID client ID).

  • But in the Identity DB, the permissions table still had the old Keycloak-style audiences:

    • operate-api, optimize-api, tasklist-api, …
  • Result: Identity looks up permissions for the new audience (GUID), finds no rows, and Optimize/Operate return 403.

How it shows up

  • Logs show Identity hitting:

    GET /api/permissions/for-token?audience=<GUID_of_Entra_App>
    
    

    Then the login callback ends with 403 even though Microsoft login succeeds.

How to confirm (quick DB check)

Open Postgres for Identity and inspect audiences in the permissions table public.permissions:

SELECT DISTINCT audience
FROM public.permissions
ORDER BY audience;

If you see operate-api, optimize-api, tasklist-api (or similar) instead of your Entra client IDs, that’s the mismatch.

The fix

Update those audience values to the actual Entra App (client) IDs you configured:

-- Operate
UPDATE public.permissions
SET audience = '<OPERATE_APP_CLIENT_ID>'
WHERE audience = 'operate-api';

-- Optimize
UPDATE public.permissions
SET audience = '<OPTIMIZE_APP_CLIENT_ID>'
WHERE audience = 'optimize-api';

-- Tasklist (if you use it)
UPDATE public.permissions
SET audience = '<TASKLIST_APP_CLIENT_ID>'
WHERE audience = 'tasklist-api';

After this, the callback completed normally and the apps stopped returning 403.

Make sure your mappings are correct, and you give the user/group the correct permissions.

Summary: Operate 8.7 + Identity + Microsoft Entra ID /noPermission Issue

Root Cause: The issue you’re experiencing is a common problem when migrating to or setting up Microsoft Entra ID with Camunda Identity. The problem occurs because:

  1. Your configuration is mostly correct - you’re using the right Spring profile (identity-auth) and the correct audience setting (<OPERATE_APP_ID>)

  2. Database mismatch - The Identity database’s permissions table still contains old-style audience values (like operate-api) instead of your actual Entra ID client IDs

The Fix:

You need to update the audience values in the Identity database to match your Entra ID application client IDs:

-- Connect to your Identity PostgreSQL database and run:
UPDATE public.permissions
SET audience = '<YOUR_OPERATE_APP_CLIENT_ID>'
WHERE audience = 'operate-api';

Verification Steps:

  1. Check your current database state:

    SELECT DISTINCT audience FROM public.permissions ORDER BY audience;
    
  2. If you see operate-api instead of your Entra client ID, apply the UPDATE statement above

  3. Restart Operate and test the login flow

Key Configuration Points Confirmed:

  • :white_check_mark: SPRING_PROFILES_ACTIVE=identity-auth is correct
  • :white_check_mark: CAMUNDA_OPERATE_IDENTITY_AUDIENCE=<OPERATE_APP_ID> is correct
  • :white_check_mark: Your mapping rules in Identity UI should work once the database is updated
  • :white_check_mark: Your Entra ID redirect URI configuration is correct

This database update resolves the mismatch between what Identity expects (your Entra client ID) and what’s stored in the permissions table, allowing proper authorization after successful authentication.

References:

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.