Why can't an id_token be used to authenticate an API

Let me preface this by saying I am using Google Cloud Endpoints Framework in Java (Which is supported by auth0 and Cloud Endpoints). In this framework the JWT Token that is passed must contain an email claim , if it does not then the backend doesn’t get called. Unfortunately the access_token that auth0 provides does not have a email claim. I could add a namespaced email claim to this token using rules however I don’t have access to change Googles codebase which they are hosting so it would never pick up this custom claim.

Whilst I could send a id_token which contains a user and this authenticates correctly I would like to know why you recommend against it.
I see the main argument is that

the id_token is signed with a secret that is known to the client (since it is issued to a particular client)

However as my client or application is a SPA which uses PKCE I don’t believe the client would have knowledge of the secret. If this is the case, then why can I not provide the id_token to authenticate?

In the google doc I beleive this is what it suggests Authenticating users  |  Cloud Endpoints Frameworks for App Engine Notice they say to set the audience to check for to be the client ID - not the custom API.

Hi @daniel10,

The short answer here is that ID tokens are for authenticating a user and access tokens for authorizing access to an API. ID tokens are meant for the client only, access tokens the API only. ID tokens do not authorize the user to access an API and trying to use them as such is an abuse of their purpose.

That said, people abuse ID tokens and access tokens all the time, in part because, at least until very recently, there was no standard for JWT formatted access tokens. I am not suggesting anyone start abusing tokens in this way, just pointing out that it does happen. There is now a standard for JWT formatted access tokens but who knows how long it will take for vendors to implement it:

https://tools.ietf.org/html/draft-ietf-oauth-access-token-jwt-12#section-2.2

1 Like

Thanks for the reply @markd. I really want to follow the proper standard and pass through an access token, but the jwt access token must contain an email for Google to accept the token. I understand it’s abusing it but would there be any security implications about using this id_token? As long as I’m confident that the token is issued by auth0 and not modified, I’m happy to trust it.

Identity wizards will likely balk at it but I don’t think there any significant harm, especially given this is all “in house” (not using ID tokens with a 3rd party API). That said, I’m definitely not an expert in the potential security implications here.

I’d also suggest submitting a feature request to Auth0 at the link below. Considering the Author of that new spec is Auth0’s own identity guru, I would hope Auth0 implements the new spec relatively quickly so we can have a “root” email claim in the AT! :slight_smile:

2 Likes

Hi @daniel10,

So it turns out you can add non-namespaces claims to the access token, meaning you can add a “root” email claim. This example Rule adds email twice, as a root email claim and with a namespace:

function addEmailToAccessToken(user, context, callback) {
  var namespace = 'https://example.com/';
  context.accessToken[namespace + 'email'] = user.email;
  context.accessToken.email = user.email;
  return callback(null, user, context);
}
.
.
.
  "accessToken": {
    "https://example.com/email": "jdoe@foobar.com",
    "email": "jdoe@foobar.com"
  },
.
.
.
1 Like

Hi @markd

Did you have to enable any settings to get that working? I have tried that rule, in the save and try inside the context object i can see the access token like that

  "accessToken": {
    "https://example.com/email": "jdoe@foobar.com",
    "email": "jdoe@foobar.com"
  },

But when I get a token issued and decode it the root email claim is missing.

Please remember to reference the best practices for tokens documentation at Token Best Practices especially the part about not including sensitive information in the access token payload. This is an access token can be easily decoded, for an example take any existing access token and use https://jwt.io/ to see it decoded. Instead, you might want to leverage the /userinfo endpoint (see Authentication API Explorer ) together with an access token to retrieve any additional information you might require about the user to complete operations. You can also use rules to store and retrieve any additional data using the user_metadata field (see Metadata) as part of your custom logic.

1 Like

Hi @daniel10. I had the same problem. It appeared to work with the “try this rule” button but I could not get it to work in Postman. It turns out the ability to create non-namespaced claims is a private beta feature at the moment. If you have an account manager / TAM you can request access through them.

1 Like

Yep that is correct!