Enterprise Java

Integrating Auth0 OIDC (OAUTH 2) with authorization (groups and roles)

If you’re using Auth0 to authenticate and authorize your users across several existing applications, you may want to integrate your next web application with Auth0.

There are several ways to do that, for example, if you want to integrate Jenkins with Auth0, you could use SAML v2; this blog post explains it pretty well.

If your application does not support SAML v2 or make it an enterprise paying feature you could want to use the OAuth2 (or OIDC) integration.

Let’s take the example of the Open Source monitoring solution Grafana, and let’s integrate it with Auth0.

Authenticate Grafana users with Auth0: just read the documentation

The official Grafana documentation will explain you how to:

  • set the root_url option of [server] for the callback URL to be correct
  • create a new client in Auth0, set the allowed callback Urls to https://<grafana domain>/login/generic_oauth
  • configure Grafana with a similar configuration:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
; not mandatory, but super useful to debug OAuth interactions with Auth0
[log]
level = debug
[server]
root_url = https://<grafana domain>/
[auth.generic_oauth]
enabled = true
allow_sign_up = true
team_ids =
allowed_organizations =
name = Auth0
client_id = <client id>
client_secret = <client secret>
scopes = openid profile email
auth_url = https://<domain>/authorize
token_url = https://<domain>/oauth/token
api_url = https://<domain>/userinfo

The problem is… you won’t get any type of authorization with that; all your Auth0 users will be able to login to Grafana, but will be assigned the Viewer role by default. That’s because Grafana needs to receive extra information about the role of the logged in user from Auth0.

1
2
3
t=2020-04-14T11:39:03+0000 lvl=dbug msg="Received user info response" logger=oauth.generic_oauth raw_json="{\"sub\":\"auth0|5e87486a85dd980c68d912c4\",\"nickname\":\"anthony\",\"name\":\"anthony@host.net\",\"picture\":\"https://s.gravatar.com/avatar/79033b96a632e4ea71b59fe9554c53a2?s=480&r=pg&d=https%3A%2F%2Fcdn.auth0.com%2Favatars%2Fan.png\",\"updated_at\":\"2020-04-14T11:39:02.862Z\",\"email\":\"anthony@host.net\",\"email_verified\":false}" data="Name: anthony@host.net, Displayname: , Login: , Username: , Email: anthony@host.net, Upn: , Attributes: map]"
t=2020-04-14T11:39:03+0000 lvl=dbug msg="User info result" logger=oauth.generic_oauth result="&{Id: Name:anthony@host.net Email:anthony@host.net Login:anthony@host.net Company: Role: Groups:]}"
t=2020-04-14T11:39:03+0000 lvl=dbug msg="OAuthLogin got user info" logger=oauth userInfo="&{Id: Name:anthony@host.net Email:anthony@host.net Login:anthony@host.net Company: Role: Groups:]}"

If you look at the Grafana debug logs above, you’ll see that the user was logged in, but since no role was mapped, the user was assigned the Viewer role

Authorization in Auth0: install the extension, then set groups and roles

In Auth0, you first need to add the Authorization extension, you’ll then be prompted to configure the extension:

Once it’s done (make sure to enable Groups and Roles, and then to Rotate and press publish rule) you can then create some groups

You can then add a user to the Admin group

If you go back to Auth0, more precisely the rules panel, you’ll see that the extension added and activated a new rule:

Unfortunately, this is not enough: we need to have Auth0 enrich the userinfo it sends back to Grafana; in the previous chapter, we saw the Grafana debug logs showed to us:

1
2
3
4
5
6
7
8
9
  {
    "sub": "auth0|5e87486a85dd980c68d912c4",
    "nickname": "anthony",
    "name": "anthony@host.net",
    "updated_at": "2020-04-14T11:39:02.862Z",
    "email": "anthony@host.net",
    "email_verified": false
  }

So to enrich this json object with group info, we need to create another rule, that will enrich the user profile; let’s create a new rule (I’ve named it add-groups) and add the following code:

1
2
3
4
5
function addAttributes(user, context, callback) {
  const namespace = 'https://dahanne.net/';
  context.idToken[namespace + 'groups'] = user.groups;
  callback(null, user, context);
}

We should now have 2 rules applied to our Auth0 tenant:

If you log back in to Grafana now, you won’t see any change to your Grafana profile; but if you look at the logs, in particular at the raw_json from the userinfo object, you’ll notice a new field that was added by our rules:

01
02
03
04
05
06
07
08
09
10
11
12
  {
    "sub": "auth0|5db0908a8bc0400c5c05604e",
    "nickname": "anthony",
    "name": "anthony@host.net",
    "updated_at": "2020-04-13T22:49:58.965Z",
    "email": "anthony@host.net",
    "email_verified": true,
      "Admin"
    ]
  }

Now we need to instruct Grafana how to read this new field and use it to assign a group to our user profile.

Back to Grafana, use JMESPath to retrieve the user role from Auth0 response

We’ll need first to read the documentation for Grafana JMESPath

From the documentation, we can deduct that we need such a mapping:

1
role_attribute_path = contains("https://dahanne.net/groups"[*], 'Admin') && 'Admin' || contains("https://dahanne.net/groups"[*], 'Editor') && 'Editor' || 'Viewer'

Now, if you log back into Grafana, and have a look at the debug logs, you’ll see the new field from Auth0:

1
lvl=dbug msg="User info result" logger=oauth.generic_oauth result="&{Id: Name:anthony@host.net Email:anthony@host.net Login:anthony@host.net Company: Role:Admin Groups:]}"

And of course, your user profile in Grafana is now updated:

Final words

While the authentication integration is well documented, I had trouble figuring out the authorization part… At first, I tried enriching the user object in the Auth0 rules, but only enriching the context idToken would work (thanks to my colleague Brett for helping me out with that); and even more, the namespace being an URL is mandatory too!

On the Grafana side though, everything worked pretty well out of the box; the debug logs were really helping!

Published on Java Code Geeks with permission by Anthony Dahanne, partner at our JCG program. See the original article here: Integrating Auth0 OIDC (OAUTH 2) with authorization (groups and roles)

Opinions expressed by Java Code Geeks contributors are their own.

Anthony Dahanne

Anthony Dahanne is a Java software developer for 8 years, his favorite topics are Android, building tools, Continuous Integration and, of course, core Java development. Working for Terracotta, he currently implements the REST management interface for EhCache.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button