Role is not attached to user when using role_attribute_path for generic oauth

Hey guys,

I am trying to attach roles when users login using auth.generic_oauth. I am using Okta so wanted to know if there is something missing from her.

[auth.generic_oauth]
enabled = true
name = Okta
allow_sign_up = true
client_id = <client_id>
client_secret = <client_secret>
scopes = openid profile email
;email_attribute_name = email:primary
;email_attribute_path =
auth_url = https://<okta_url>/oauth2/v1/authorize
token_url = https://<okta_url>/oauth2/v1/token
api_url = https://<okta_url>/oauth2/v1/userinfo
;allowed_domains =
;team_ids =
;allowed_organizations =
role_attribute_path = contains(info.groups[], ‘admin’) && ‘Admin’ || contains(info.groups[], ‘editor’) && ‘Editor’ || ‘Viewer’
;tls_skip_verify_insecure = false
;tls_client_cert =
;tls_client_key =
;tls_client_ca =

Thanks,

Vignesh

Increase log level to debug and check logs. You will see all received tokens/userinfo details there, so you can verify it against used JMESPath.

1 Like

:roll_eyes: I didn’t ask you to post those details. I just give you hint how to debug it safely. You are exposing your identity and credentials. Not clever idea.

@jangaraj: i get the below error

t=2020-02-06T23:12:07+0000 lvl=eror msg=“Attribute not found when searching JSON with provided path” logger=oauth.generic_oauth attributePath=grafana_admin

t=2020-02-06T23:12:07+0000 lvl=eror msg=“Attribute not found when searching JSON with provided path” logger=oauth.generic_oauth attributePath=grafana_admin

I am just trying to figure out how the resourcePath is supposed to look like

Your input:

  • id_token and userinfo from logs (they are json)
  • role_attribute_path value

Both use on http://jmespath.org/ and test/evaluate your role_attribute_path value.

Note 1: use 6.6.0+ because you may need https://github.com/grafana/grafana/pull/20300
Note 2: you may need to configure your Okta OIDC client, because only you know what is returned by Okta IdP; maybe some details useful for authorization are not returned

Doc: https://grafana.com/docs/grafana/latest/auth/generic-oauth/#jmespath-examples

@jangaraj: Is this working in 6.5.x? If thats the case I can downgrade to that version?

Please read release notes.

I am using Okta OAuth2 as mentioned here https://grafana.com/docs/grafana/latest/auth/okta/. The example for using role_attribute_path points to https://grafana.com/docs/grafana/latest/auth/generic-oauth/#jmespath-examples But the example needs to be modified in the documentation. It should be

role_attribute_path = contains(groups[*], 'admin') && 'Admin' || contains(groups[*], 'editor') && 'Editor' || 'Viewer'

That is what worked for me.

2 Likes

I don’t agree. Each Identity Provider (IDP) can provide own custom payload in the access/id token. So your example will be valid only for Okta IDP users and very likely it won’t be valid for other IDP users. Also IDP administrator may configure custom payload, so there is no way where one example of role_attribute_path will cover all IDPs and all their configurations.

I would recommend to create PR with your example only to Okta doc. See https://www.youtube.com/watch?v=EP0dMMLP954

Hi folks,

I’m also using Okta OAuth2, and gopi1’s example seems like it should work because I can verify with the JMES tool on https://jmespath.org/ that the correct roles are being selected from the groups coming back from Okta, but I’m getting the following debug message, and my user is getting a role of “viewer” regardless of the group.

t=2020-10-21T23:11:46+0000 lvl=dbug msg="Syncing Grafana user with corresponding OAuth profile" logger=oauth
t=2020-10-21T23:11:46+0000 lvl=dbug msg="Syncing organization roles" logger=login.ext_user id=2 extOrgRoles=map[]
t=2020-10-21T23:11:46+0000 lvl=dbug msg="Not syncing organization roles since external user doesn't have any" logger=login.ext_use

But by my role_attribute_path is:

GF_AUTH_ROLE_ATTRIBUTE_PATH="contains(groups[*], 'umbra-admin') && 'Admin' || contains(groups[*], 'umbra-editor') && 'Editor' || 'Viewer'"

And I can see the correct groups in the following debug messages:

t=2020-10-21T23:11:46+0000 lvl=dbug msg="Received user info response" logger=oauth.okta raw_json="{\"sub\":\"00ut7ue3vvf5cThqF0h7\",\"name\":\"Rxxx\",\"locale\":\"US\",\"email\":\"rxxx@zxxx.com\",\"preferred_username\":\"rxxx@zxxx.com\",\"given_name\":\"Rxxx\",\"family_name\":\"Mxxx\",\"zoneinfo\":\"America/Los_Angeles\",\"updated_at\":1602698967,\"email_verified\":true,\"groups\":[\"umbra-admin\"]}" ...
t=2020-10-21T23:11:46+0000 lvl=dbug msg="OAuthLogin got user info" logger=oauth userInfo="&{Id:00ut7ue3vvf5cThqF0h7 Name:Rxxx Email:rxxx@zxxx.com Login:rxxx@zxxx.com Company: Role: Groups:[umbra-admin]}

What am I missing?

Nevermind, it was a typo :man_facepalming: I just noticed it was not appearing as a config override in the logs like the other auth overrides were.

For anyone else running into this, if you’re configuring Grafana via environment variables, the role_attribute_path key should be GF_AUTH_OKTA_ROLE_ATTRIBUTE_PATH not GF_AUTH_ROLE_ATTRIBUTE_PATH.

thought I’d just add this as it took quite a few hours to discover…

I followed current grafana keycloak instructions and its mentions creating clientId as grafana-oauth.
Short version… When you expose the roles in keycloak by going to the client scopes → roles → Mappers → client roles (ie enable Add to Id Token , Add to userinfo), the entry in the json returned by keycloak for roles will be in the format seen in the ‘Token Claim Name’ field and the default is ‘resource_access.${client_id}.roles’
Its will be returned in the userinfo api like

"resource_access":{"grafana-oauth":{"roles":["admin","Admin","grafanaadmin"]}}

The issue is that if you try to setup your role_attribute_path using ‘grafana-oauth’ like below, the JMESPATH query will fail as it does NOT like the - in granfan-oauth.

role_attribute_path = contains(resource_access.grafana-oauth.roles[], ‘grafanaadmin’) && ‘GrafanaAdmin’ || contains(resource_access.grafana-oauth.roles[], ‘admin’) && ‘Admin’ || contains(resource_access.grafana-oauth.roles[*], ‘editor’) && ‘Editor’ || ‘Viewer’

The simple fix is to use the underscore when creating the client Id ie “granfan_oauth”
then the role path can be specified like

role_attribute_path = contains(resource_access.grafana_oauth.roles[], ‘grafanaadmin’) && ‘GrafanaAdmin’ || contains(resource_access.grafana_oauth.roles[], ‘admin’) && ‘Admin’ || contains(resource_access.grafana_oauth.roles[*], ‘editor’) && ‘Editor’ || ‘Viewer’

Hope this helps. Took my hours to figure out that it was a JMESPATH query issue.

FYI… Its helpful to turn logging = debug as you can see the info returned from the get userInfo api. you can then see how you need to structure the role_attribute_path JMSEPATH query.