# Troubleshoot SSO

Use this page to investigate federated identity and SSO issues without exposing sensitive identity data.

## Start with the failure point


```mermaid
flowchart TD
    A["User starts login"] --> B{"Redirect to Keycloak works?"}
    B -- No --> R["Check URLs, ingress, TLS, and Keycloak availability"]
    B -- Yes --> C{"External IdP login works?"}
    C -- No --> I["Check discovery, client ID, client secret, redirect URI, scopes, and IdP policy"]
    C -- Yes --> D{"Keycloak maps the user?"}
    D -- No --> M["Check provider mappers and required claims"]
    D -- Yes --> E{"Custody accepts the token?"}
    E -- No --> T["Check issuer, audience, subject, loginIds, and user domain access"]
    E -- Yes --> S["Check session, role, policy, and application-specific behavior"]
```

## Common symptoms

| Symptom | Check first |
|  --- | --- |
| User cannot reach the sign-in page | Keycloak availability, ingress, TLS, hostname, and browser redirect URL. |
| IdP rejects the login request | Client ID, client secret, redirect URI, requested scopes, and IdP application assignment. |
| User loops through the identity provider | IdP prompt and consent settings, and whether the user has already granted required consent. |
| Login succeeds at the IdP but fails in Keycloak | Keycloak provider settings, client secret, discovery endpoint, JWKS, and provider mappers. |
| Web login remains stuck after identity-provider authentication | Keycloak client configuration, required claims, and token mapper configuration. |
| Token validation returns 401 | Issuer, audience, token expiry, signing key, and whether the token subject matches a Custody login ID. |
| User signs in but sees only some domains | `loginIds`, roles, and domain access for each domain where the user should operate. |
| Repeat login creates or finds the wrong user | Mapper templates, chosen claim, sync mode, and whether the claim is stable and populated. |
| Keycloak or dependent services fail after deployment | Database connection URL encoding, Keycloak database state, client secrets, and deployment secret references. |


## Claim and mapper checks

For a federated user, confirm:

- The upstream ID token contains the claim used by `${CLAIM.<claim-name>}`.
- The Keycloak provider alias matches the Custody `loginIds.providerId`.
- Username template mappers use `:` as the separator.
- The `Hardcoded user session attribute` mapper sets `identity_provider_alias`.
- The Keycloak-issued token subject is the value Custody expects for the user's login ID.


If a mapper template resolves to an empty value, request the missing scope in Keycloak or configure the upstream identity provider to emit the required claim.

## Browser-visible and server-side failures

Some SSO failures are not visible in browser developer tools. During OIDC federation, the browser sees the redirects, but Keycloak also performs server-side calls to the upstream provider.

| Failure area | Where to look |
|  --- | --- |
| Authorization redirect | Browser network trace, redirect URI, provider alias, and IdP application assignment. |
| Token exchange | Keycloak logs, upstream token endpoint availability, client secret, TLS trust, and network policy. |
| User mapping | Keycloak logs, provider mappers, token claims, and Custody `loginIds`. |
| Custody authorization | Custody API response, user roles, domain access, policy requirements, and signing state. |


If login fails after the upstream IdP step, do not rely only on the browser trace. Check Keycloak logs for token endpoint, TLS, issuer, audience, and mapper errors.

## Secret and redirect checks

Client secret and redirect URI mismatches are common because both Keycloak and the upstream identity provider must agree on the values.

| Area | What to compare |
|  --- | --- |
| Identity provider client secret | Secret configured on the Keycloak identity provider and the secret configured for the application in the upstream IdP. |
| Component client secrets | Secrets stored in Keycloak and the deployment secrets consumed by Custody components. |
| Redirect URI | Redirect URI registered in the upstream IdP and the Keycloak broker endpoint for the provider alias. |
| Issuer URL | Issuer in tokens and the issuer expected by the downstream verifier. Match scheme, host, port, realm, and trailing slash behavior exactly. |
| Audience | Audience in the token and the value expected by the receiving service. |


When rotating secrets, remember that Keycloak stores some configuration in its realm database. Updating a Kubernetes secret alone might not update the value already stored in Keycloak. Confirm the value in the upstream IdP, Keycloak, and the deployment secret reference.

For deployment-level secret references, see [Secret management for authentication](/products/custody/v1.36/deployment/reference/auth-secrets) and [Keycloak configuration](/products/custody/v1.36/deployment/reference/keycloak).

## Keycloak deployment checks

If Keycloak or a dependent service fails immediately after deployment:

- Confirm Keycloak can connect to its PostgreSQL database.
- Percent-encode reserved URL characters in database usernames or passwords used in connection strings.
- Confirm Keycloak realm import or synchronization completed successfully.
- Confirm client secrets in Keycloak match the secrets consumed by dependent services.
- Confirm the Keycloak issuer URL is reachable from both the browser path and the in-cluster service path.


## Evidence to collect

Collect enough evidence to isolate the failure point:

- The Keycloak provider alias.
- The non-secret IdP client settings: discovery endpoint, redirect URI, scopes, and issuer.
- Sanitized Keycloak logs around the failed login.
- Sanitized application logs around the failed API call.
- Decoded JWT headers and claims with signatures, secrets, and personal data removed.
- Timestamp, redacted user identifier, and whether repeat login or first login failed.


Do not collect client secrets, private keys, full JWTs, or unredacted identity data in tickets or chat.

## When login succeeds but authorization fails

SSO proves who the user is. It does not grant custody permissions by itself. If authentication succeeds but the user cannot perform an action, check:

- The user exists in the expected domain.
- The user has the expected `loginIds`.
- The user has the roles required by policies and domain read access.
- The operation still has the required signature and approval path.
- The user is not locked.


For user operations, see [Manage users and roles](/products/custody/v1.36/governance/users/manage-users-and-roles). For the policy model, see [Policies](/products/custody/v1.36/governance/policies).