Auth0 Home Blog Docs

Rule doesn't add custom claims


#1

In my Node CLI I I use the auth0 package to call Auth0.

If I use the signIn method on the database login like this:

await this.authClient.database!.signIn({
username: email,
password,
connection: ‘Username-Password-Authentication’,
})

When I use this tool to decode the tool: https://jwt.io/
I get back a token which doesn’t contain the custom data I added via a rule, just the basic fields

{
“iss”: “https://mydomain.auth0.com/”,
“sub”: “auth0|5b6b2342j54355613fd40421”,
“aud”: “kcpmPE21Lc6nSJf36oneC5pxJ69Vs”,
“iat”: 1546061189,
“exp”: 1546097189
}

But when I use a password grant:

const asd = await this.authClient.oauth!.passwordGrant({username: email, password, realm: ‘Username-Password-Authentication’})

I get a token that decodes like this:

{
https://www.mydomain.com/meta”: {
“roles”: [
“ordinary”
],
“importantValue”: “17”,
“claims”: [
“admin”
]
},
“nickname”: “piersm”,
“name”: "piers@piers.com",
“picture”: “https://s.gravatar.com/avatar/74962f17942d8f13f13fde7af051eb90?s=480&r=pg&d=https%3A%2F%2Fcdn.auth0.com%2Favatars%2Fpi.png”,
“updated_at”: “2018-12-29T05:26:30.034Z”,
“email”: "piers@piers.com",
“email_verified”: false,
“iss”: “https://mydomain.auth0.com/”,
“sub”: “auth0|5b6b57f3e5439292923fd40421”,
“aud”: “kcpmPE21Lc6nSz5yFasateC5pxJ69Vs”,
“iat”: 1546061190,
“exp”: 1546097190
}

But I can’t specify the audience of that request so my backend API can’t decode the token.

I’m not sure I understand the difference of what I’m doing here that is causing this. Why are there different tokens? What’s the audience?


#2

Hi!
await this.authClient.database!.signIn uses the older (and deprecated) /oauth/ro to get the token result. /oauth/ro will not get the custom claims added, and also does not take an audience parameter (so the access token returned can’t be used to make requests to a custom API).

So, if you are using resource owner password grant (i.e. exchanging credentials for a token) you should be using the passwordGrant function, which uses the /oauth/token endpoint (the correct one to use in these cases).

But I can’t specify the audience of that request so my backend API can’t decode the token.

I’m not quite sure what you mean here, particularly because /oauth/ro does not take an audience parameter (/oauth/token does, on the other hand).
If you specify openid as the scope (which is the default value) you will get an ID Token (information about the user for the client application) and an Access Token (good to make requests to the /userinfo endpoint).
If you also specify an audience (an identifier of a custom API you created in the Auth0 dashboard), you will get an access token that is of JWT format, and can be used to make requests to your custom API. This is the token that you would usually use to authorize requests to the backend.


#3

I dug into the code a little. Bear with me here. There are 3 applications:

  1. React Web App
  2. Nodejs back end
  3. Nodejs CLI (new app I’m trying to get working)

Now the back end uses the following code (using the npm jsonwebtoken package)

decoded = jwt.verify(token, publicKey, {
  audience: config.authorizer.audience,
  issuer: config.authorizer.issuer,
  algorithms: ['RS256'],
});

To crack open the token and get the information stored in there (the stuff in the claims property from above).

Now there’s an Auth0 application for existing React web app. That web app uses the Client ID as it’s audience. Then the backend also uses that client ID to verify the token.

Since I created a separate application for my CLI (with a different Client ID) I now understand why calls made from the CLI to the backend are failing at that .verify() step.

So what’s the recommended way to handle this situation where a backend API has 2 different clients? Should they use the same Auth0 application? Should I use something else as the audience?


#4

The backend should be modeled as an API (https://manage.auth0.com/#/apis). When you create the API, you assign an identifier to it, which will be the audience to check for.

Then each client you define will need to request an Access Token to that API, by adding the audience={the_api_identifier} parameter in the token request. When you add the audience parameter, the client application will get an access token where the audience is that of the target API. Note that if you also specified scope=openid you will get an ID Token, which carries information about the user and is meant to be consumed by the client application directly.

So, in essence, you end up with one API and any number of clients (each with their own client ID) that can potentially request a token for the API. In the access tokens, the aud claims (audience) will be the API identifier. In the ID tokens, the aud will be the client ID.

Also, note that you will need passwordGrant method (not signIn), as /oauth/ro is not compatible with the audience and API authorization features. Or, even better, use an interactive authorization flow (/authorize) to avoid collecting the credentials directly in the react application.


#5

So I managed to get something working but it doesn’t align with what you laid out. I just want to clarify.

So here’s what I have. A node.js API and two clients a node CLI and a React web page. So everything is in javascript.

Here’s the web page client code. It was set up long ago and seems to work. It uses the auth0-js package

auth0 = new auth0.WebAuth({
domain: ‘mycompany.auth0.com’,
clientID: ‘SDFWR@#$GR@#$RSFD#@$F3214’,
redirectUri: ‘mycompany.com/callback’,
audience: https://mycompany.auth0.com/userinfo,
responseType: ‘token id_token’,
});

Then the CLI uses this (unfortunately it’s not easy to use the redirect logic). It uses the auth0 package

const authClient = new AuthenticationClient({
clientId: ‘nvbnfghf5t34567rhnfg54r674hgdf546s’,
domain: ‘mycompany.auth0.com
})

Now when I use both I get a token which I used the npm jsonwebtoken package to crack open as such

const decodedToken = jwt.verify(
  token!,
  functionToGetPublicKey(),
  {
    audience: CLIENT_ID for either above apps
    issuer: 'https://mycompany.auth0.com/',
    algorithms: ['RS256'],
  });

This works and I get the claims in the token I’m looking for provided I supply the right client id as the audience. However this is very different than what you’ve laid out.

  1. There’s no access tokens ( I have no idea where they come into play)
  2. Audience which is listed in my Auth0 dashboard as https://mycompany.auth0.com/api/v2/ isn’t used anywhere. Audience is only specified on the web client SDK and the API side decoding, there’s no mention of it in the CLI. The .verify() uses the client ID as the audience.

Do I have this wired up wrong?