Skip to main content

Troubleshooting IdP Logins

Goal

A user signs in through your external IdP successfully, but the application then behaves as though they have no access — the Policies tab is missing, creating an AI System fails, or the UI reports an authentication error even though the login itself worked.

None of the symptoms below indicate a misconfigured Identity Provider. If sign-in completes and the user reaches the application at all, the IdP integration is working. Each one is a distinct, later step in onboarding that a federated user does not receive automatically.

Most of this is avoidable

Most of these sections exist because a required onboarding step was skipped, not because something broke. If you are setting up an IdP now, follow Entra ID as IdP and Add the Email Claim and you should never reach this page. It is here for deployments already past that point, and to map symptoms back to causes that are not obvious from the error text.

Use this guide after completing Entra ID as IdP or Keycloak as IdP and Adding Mappers.

The Policies Tab Is Missing for an IdP User​

The user signs in, sees Projects and AI Systems, and no Policies tab. Roles and group membership look correct in Keycloak.

On 3.26.9 and later, check the user's DynamoGuard role first. The release removed the per-user flag that used to gate this tab, so a missing tab now means a missing role rather than a missing activation step. See Roles for which roles grant DynamoGuard access.

On Releases Before 3.26.9​

Earlier releases gate the tab on a per-user configuration value rather than on a role:

hasDynamoGuardAccess = config.MODERATION.dynamoGuardAccess === 'ACTIVATED'

Its default is UNACTIVATED, and no Keycloak role or group mapper can set it, because it lives in the platform's own configuration store rather than in the realm. Checking the user's Keycloak roles is a dead end on those releases: the roles are correct and irrelevant to the flag.

The value is user scoped, so query it as the affected user rather than as an administrator:

Read the access config as the affected user
curl -s -H "Authorization: Bearer $USER_TOKEN" \
https://api.<domain>/v1/config | jq '.response.MODERATION'

ACTIVATED means this is not the cause. Anything else means the activation step has not run; see Activate Each IdP User on the Platform.

POST /v1/user/setup does not grant this access. It creates demo policies and models, reports the steps POLICIES and MODELS, and never writes dynamoGuardAccess. A successful response from it is not evidence that the user has access.

Policy user:<email> not found When Creating an AI System​

Creating an AI System (or another shared resource) fails with:

Policy user:someone@example.com not found

Creating a resource attaches a permission bound to a Keycloak authorization policy named after the creator. That policy is created lazily, from the email on an authenticated request. If it is absent, resource creation fails while everything else about the session works — which is why this looks like a permissions bug rather than a missing object.

List the policies that exist on the API client's resource server:

List per-user authorization policies
curl -s -H "Authorization: Bearer $ADMIN_TOKEN" \
"https://<keycloak-domain>/admin/realms/<realm>/clients/<api-client-uuid>/authz/resource-server/policy?max=100" \
| jq -r '.[] | select(.name | startswith("user:")) | .name'

Expect one user:<email> entry per active user. A federated user missing from that list is the failure.

Create the missing policy​

Have the user load the application once and retry first — the lazy creation is driven by their request, so an admin acting on their behalf does not trigger it. If it still does not appear, create it explicitly:

Create the user policy
curl -s -X POST \
"https://<keycloak-domain>/admin/realms/<realm>/clients/<api-client-uuid>/authz/resource-server/policy/user" \
-H "Authorization: Bearer $ADMIN_TOKEN" -H 'Content-Type: application/json' \
-d '{"name":"user:someone@example.com","users":["<keycloak-user-uuid>"]}'
This also blocks user setup

The POLICIES step of user setup fails with this same message when the policy is absent, on deployments where that step runs at all. Create the policy first, then re-run setup. Otherwise setup reports a partial success that is easy to misread as complete.

The IdP Returns No Email Claim​

A first-time IdP user is shown Keycloak's Review Profile page and asked to type their email, or a request fails because the platform cannot resolve the user.

The email is not cosmetic. The platform resolves the signed-in user by email on every request, and the lazy creation of the authorization policy above is keyed on it — so a token without an email produces failures that look unrelated to the IdP.

Two things to check, in order:

  1. Does the IdP actually send it? Microsoft Entra ID only emits an email claim when the user's mail attribute is populated. For many directories the address lives in the UPN instead. Add email (and upn) as optional ID-token claims on the application registration — the same Token configuration screen used to add the groups claim in Adding Mappers.

  2. Is it mapped onto the user? Add an Attribute Importer mapper on the Identity Provider so the claim lands on the account:

    AttributeValue
    Mapper TypeAttribute Importer
    Claimemail
    User Attribute Nameemail
    Sync Mode OverrideInherit

    Add a second one from preferred_username to email as a fallback for directories that only populate the UPN. Identity-provider mappers run before the profile-review step, so a populated email suppresses the prompt.

Where the prompt is actually controlled

The Review Profile page is governed by the first broker login flow's Review Profile execution, whose config is update.profile.on.first.login. The default missing prompts only when a required field is absent — which is the correct setting, and means a prompt is evidence that a claim is genuinely missing rather than something to switch off. The Identity Provider's own updateProfileFirstLoginMode field is legacy and is not honoured by current Keycloak versions; setting it has no effect.

Unable to authenticate user During Normal Use​

The UI intermittently reports Unable to authenticate user, or an action such as saving a policy fails with Please try later, and retrying a minute later succeeds.

Check whether Keycloak restarted rather than looking for a permissions problem:

Keycloak and API pod age
kubectl -n <namespace> get pods -l app.kubernetes.io/name=keycloak
kubectl -n <namespace> get pods -l app.kubernetes.io/name=dynamoai-api

A Keycloak pod that is only a minute or two old, alongside API pods with recent restarts, is the signature. The API treats Keycloak as a hard startup dependency — it logs Keycloak is not available, then Failed to authenticate with Keycloak after multiple attempts, and exits. So a brief Keycloak outage becomes a longer API outage, and the user-visible error names authentication rather than the restart.

Confirm from the API's own logs
kubectl -n <namespace> logs deploy/dynamoai-api --previous | grep -i keycloak

On clusters with node autoscaling this is usually node consolidation evicting the pod:

kubectl -n <namespace> get events --sort-by=.lastTimestamp | grep -iE 'Evicted|Underutilized'
A PodDisruptionBudget may not protect a single-replica component

A PDB written as maxUnavailable: 1 against a one-replica workload permits disrupting 100% of it — it looks like protection and provides none. kubectl get pdb shows ALLOWED DISRUPTIONS 0 only while the pod is already down, which makes the gap easy to miss.

For a stateful singleton such as Keycloak or MinIO, either use minAvailable: 1, or exclude it from consolidation entirely. With Karpenter or AKS Node Auto Provisioning:

Exclude a singleton from node consolidation
podAnnotations:
karpenter.sh/do-not-disrupt: "true"

Apply the same treatment to any single-replica component whose loss breaks others — MinIO is the other common one, because guard model servers stream their weights from it and crashloop while it is gone.

Claim-Mapped Roles Missing After Entra ID Sign-In​

The user signs in through Entra ID without error, is in the all-users group, but is missing org-level roles that their Entra security group membership should grant. Other users with fewer Entra groups receive the expected roles.

Start by reading the roles the platform actually resolved for the user, rather than inferring them from the console:

Read a user's effective org-level roles
curl -s -H "Authorization: Bearer $ADMIN_TOKEN" \
"https://api.<domain>/v1/user/all?includeOrgLevelRoles=true" \
| jq '.users[] | select(.email=="USER_EMAIL") | {email, orgLevelRoles}'

An empty orgLevelRoles array confirms that no Advanced Claim to Role mapper matched. Three causes produce that result, and they are distinguished by decoding the user's ID token:

CauseWhat the token showsFix
Group claim overage_claim_names or hasgroups, and no groups arrayEntra ID Groups Claim Overage
Mapper claim value does not matchA groups array whose Object IDs are absent from the mapper regexCorrect the regex in Adding Mappers
Mapper never evaluatedA groups array that does match the regexHave the user sign out fully and sign in again

Keycloak Advanced Claim to Role mappers read only what is present in the ID token at login. They do not call Microsoft Graph through the _claim_sources overage endpoint, and they do not re-evaluate outside a login.

A partial role set is the same failure

A user who receives some of their expected roles and not others is not a different problem. Each mapper matches independently, so one malformed regex removes exactly one role while every other mapper keeps working. Compare the resolved orgLevelRoles against the full set of mappers rather than concluding that mapping works because a role arrived.

A User With No Org-Level Roles Receives 500​

The user signs in, and the interface reports Error processing request. with a request ID. The API log shows:

GlobalExceptionsFilter: Exception: undefined is not iterable (cannot read property Symbol(Symbol.iterator))
at DynamoAIKeycloakService.getUserOrgLevelScopes

A user holding zero org-level roles produces a server error rather than an empty permission set, so the first symptom of a role-mapping failure is a crash rather than a clean denial. Side effects include Unable to fetch platform config and Error fetching user terms and consents in the same session, because those requests resolve scopes too.

Confirm with the effective-roles command above. An empty orgLevelRoles array alongside this error is the signature.

Fix​

Assign the user at least one org-level role. This is the same root cause as Claim-Mapped Roles Missing, so fix the mapping rather than granting a role by hand, and the error resolves with it.

An Endpoint Returns 500 for a Valid User​

A request that takes a user identifier returns Internal Server Error rather than a not-found response, for a user who demonstrably exists.

The platform holds two different identifiers for the same person, and they are not interchangeable:

IdentifierShapeExample
Keycloak user idUUID, 36 characters with hyphensb815994f-fd4e-446b-b686-7e0129b14e2a
Application user id24 hexadecimal characters507f1f77bcf86cd799439011

Endpoints that accept a userId expect the application user id. Supplying the Keycloak UUID fails type conversion before the not-found check runs, which is why the response is 500 rather than 404.

Read both from the same record:

Read both identifiers for a user
curl -s -H "Authorization: Bearer $ADMIN_TOKEN" \
"https://api.<domain>/v1/user/all" \
| jq '.users[] | select(.email=="USER_EMAIL") | {email, keycloakId, dynamoAIId}'

dynamoAIId is the value these endpoints expect. keycloakId is the value shown in the Keycloak administration console, which is where the wrong one is usually copied from.