Skip to main content

Keycloak RBAC

This guide maps Keycloak client roles onto Endatix roles. The API keeps the access token small and loads roles from the Keycloak token introspection endpoint. Introspection runs only when Authorization.RoleMappings has at least one entry.

Concepts

For a general overview of external authorization concepts and benefits, see the External Authorization guide.

Prerequisites​

  • Keycloak authentication already configured (see Keycloak Setup)
  • Admin access to Keycloak realm
  • Endatix API and Endatix Hub running

Dev realm​

The Endatix API realm file already defines client roles on endatix-hub and assigns them. Password for each user is admin@2.

UserClient roleEndatix role
external-admin@endatix.comadminAdmin
external-creator@endatix.comcreatorCreator
respondent@endatix.comrespondentRespondent
external@endatix.comnonenone beyond Authenticated

external-admin@endatix.com is on endatix.com. The dev realm turns on Always use lightweight access token for endatix-hub. Hub stores that access token in the session cookie, so the JWT stays small: sub, aud, issuer, expiry, and session id. Email, name, and client roles stay out of the JWT. The API reads roles from token introspection.

A password grant for external-admin@endatix.com against client endatix-hub returns a JWT whose aud is endatix-hub and endatix-app, with no resource_access. Introspection of that same token returns resource_access.endatix-hub.roles ["admin"]. Both audiences have to be in the JWT. The API checks endatix-app, and Keycloak introspection stays inactive unless endatix-hub is in aud. On Keycloak 26 the mapper switch is Add to lightweight access token (lightweight.claim). The older include.in.lightweight.access.token flag is ignored, so aud and sub disappear from the JWT and the API rejects the call.

Introduction​

This guide covers:

  • Enabling lightweight JWT tokens in Keycloak
  • Configuring protocol mappers for token introspection
  • Setting up role mappings in the Endatix API
  • Testing token introspection

Why Lightweight Tokens?​

Lightweight access tokens keep the JWT small:

  • The Hub session cookie stays under browser size limits when a user has many client roles
  • Email and name are not copied into every API request
  • Role checks go through the introspection endpoint, which is where enterprise role sets belong

Lightweight Token Overview​

When using lightweight tokens, certain claims cannot be removed as they are essential for security:

  • exp: Expiration time - Unix timestamp when the token becomes invalid
  • iat: Issued at - Unix timestamp when the token was created
  • jti: JWT ID - Unique token identifier for revocation tracking
  • iss: Issuer - Identifies the Keycloak realm that issued the token
  • typ: Type - Declares token type (Bearer)
  • azp: Authorized party - The client that the token was issued to
  • sid: Session ID - Links the token to a specific Keycloak session
  • scope: Scopes granted - Lists permissions or OpenID Connect scopes

Role and permission information is excluded from the lightweight token and retrieved via token introspection when needed.

Step 1: Enable Lightweight JWT Tokens in Keycloak​

  1. Go to your realm in Keycloak Admin Console
  2. Click on "Clients"
  3. Select your client (e.g., endatix-hub)
  4. Go to "Advanced settings" tab
  5. Find "Always use lightweight access token" and turn the switch to On
  6. Click "Save"
Alternative Method

You can also use Keycloak client policies to conditionally enable lightweight tokens. See the Keycloak documentation for details.

Step 2: Keep sub and aud in the lightweight token​

Keycloak 26 leaves Add to lightweight access token off on protocol mappers. Turn it on only for the claims the API reads from the JWT itself.

  1. Open client endatix-hub, Client scopes, Dedicated scopes, Mappers.
  2. For each audience mapper (endatix-app and endatix-hub), turn Add to lightweight access token on. Leave Add to token introspection on.
  3. Add a mapper By configuration, type Subject (sub), and turn Add to lightweight access token on. The default sub mapper on the basic client scope does not add sub to a lightweight token, and the API requires that claim.
  4. Leave the client-roles mapper out of the lightweight token. Turn Add to token introspection on so resource_access.endatix-hub.roles is returned by POST /realms/{realm}/protocol/openid-connect/token/introspect.

The dev realm already has these mappers. A decoded access token contains sub and aud, and does not contain resource_access or email.

Step 3: Configure Client Roles​

For token introspection to return role information, users must have client roles assigned:

  1. Go to "Clients" in Keycloak
  2. Click on your client (e.g., endatix-hub)
  3. Go to the "Roles" tab
  4. Create client-specific roles. The dev realm uses admin, creator, and respondent.
  5. Assign these roles to users:
    • Go to "Users" → Select a user
    • Go to "Role Mappings" tab
    • Click "Assign role"
    • Filter by your client and select the roles
    • Click "Assign"

Step 4: Configure Protocol Mappers for Introspection​

Ensure role mappers are configured to include data in token introspection:

  1. Go to "Client Scopes" → "Roles" → "Mappers" tab
  2. For each role mapper (e.g., "realm roles", "client roles"):
    • Click on the mapper
    • Ensure "Add to token introspection" is turned On
    • Click "Save"

This ensures that role information is available in the introspection response even though it's excluded from the lightweight token payload.

Step 5: API Configuration​

Update your appsettings.json to include the Authorization section:

{
"Endatix": {
"Auth": {
"Providers": {
"Keycloak": {
"Enabled": true,
"DefaultTenantId": 1,
"Audience": "endatix-app",
"Issuer": "http://127.0.0.1:8080/realms/endatix",
"RequireHttpsMetadata": false,
"ClientId": "endatix-hub",
"ClientSecret": "endatix-dev-hub-client-secret",
"Authorization": {
"RoleMappings": {
"admin": "Admin",
"creator": "Creator",
"respondent": "Respondent"
},
"RolesPath": "resource_access.{ClientId}.roles"
}
}
}
}
}
}

Configuration Properties​

Authorization Section:

  • RoleMappings: Maps Keycloak roles to Endatix application roles
    • Key: Keycloak role name (as it appears in the introspection response)
    • Value: Endatix role name (Admin, Creator, Respondent, or PlatformAdmin)
  • RolesPath: JSON path to roles in the token introspection response
    • Use {ClientId} placeholder which will be replaced with your actual ClientId
    • Example: "resource_access.endatix-hub.roles" (if ClientId is endatix-hub)

Other Properties:

  • DefaultTenantId: Default tenant ID for authenticated users (defaults to 0)
  • ClientId: Your Keycloak client ID (required)
  • ClientSecret: Your Keycloak client secret (required)

Step 6: Testing Token Introspection​

Get an Access Token​

  1. First, obtain a lightweight access token from Keycloak using your preferred method (OAuth flow, direct access grant, etc.).
  2. Call GET /api/auth/me on the Endatix API with the token in the Authorization header.
curl --location 'https://{{ENDATIX_API_URL}}/api/auth/me' \
--header 'Authorization: Bearer {{KEYCLOAK_ACCESS_TOKEN}}'

The response should be like this:

GET /api/auth/me returns AuthorizationData. Roles are Endatix role names after RoleMappings, plus Authenticated. A user with only the Keycloak role admin looks like this. isAdmin is true because the mapped role is Admin. permissions come from those roles. There is no email field.

{
"userId": "0f6d8b28-e761-4033-8e84-2ddebecec49c",
"tenantId": 1,
"roles": ["Authenticated", "Admin"],
"permissions": ["access.authenticated", "access.apps.hub"],
"isAdmin": true,
"cachedAt": "2025-01-01T00:00:00Z",
"expiresAt": "2025-01-01T00:05:00Z",
"eTag": "1234567890"
}

Debug Tips​

  1. Enable API logging to see introspection calls and responses
  2. Test introspection directly with Keycloak.
  3. Verify token structure by decoding the JWT (without verification) to see available claims. You can use jwt.io to decode the token.
  4. Check Keycloak logs for introspection endpoint activity

Security Considerations​

Why Lightweight Tokens Are More Secure​

  • Reduced attack surface: Less information in the token means less information to exploit
  • PII protection: Sensitive user data is not transmitted in every request
  • Token size: Smaller tokens reduce the risk of header size limits and improve performance

Production Best Practices​

  • Use HTTPS: Always use HTTPS in production for token transmission
  • Rotate secrets: Regularly rotate client secrets
  • Monitor introspection: Log and monitor introspection endpoint usage
  • Limit token lifetime: Use appropriate token expiration times
  • Secure storage: Store client secrets securely (environment variables, secrets manager)
  • Audit logging: Enable audit logging in Keycloak for authorization events

Next Steps​

Additional Resources​