How to add custom user claim to access token for API? (Authorization Code Grant)

I have a Regular Web App and an API. Both are secured through JWT. In my web app, I modified the identity token with Auth0 rules to add some custom claims. Essentially I add if the user will be an administrator or not.

When I access my user claims in my web app, I get all regular claims + my custom claims. In my web API, I want to be able to access these custom claims. When I call my API from my app, I sent the access token in an authorization header. But all the user claims are lost and only the claims in the access token are present (i.e. issues, audience, etc.). How do I also pass my claims from the identity token? Or can I even just add a custom claim to the access token?

I know I can just create an object from my application and call the API with these values. But I wanted to know if there was a more secure way of sending this data over. I do not want a regular user who is authenticated to potentially fake this data to be sent.

My regular web app uses Authorization Code grant to get both an access token and a refresh token for my API. The API is secured through both basic authentication and also policy based authorization for specific actions. The reason I can’t use a policy in this case is because I need to check if the access token has an administrator claim in some logic for my API.

How would I go about doing this? Is there an example I could follow to add the custom claim to the access token used to call my API?

1 Like

Hi VR1020. You can add custom claims to the access token pretty much in the same way as you do it for the ID token:

function(user, context, callback) {
  context.accessToken['https://acme.com/claims/role'] = 'admin';
  callback(null, user, context);
}

The access token includes the sub claim containing the user_id so theoretically the API could decide authorization based on that alone (fetch the user role based on the sub).
Using authorization information in the access token as an optimization is fine as long as the implications are clear. Following the previous example, if the user’s admin privileges are removed and the API only uses the token information for authorization policies, then the user will be able to perform admin actions until the token expires.

1 Like

Thanks! I added the custom claim to my access token and am able to access the custom claims for the token in my API. Only one user will be an admin and I’ll be using policy based authorization for all other functionality.

You mentioned that the sub claim should exist in the access token but when I list all the claims out, I don’t see it. I see the custom claim that I added, iss, aud, iat, exp, scope, azp, and the schema (I am using google social to log in). But I don’t see a sub claim at all. Is this an issue with how I set up getting an access token?

Is this because I am using a social login that the registered claim is missing?

The sub claim should be there even when using social providers…

Are you inspecting the token directly, or are you looking at the claims provided by your API SDK? Not sure what you are using on the back end but maybe there is some kind of transformation going on (like the sub ending up in a user property or something).
Can you get the full access token as returned by the code exchange and decode it in https://jwt.io?

You are right. There is a transformation taking place.

I am using the API SDK to access the claims instead of accessing the token directly. I am using Asp.net core 2 for my back end so its transforming the sub property to a claims/nameidentifier (when I loop through User.Claims) .I decoded it in jwt.io and I see the sub claim in it.

One last question I had was that Auth0 rules execute whenever a user authenticates. Is it possible to limit the rule execution to a specific Web App / API? I didn’t see anything that stood out in the rules configuration. Is it possible to specify that the rule can only execute when the application ID is XYZ as opposed to any application requesting authentication?

You can use context.clientID or context.clientName for this type of logic:

// only run for a specific client ID
if (context.clientID !== 'my_special_app_id') {
  return callback(null, user, context);
}
[...] //otherwise continue

The API is a little tricker because you’ll have to check for the audience, which is not on the context, but you can get it from the request body/query string:

var requestedAudience = context.request.body 
  ? context.request.body.audience
  : ( context.request.query ? context.request.query.audience : null);
if (requestedAudience !== 'your_API_identifier') {
  return callback(null, user, context);
}

(hopefully I’m writing the JavaScript correctly, I didn’t test it but hopefully you get the idea).

2 Likes

Thank you! I was able to get it to work with the web application with the client ID check. For the API its not working yet but I’ll play around with the function to verify what the correct check is. Thanks for all the help!

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.