SECURITY WARNING: Never run commands you don't understand. Always review code before execution. Use at your own risk.
Auth New Added 26 October 2026

Keycloak: Invalid token issuer. Expected 'http://keycloak:8080/realms/myrealm'

The token's iss claim comes from whichever hostname the client used to reach Keycloak, and something later checked it against a different one. The classic case is Docker Compose: the browser logs in through http://localhost:8080, the backend validates against http://keycloak:8080, and the two never match although they are the same server. A reverse proxy that does not pass X-Forwarded headers splits http from https the same way. Giving Keycloak a fixed public hostname makes every token carry one issuer.

Quick fix

Read the commands before running them. Anything that restarts a service, deletes data or changes permissions should be tried on a non-production system first.

Quick fix
# Decode the token and read iss (inspection only, nothing is verified)
echo "$TOKEN" | cut -d. -f2 | tr "_-" "/+" | base64 -d 2>/dev/null; echo

# What issuer does Keycloak advertise from where the backend calls it?
curl -s http://keycloak:8080/realms/myrealm/.well-known/openid-configuration | grep -o '"issuer":"[^"]*"'

# Keycloak 25+: pin the public URL so every token has the same issuer
# KC_HOSTNAME=https://auth.example.com
# KC_HOSTNAME_BACKCHANNEL_DYNAMIC=true   # backend may still use http://keycloak:8080
# KC_PROXY_HEADERS=xforwarded            # behind a TLS-terminating proxy

# Local Compose shortcut: make "keycloak" resolve on the host as well,
# then log in through http://keycloak:8080 in the browser too
echo "127.0.0.1 keycloak" | sudo tee -a /etc/hosts

How to diagnose Auth errors

Identity errors are almost always configuration mismatches between two systems rather than code bugs: a redirect URI registered with a trailing slash, a client secret that was rotated on one side only, a clock that has drifted past the token skew allowance. Because the identity provider deliberately returns vague errors to avoid leaking information to attackers, the provider's own log is usually far more informative than the message your application receives.

If the quick fix above does not resolve it, work through these steps. They apply to this whole class of error, not just to this one message, which is usually what saves the time.

  1. Open the identity provider's log or event stream first. Auth0, Okta and Keycloak all record a detailed reason that they never send back to the client.
  2. Compare the redirect URI byte for byte, including scheme, port and trailing slash. http://localhost:3000/callback and http://localhost:3000/callback/ are different URIs.
  3. Decode the token rather than guessing. Paste it into a local JWT decoder and check iss, aud, exp and nbf, never a remote paste site, because tokens are credentials.
  4. Check clock skew with timedatectl or ntpq -p. Kerberos, SAML and JWT all reject tokens outside a tight time window, and a drifting VM clock produces intermittent, unreproducible auth failures.
  5. For passkeys and WebAuthn, verify the Relying Party ID matches the origin exactly and that the page is served over HTTPS or on localhost. Nothing else is a secure context.

Tools worth reaching for

  • Provider audit logs
  • jwt decoding (locally)
  • openssl x509 -noout -text
  • browser devtools network tab

Authoritative references

Primary documentation for this error, worth reading before applying any fix in production.

keycloak.org keycloak.org

Related Auth errors

See all 20 Auth errors →

Browse other categories

Something missing or wrong?

This entry is maintained by hand. If the fix is out of date, incomplete, or you have a better one, email a correction and it will be reviewed.