Keycloak Troubleshooting: Fix the 10 Most Common Errors

Guilliano Molaire Guilliano Molaire Updated June 3, 2026 10 min read

Last updated: March 2026

Every Keycloak administrator hits the same set of errors. After helping hundreds of teams deploy and configure Keycloak, these are the ten errors that come up again and again. For each one, we provide the error message you will see, what causes it, and the exact steps to fix it.

Bookmark this page. You will need it.

1. Redirect URI Mismatch

The Error

Invalid parameter: redirect_uri

Or in the browser:

We are sorry...
Invalid redirect uri

What Causes It

The redirect_uri parameter in the authorization request does not match any of the Valid redirect URIs configured on the Keycloak client. Keycloak validates this strictly for security reasons (to prevent open redirect attacks).

Common triggers:

  • Trailing slash mismatch (https://app.example.com vs https://app.example.com/)
  • HTTP vs HTTPS mismatch
  • Port number included in one but not the other
  • Query parameters in the redirect URI that are not covered by a wildcard
  • Different domain (e.g., localhost in development vs production domain)

How to Fix It

  1. Open the Keycloak Admin Console
  2. Go to Clients > select your client > Settings
  3. Under Valid redirect URIs, add the exact URI your application sends, or use a wildcard pattern

Common patterns:

https://app.example.com/*          # Matches any path
http://localhost:3000/*             # Local development
https://app.example.com/callback   # Exact match

For development, you can temporarily use * as the redirect URI, but never do this in production.

Verify the fix: Check what your application is actually sending by inspecting the browser’s network tab. Look at the authorization request URL and find the redirect_uri parameter. Copy that exact value into the Valid redirect URIs field.

You can also use the JWT Token Analyzer to inspect tokens after a successful login to confirm the correct client and redirect URI are being used.

2. Invalid Grant (invalid_grant)

The Error

{
  "error": "invalid_grant",
  "error_description": "Code not valid"
}

Or:

{
  "error": "invalid_grant",
  "error_description": "Session not active"
}

What Causes It

The invalid_grant error has several common causes:

  • Expired authorization code: Authorization codes are valid for a very short time (default: 60 seconds in Keycloak). If your application takes too long to exchange the code for tokens, it expires.
  • Code already used: Authorization codes are single-use. If your application accidentally exchanges the same code twice (e.g., due to a page refresh), the second exchange fails.
  • Expired refresh token: When using a refresh token that has expired or been revoked.
  • Session ended: The user’s session was terminated by an admin or by session timeout settings.
  • Clock skew: The server clock is out of sync, causing time-based validations to fail.

How to Fix It

For expired codes:

  • Check your application’s token exchange timing. The code exchange should happen immediately after receiving the callback.
  • In Keycloak, you can increase the code lifespan under Realm Settings > Tokens > OAuth 2.0 Device Code Lifespan, but this is not recommended. Fix the timing in your application instead.

For reused codes:

  • Ensure your application does not exchange the code on page refresh. A common pattern: after exchanging the code, redirect the user to a clean URL without the code query parameter.

For expired refresh tokens:

  • Check Realm Settings > Sessions and Tokens for the session and token lifespan values.
  • Implement proactive token refresh in your application (refresh before the token expires, not after).

For clock skew:

# Check the server time
date
# Sync with NTP
timedatectl set-ntp true

3. 403 Forbidden

The Error

403 Forbidden

This can appear in the Admin Console, Admin REST API, or when accessing protected resources.

What Causes It

  • Admin API access without proper roles: The user or service account does not have the required admin realm roles.
  • Fine-grained admin permissions: Keycloak 25+ has fine-grained admin permissions that may restrict access to specific operations.
  • Client does not have service account roles: When using client credentials flow, the client’s service account needs realm management roles.
  • IP restriction: If you have IP restrictions configured on the admin console.

How to Fix It

For Admin API access:

  1. Go to Realm Settings > Users > find the admin user
  2. Go to Role Mappings
  3. Assign the appropriate roles from the realm-management client:
    • realm-admin for full access
    • view-users, manage-users, etc. for specific access

For service accounts (client credentials):

# Check which roles your service account has
curl -s -H "Authorization: Bearer $TOKEN" 
  "$KEYCLOAK_URL/admin/realms/$REALM/clients/$CLIENT_UUID/service-account-user" | jq

For a detailed troubleshooting guide on 403 errors, see our dedicated post on Keycloak 403 Forbidden troubleshooting.

4. Connection Refused / Cannot Connect to Database

The Error

Failed to obtain JDBC connection
org.postgresql.util.PSQLException: Connection refused

Or on startup:

ERROR: Failed to start server
Caused by: org.postgresql.util.PSQLException: The connection attempt failed.

What Causes It

  • Database is not running or not ready when Keycloak starts
  • Wrong database hostname, port, or credentials
  • Database connection pool exhausted
  • Network connectivity issue between Keycloak and the database
  • PostgreSQL pg_hba.conf does not allow connections from Keycloak’s IP

How to Fix It

Verify database connectivity:

# From the Keycloak container/host, test the connection
psql -h postgres-host -U keycloak -d keycloak

# If using Docker Compose, check the database container is healthy
docker compose ps
docker compose logs postgres

Check environment variables:

# Verify these are set correctly
echo $KC_DB_URL          # jdbc:postgresql://hostname:5432/keycloak
echo $KC_DB_USERNAME     # keycloak
echo $KC_DB_PASSWORD     # (should be set)

If using Docker Compose, ensure Keycloak depends on the database with a health check:

keycloak:
  depends_on:
    postgres:
      condition: service_healthy

For connection pool exhaustion, increase the pool size:

KC_DB_POOL_MIN_SIZE=5
KC_DB_POOL_MAX_SIZE=20

See our Docker Compose production guide for a properly configured setup.

5. SSL/TLS Certificate Errors

The Error

PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException:
unable to find valid certification path to requested target

Or in the browser:

SSL_ERROR_RX_RECORD_TOO_LONG

What Causes It

  • Self-signed certificates not trusted by Keycloak’s JVM truststore
  • TLS termination misconfiguration (Keycloak receiving HTTPS when it expects HTTP behind a proxy)
  • Certificate chain incomplete (missing intermediate certificates)
  • Wrong hostname in the certificate

How to Fix It

If Keycloak is behind a reverse proxy (most common setup):

Keycloak should run in HTTP mode, and the proxy handles TLS:

KC_HTTP_ENABLED=true
KC_PROXY_HEADERS=xforwarded
# Do NOT set KC_HTTPS_* variables when behind a proxy

If Keycloak handles TLS directly:

KC_HTTPS_CERTIFICATE_FILE=/opt/keycloak/certs/tls.crt
KC_HTTPS_CERTIFICATE_KEY_FILE=/opt/keycloak/certs/tls.key

If connecting to an external IdP with a self-signed cert:

Import the certificate into Keycloak’s JVM truststore:

keytool -import -alias idp-cert 
  -file /path/to/idp-cert.pem 
  -keystore /opt/keycloak/conf/truststore.jks 
  -storepass changeit -noprompt

# Then configure Keycloak to use it
KC_TRUSTSTORE_PATHS=/opt/keycloak/conf/truststore.jks

For a complete guide on running Keycloak behind a reverse proxy, see our post on how to run Keycloak behind a reverse proxy.

6. Login Loop (Infinite Redirect)

The Error

The browser keeps redirecting between your application and Keycloak without ever completing the login. You see the login form, submit credentials, and get redirected back to the login form.

What Causes It

  • Cookie issues: The browser cannot set or read the Keycloak session cookie. Common when the Keycloak hostname uses a different domain than expected, or when SameSite cookie settings are too restrictive.
  • Hostname mismatch: The KC_HOSTNAME setting does not match the URL the browser uses to access Keycloak.
  • Proxy misconfiguration: The reverse proxy is not forwarding the correct headers, so Keycloak generates URLs with the wrong scheme or host.
  • Mixed HTTP/HTTPS: Part of the flow uses HTTP and part uses HTTPS, causing cookie loss.

How to Fix It

Check hostname configuration:

# Verify KC_HOSTNAME matches what users see in the browser
KC_HOSTNAME=auth.example.com

# If behind a proxy, ensure proxy headers are configured
KC_PROXY_HEADERS=xforwarded

Check proxy headers:

Your reverse proxy must forward these headers:

X-Forwarded-For: <client IP>
X-Forwarded-Proto: https
X-Forwarded-Host: auth.example.com
X-Forwarded-Port: 443

Check cookies in the browser:

Open DevTools > Application > Cookies. Look for the AUTH_SESSION_ID and KEYCLOAK_SESSION cookies. If they are not being set, it is likely a SameSite or Secure flag issue.

Verify with the Keycloak logs:

# Set Keycloak log level to DEBUG temporarily
KC_LOG_LEVEL=org.keycloak.authentication:DEBUG

7. Token Expired

The Error

Your API returns:

{
  "error": "invalid_token",
  "error_description": "Token is not active"
}

Or in the application:

Token expired

What Causes It

Access tokens in Keycloak have a short lifespan by default (5 minutes for access tokens). If your application does not refresh the token before it expires, API calls will fail.

How to Fix It

Application-side (recommended):

Implement proactive token refresh. Refresh the token when it is close to expiring, not after it has expired:

// Refresh when 30 seconds remain
const tokenExpiresAt = decodedToken.exp * 1000;
const refreshAt = tokenExpiresAt - 30000;

if (Date.now() > refreshAt) {
  await refreshToken();
}

If you are using keycloak-js:

// Auto-refresh: refresh if token expires within 30 seconds
setInterval(() => {
  keycloak.updateToken(30).catch(() => {
    keycloak.login();
  });
}, 10000);

Server-side (adjust lifespan):

If your use case requires longer-lived tokens, adjust in Realm Settings > Tokens:

  • Access Token Lifespan: Default 5 minutes (increase cautiously)
  • Client Session Idle: Default 30 minutes
  • Client Session Max: Default 60 minutes

Decode and inspect your tokens with the JWT Token Analyzer to verify expiration times match your configuration.

For a deeper dive into token lifecycle management, see our guide on JWT token lifecycle management.

8. Realm Not Found

The Error

{
  "error": "Realm does not exist"
}

Or when accessing the login page:

Realm does not exist

What Causes It

  • Typo in the realm name in your application’s configuration
  • The realm was deleted or not yet created
  • Case sensitivity: Keycloak realm names are case-sensitive

How to Fix It

  1. Verify the realm exists in the Admin Console under Realm selector (top-left dropdown)
  2. Check the exact spelling and case in your application config:
# These are different realms:
KC_REALM=my-app    # lowercase
KC_REALM=My-App    # mixed case (different realm!)
  1. Verify the OIDC discovery URL works:
curl -s "https://auth.example.com/realms/my-app/.well-known/openid-configuration" | jq .issuer

If the URL returns a 404, the realm does not exist or the realm name is wrong.

9. User Not Found / Invalid Credentials

The Error

Invalid username or password.

In the logs:

ERROR [org.keycloak.authentication] invalid_user_credentials

What Causes It

  • User does not exist in the realm
  • User exists but is disabled
  • Wrong password
  • User account is locked due to brute force protection
  • User federation source (LDAP/AD) is unreachable
  • Required actions are pending (e.g., UPDATE_PASSWORD) but not rendered

How to Fix It

Check if the user exists:

curl -s -H "Authorization: Bearer $ADMIN_TOKEN" 
  "$KEYCLOAK_URL/admin/realms/$REALM/[email protected]" | jq

Check if the user is enabled:

In the Admin Console, go to Users > find the user > verify Enabled is toggled on.

Check brute force protection:

Go to Realm Settings > Security Defenses > Brute Force Detection. If enabled, check if the user’s IP is temporarily blocked. You can clear the user’s login failures:

# Clear brute force status for a user
curl -X DELETE -H "Authorization: Bearer $ADMIN_TOKEN" 
  "$KEYCLOAK_URL/admin/realms/$REALM/attack-detection/brute-force/users/$USER_ID"

Check LDAP federation:

If using LDAP federation, verify the LDAP connection:

  1. Go to User Federation > your LDAP provider
  2. Click Test Connection and Test Authentication

For monitoring login failures and security events, see our guide on Keycloak audit logs and auditing best practices.

10. CORS Errors

The Error

In the browser console:

Access to fetch at 'https://auth.example.com/realms/my-app/protocol/openid-connect/token'
from origin 'https://app.example.com' has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested resource.

What Causes It

The browser’s Cross-Origin Resource Sharing (CORS) policy blocks requests from your application’s domain to Keycloak because Keycloak has not been configured to allow requests from your origin.

How to Fix It

  1. Open the Keycloak Admin Console
  2. Go to Clients > select your client > Settings
  3. Under Web origins, add your application’s origin:
https://app.example.com

Or use + to allow all origins that match the configured redirect URIs:

+

Or use * to allow all origins (development only, never in production):

*

Important: CORS is evaluated per-client. Make sure you are configuring the correct client (the one your SPA uses, not a backend client).

If behind a reverse proxy, make sure the proxy is not stripping or adding its own CORS headers, which can conflict with Keycloak’s headers.

For a complete guide on CORS configuration, see our post on configuring CORS with your Keycloak OIDC client.

General Debugging Strategy

When you encounter a Keycloak error that is not in this list:

  1. Check the server logs: Set KC_LOG_LEVEL=DEBUG temporarily to get detailed output
  2. Check the browser DevTools: Network tab for HTTP responses, Console for JavaScript errors, Application tab for cookies
  3. Use the Admin Events: Go to Events > Admin Events or User Events in the Admin Console to see what happened
  4. Test the OIDC endpoints directly:
# Discovery document
curl -s "$KC_URL/realms/$REALM/.well-known/openid-configuration" | jq

# JWKS (public keys)
curl -s "$KC_URL/realms/$REALM/protocol/openid-connect/certs" | jq

# Userinfo (with a valid token)
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" 
  "$KC_URL/realms/$REALM/protocol/openid-connect/userinfo" | jq
  1. Decode your tokens: Use the JWT Token Analyzer to verify token contents, or the SAML Decoder for SAML assertions

Getting Help

If you are self-hosting Keycloak, the Keycloak documentation and GitHub Discussions are excellent resources.

If you want professional support and do not want to troubleshoot infrastructure issues yourself, Skycloak’s managed hosting includes monitoring, alerting, and support from a team that specializes in Keycloak operations. Visit our pricing page to learn more, or check our SLA for uptime guarantees.

Guilliano Molaire
Written by Guilliano Molaire Founder

Guilliano is the founder of Skycloak and a cloud infrastructure specialist with deep expertise in product development and scaling SaaS products. He discovered Keycloak while consulting on enterprise IAM and built Skycloak to make managed Keycloak accessible to teams of every size.

Ready to simplify your authentication?

Deploy production-ready Keycloak in minutes. Unlimited users, flat pricing, no SSO tax.

© 2026 Skycloak. All Rights Reserved. Design by Yasser Soliman