What Grafana version and what operating system are you using?
Grafana v11.x Enterprise deployed on Kubernetes using the kube-prometheus-stack
Helm chart. OS: Linux containers (Alpine-based).
What are you trying to achieve?
Enable OAuth login with Keycloak. Allow users to authenticate via username
(not sub
) and maintain consistent login behavior even after user recreation in Keycloak.
How are you trying to achieve it?
Using auth.generic_oauth
with the following configuration in grafana.ini
:
[auth.generic_oauth]
enabled = true
client_id = grafana
name = Keycloak
login_attribute_path = username
name_attribute_path = name
role_attribute_path = contains(resource_access.grafana.roles[*], 'grafanaadmin') && 'GrafanaAdmin' || contains(resource_access.grafana.roles[*], 'admin') && 'Admin' || contains(resource_access.grafana.roles[*], 'editor') && 'Editor' || contains(resource_access.grafana.roles[*], 'viewer') && 'Viewer' || 'NoAccess'
scopes = openid email profile roles
What happened?
OAuth login works fine initially. But if:
- I delete a user from Keycloak and recreate it (same username),
- Or I recreate the Identity Provider (IdP) config,
Keycloak assigns a new sub
claim, and Grafana throws a User Sync Failed
error—even though all other claims (username
, email
, etc.) are the same.
What did you expect to happen?
Grafana should match the user based on the configured login_attribute_path = username
, not on sub
. Recreated users with the same username should log in successfully.
Can you copy/paste the configuration(s) that you are having problems with?
See the relevant part of grafana.ini
above. Here is an example of the user info returned by Keycloak:
NA
And debug logs:
logger=oauth.generic_oauth level=debug msg="Getting user info from API"
logger=oauth.generic_oauth level=debug msg="HTTP GET" url=https://<redacted>/protocol/openid-connect/userinfo status="200 OK"
response_body="{\"sub\":\"...\",\"upn\":\"redact\",\"email_verified\":false,\"name\":\"redact\",\"preferred_username\":\"redact\",\"given_name\":\"redact\",\"family_name\":\"redact\",\"email\":\"redact\",\"username\":\"redact\"}"
logger=oauth.generic_oauth level=debug msg="Received user info response from API" data="Name: match, Displayname: , Login: , Username: match, Email: match, Upn: match, Attributes: map[]"
logger=oauth.generic_oauth level=debug msg="Processing external user info" source=token match
logger=oauth.generic_oauth level=debug msg="Setting user info name from name field"
logger=oauth.generic_oauth level=debug msg="Searching for login among JSON" loginAttributePath=username
logger=oauth.generic_oauth level=debug msg="Set user info email from extracted email"
Did you receive any errors in the Grafana UI or in related logs? If so, please tell us exactly what they were.
Yes. UI displays:
Login Failed
User Sync Failed
Grafana logs show debug-level details ending with User Sync Failed
.
Did you follow any online instructions? If so, what is the URL?
Yes. Followed:
Question:
Does Grafana internally depend on the sub
claim to identify users, even when login_attribute_path = username
is explicitly set?
If so, is there a recommended way to avoid this dependency so users recreated in Keycloak don’t get blocked by Grafana?