API access to user information

I have a SPA client and an API. The SPA client can successfully get an API access_token and the API correctly validates it. However, all the API sees is the content of the JWT:

  "iss": "https://mozilla-dustin.auth0.com/",
  "sub": "google-oauth2|105883044168332773236",
  "aud": "https://taskcluster-login.ngrok.io",
  "azp": "l23BM36nbr3pUHBkwWqjCrYLiqV3YG3n",
  "exp": 1491272326,
  "iat": 1491265126,
  "scope": "credentials:get"

I’d like to get information about the user making the request. I’ve tried using the Auth0.js auth0.client.userInfo method, passing the Authorization header content (the API access_token), but I get 401’s from the auth0 API.

I think I see why this is the case: the JWT azp claim is the client, so while the API can validate it, the API is not allowed to use the token to call the auth0 API.

(The motivation is that access control to the webapp is much more fine-grained than a finite list of scopes allows, and requires access to the user’s identity, groups, etc.)

The behavior of the scope parameter has also changed to conform to the OIDC specification. Instead of requesting arbitrary application-specific claims, clients can request any of the standard OIDC scopes such as profile and email, as well as any scopes supported by a resource server.

If custom claims are desired, these will need to be added to the token via a rule, and conform the the namespaced format, e.g:

function (user, context, callback) {
  const namespace = 'https://myapp.example.com/';
  context.accessToken[namespace + 'favorite_color'] = user.favorite_color;
  context.accessToken[namespace + 'preferred_contact'] = user.user_metadata.preferred_contact;
  callback(null, user, context);

More information is available here: OpenID Connect Scopes

1 Like

So, if I understand correctly, I would need to include the user profile – or at least, the bits of it that I need – as scope claims in the JWT? In that case, it sounds like I should include the minimal user identifiers (github username, google email, corporate email, etc.) as claims, and then my API should call those individual services to get the additional information – otherwise I might end up with a too-large JWT.

At which point, Auth0 isn’t providing me much value, as it’s only doing authorization and leaving me to do the authentication myself.

@dustin where are you storing the user information? Is it in a custom database? I am going to have a similar setup where I shall need some additional info to be passed to API.

I’d like to store it in auth0, where I can allow users to link mutliple accounts (google + github, for example), and get the totality of the user profile from auth0 so I can make an authorization decision.

@dustin How about the following scenario? Use auth0 without a custom database, but include post creation hooks to have the users created in your database. This way you will be able to get the data out of your profiles table.

This is already supported by our new Hooks feature. We currently have 3 extensibility points (including Post User Registration), with more to be added. Take a look at the following docs which outline our new Hooks feature, as well as the Post User Registration extensibility point.

The reason for the limited claims returned in the id_token is to conform to the OIDC specifications, outlined here: Final: OpenID Connect Core 1.0 incorporating errata set 1. In saying that, as mentioned, you can add custom, namespaced claims through Rules.

…as it’s only doing authorization
and leaving me to do the
authentication myself.

I don’t quite understand this. Auth0 is still authenticating your users as before - the only change is that the returned id_token now contains only OIDC conformant claims (or additional claims added via a rule).

That involves replicating data out of the auth0 database, though. And if that data in auth0 changes, how would my profiles table get updated?

Not sure how your profiles are created, in my case it is a separate table, with as foreign key to users table. And I populate the profiles table in a separate from auth0 routine. I guess, question here what should be considered as a profile, in my case basic info, such as name, email etc goes to users table and role, privileges, experience goes to the profiles table.

I don’t have a profiles table – the service has no database at all. It looks at the user information on login, and makes access-control decisions on that basis (it uses a signed token to avoid re-checking that on every request).

OK, I did this wrong – I was trying to boil down the question to its essentials, but the answers I’m seeing indicate I’ve left out some important context . I have an existing API with a complex authorization system using time-limited credentials. What I want to build is a way for users to get credentials appropriate to their profile (group membership, etc.) by way of auth0. The next time they login, they may have different group membership, so I can’t simply cache their information at registration time (the hooks solution). And I need to see most of the auth0 profile, …

… so it’s too much information to pack into the JWT. The getUserInfo call seems like it would give me what I want, but I don’t think my API is allowed to use that method.

I suspect I’m looking in the wrong place, and that I don’t want to use an Auth0 “API” for this purpose.

Your use case is different, so probably you need to follow different path.

@dustin I don’t see how you expect to get information for the Auth0 user profile, without using an Auth0 API? Our Management API v2 already the GET /users endpoints which could satisfy your requirements:

The approach was correct – the /userinfo endpoint takes an access token and returns user information. However, it only does so if the access token was generated with the openid scope (which adds an additional audience claim to the token). Once I added that scope, everything fell into place. Having added openid, the email scope now causes /userinfo to return the user’s email.

Per The /userinfo endpoint returns 401 (Unauthorized) - Auth0 Community in fact this openid scope is required as well as the API using RS256, and it adds the https://<domain>/userinfo audience, which is what /userinfo is checking for.