Getting UserInfo using the Access Token

Hi

I have the following scenario.
A single page Angular 6x App calling the Auth0 to authenticate. Then it calls the User info and obtains the role of the User.
This works fine as documented in the link Authentication API Explorer

Now I need to call the API server using this access token which is in node.js and uses express. I was able to do the same and the token is received in the API server, I was able to validate the token.
Since I need to know the user’s role which is not present in the access token, I need to call the UserInfo that was done on the web app in the api server . I tried call the following url https://[myclientid].auth0.com/userinfo and passing the obtained access token in the header. What ever I do, it says Unauthorized.

I need to know what’s inside webAuth.client.userInfo(authResult.accessToken, function(err, user)) so that I can make the call manually using an existing token.

How do I use the token obtained from the web app to call the user info to obtain the user role?

If the flow is not correct, can I obtain the correct way to do this?

3 Likes

Can you provide the code you’re using, removing any sensitive info?

It a simple https get call, as of now I am using Insomnia similar to postman to try to get the userinfo.
The url is as mentioned before and the headers contain Bearer and AccessToken obtained from the Web Server.

I would like a code sample like this which obtains the access token to either get or post passing the existing Bearer token and obtain the userinfo

function getAccessToken(req, res, next){
  request
    .post('https://YOUR-AUTH0-DOMAIN.auth0.com/oauth/token')
    .send(authData)
    .end(function(err, res) {
      req.access_token = res.body.access_token
      next();
    })
}

Hey there @pulsemagic18!

Sorry for such delay in response but we were people-resources constraint in the meantime and weren’t able to provide you with the level of support and knowledge you require. Thanks for understanding!

Let me know if you managed somehow to achieve what you want or if I need to dig into it further!

Hey!

Have you had a chance to see my last message? Can you let me know whether you still require help!

Thanks a lot for that!

Providing context from another customer

Basically here is my scenario:

  1. Android app login and gets barter token with audience for out JAVA API audience: https://*****.herokuapp.com
  2. Android app requests userProfile via “auth0.domain”/api/v2/ with this token and get’s unauthorized
  • But all requests to our API with this token are working fine
    When we do a login and specify a different audience: “auth0.domain”/api/v2/ we are able to access userProfile, however now our API server is not authorized.

Tried so many different configurations, but can not figure our how to get one token to access both: userProfile and our API from an Android app.

1 Like

I’ll be looking into it shortly!

@konrad.sopala Thank you and we are looking forward for your reply and if you need any clarifications/additional info, please let me know.

Hey there @alexiceman! Researched your case a little further.

Few things to check:

  • Check that API audience is correct (From your frontend- > Backend )
  • In your backend, you should execute client credentials grant type to obtain a Management API token and use that token to call Auth0 API

@konrad.sopala
Thanks for looking into this

  1. As I’ve explained when I use my API server audience "https://**.herokuapp.com", the token I get works perfectly with my API, but doesn’t work with auth0 v2 management api: https://-dev.auth0.com/api/v2/users/
  • If I use Auth0 audience https://***-dev.auth0.com I am able to pull user profile, but I am not able to access my API server
  1. It would make sense to go directly to auth0 is we are using this service to store user data.
    So you are offering that we use auth0 for authentication, then use our own server to call auth0 api to retrieve user data and pass it back to the app? With all honesty it seems like a very poor design and on top of that we are adding workload to our server to pass through information. It feels like I should be able to add permissions to access Management API to my custom audience and use that token to pull userProfile without any problems, or at least have the ability to return the full user profile upon authentication, this way we don’t have to make 2 extra calls to pull a user profile.

Please confirm if using out API as a pass through replay to pull userProfile is the only way you suggest to implement this proper architecture? OR is there any other visible way to login on Android and get a full user profile from auth0 without using out internal API?

Thank you.

@konrad.sopala any updates?

Hi Alex,

I’m trying to understand the correct way to secure my API using Auth0 and I found your post which seems somewhat similar to the issue I’m having (at least in terms of my understanding the flow). I’m building a chat application that makes requests against my Auth0-secured NodeJS-based API.

My users authenticate against Auth0 and get both an access token and an ID token. My app in Auth0 is set up as machine-to-machine (I’m not positive this is correct). The access tokens my users get look something like this:

{
  iss: 'https://auth0_account_redacted.eu.auth0.com/',
  sub: 'auth0|59f091cee40_my_ID_redacted',
  aud: [
    'https://my_domain_redacted.com/api',
    'https://auth0_account_redacted.eu.auth0.com/userinfo'
  ],
  iat: 1589809948,
  exp: 1589896348,
  azp: 'd8mQsZ7khKj313slB_app_ID_redacted',
  scope: 'openid profile'
}

And the ID tokens looks like this:

{
  'https://my_site_id/roles': [ 'admin' ],
  'https://my_site_id/claimspermissions': [
    'create:post',
    'read:post',
    'some:other',
    'scopes:below'
  ],
  'https://my_site_id/claimsgroups': [ 'admin' ],
  'https://my_site_id/claimsroles': [ 'admin' ],
  nickname: 'tom',
  name: 'tom@my_email_domain.com',
  picture: 'https://s.gravatar.com/blah.png',
  updated_at: '2020-05-18T13:52:26.281Z',
  iss: 'https://auth0_account_redacted.eu.auth0.com/',
  sub: 'auth0|59f091cee40_my_ID_redacted',
  aud: 'd8mQsZ7khKj313slB_app_ID_redacted',
  iat: 1589809948,
  exp: 1589845948
}

I then use the access token to call the Node API. The API validates the token and then either grants access to the resource (in this case, posting a message) or it doesn’t. This all works fine.

What I’m not understanding is how, if I use the access token and not the ID token, I get the username and be sure it’s what it should be (the username in the access token - the sub field - is the Auth0 database ID and not the actual username).

The answer seems to be that my API should call the Auth0 userinfo endpoint, passing it the access token, which will return the username and other info about the scopes allowed (and that does indeed work). But that means I’ll end up making three requests to Auth0: one to log the user in and get tokens in the first place, and then two more requests each time they access the API - once to validate the token, and then again to get the username. As you say, this seems like quite a lot of work, and if the app is very busy means I’m going to be making a lot of calls to Auth0 (unless I’m supposed to cache the userinfo in my app?). If I used the ID token, which I do seem to be able to verify, I could just take the username directly from it.

Perhaps I’m not understanding the process flow correctly, and I either have it right and it does require that extra step to get the username, or I’m expected to cache usernames somehow? I’d be grateful for any pointers.

Thanks very much.

Edit: I’m almost positive I’m simply not understanding how this is supposed to work. I’ve read lots of tutorials, but I don’t seem to be getting it. :frowning:

1 Like

@tomc So far what you’ve described makes sense and we have the same issue. @kanrad.sopala has been very helpful and he is even reaching out to the dev team to dive us a proper solution.

Basically you are right and it’s really overloading servers by adding 2 extra calls to fetch userinfo. But we are still waiting to hear back from @konrad.sopala and the dev team.

I really hope there is a way to include both audiences into API our custom API and Auth0 Management API. So far we weren’t able to successfully use both with one token and we have to do the same trick as you do, use our API server for passthrough (using a separate m-to-m token to access management API from our backend)

@alexiceman Thanks very much for getting back to me. Seems quite an odd system, which is why I was so sure I’m doing it wrong. Reading your post again, while the app I’m building is currently only being used by a client web application, the intention is that there’ll be an Android app also talking to it in the future, so I think we’re trying to achieve roughly the same kind of thing.

Something I thought I could do to remove roundtrips to Auth0 would be to simply not do explicit verification and rely on the result of the call to userinfo that my API code makes. So the user logs in, and they get their tokens. They then send the access token along with their request to my API, and the API hits userinfo and if that succeeds, they’re verified. I suppose it’s not much different really - I’m just not calling the “verify” method in my JWT library, and that makes it feel a bit like a hack.

In my case, if the access token contained the username, I’d probably not have looked into it further, but I’ll be interested to hear what the correct solution is so it’s good to hear that @konrad.sopala is looking into it. I look forward to hopefully hearing more.

Thanks again for taking the time to reply.

@alexiceman Hey Alex,

I’d be interested to hear your - and the community’s - feedback on an approach I’ve implemented. I’m not sure it’s quite the right way to do things, but it certainly seems to work and appears to be a reasonable way forward.

As before, my users log in to my application using Auth0 against a machine-to-machine application and receive an access token as usual. They then make AJAX requests to my API, which itself is protected by Auth0 using the same application, passing the access token they received when they logged in. At this point, my API needs to validate the token has the correct permissions, which it does by making a request to the Auth0 userinfo endpoint using that same token (the response from userinfo contains the permissions associated with that token). Depending on the response, my API then either grants access or doesn’t.

As we discussed previously, this means a call to the userinfo endpoint for every request to my API, which is pretty inefficient. To avoid this, I store every token passed to my API in a local cache (Redis), with the key being the “sub” field in the access token, which is the Auth0 user ID associated with that token, and the value being the response back from Auth0 for that token that contains the claims. I set an expiry of five minutes on the cached token. On each client request, my API first checks the cache for a token for that user ID and if one exists, validates the request against that rather than hitting userinfo. This means that for any individual token, my API will only ever make a call to Auth0 once every five minutes.

One possible issue I can see here is if the permissions associated with that user are updated and they end up with a different token, it could be five minutes before they get an updated token. I could get around that by implementing a feature to remove all cached tokens for any particular user ID, or flushing tokens on an update, but I’m more likely to just live with it and accept that people may have to wait up to five minutes for updated permissions; peoples’ permissions being changed is something of an edge case in my scenario.

It seems like a reasonable solution - and it certainly works - but I’d be very grateful for your (or anyone else’s) feedback.

Cheers.

Edit: the stats are quite nice. I’m using Fastify and it records the time taken for each request. On the initial requests when it hits Auth0, a request can take up to 300ms. Each subsequent request for the next five minutes takes under 10ms. :slight_smile:

I’m having the same issue.
Any update on a more efficient solution to this which doesn’t require back-end calls?

2 Likes