Clarification on why auth0 seems to say id_tokens are less secure than access_tokens

Auth0 has a blog post outlining the differences between access_tokens and id_tokens.

In the post, it mentions a couple reasons why you shouldn’t pass an id_token to an API:

Furthermore, the id_token is signed with a secret that is known to the client (since it is issued to a particular client). This means that if an API were to accept such token, it would have no way of knowing if the client has modified the token (to add more scopes) and then signed it again.

Putting aside the other reasons to pass an access_token to the API, this part confuses me. Both tokens are issued and signed by auth0, correct? If the application is passing either token, couldn’t either of them technically be changed? I was under the impression that the signing token in both cases is the one that’s available under the Application settings in Auth0’s management counsel.

If that’s the case, what’s the difference between the two from a security standpoint? If it’s the case that a client has access to the signing/private certificate for the id_token, but not the access_token, I’m wondering why provide more access to the id_token.

1 Like

Hi @tnielsen

You are correct, I filed a bug with the docs team.

Thanks!

John

3 Likes

Good catch @tnielsen, that is indeed not how things work.

As for the difference between identity tokens and access tokens: it’s all in their meaning. An identity token contains information about the user’s authentication. It has an explicit target audience, which is the identifier client application. As a result, the API does not really have a way to know if that token is intended for that API.

Access tokens can have an API as the target audience. This audience is used by the API to verify that the token is indeed intended for that specific API.

Relying on scopes alone is not enough, because they are defined per API. So imagine the following scenario:

API1 has scopes “read” and “write”.
API2 also has scopes “read” and “write”.

An access token issued for API1 will have the following claims (among others):

  • aud: API1
  • scopes: read

An access token issued for API2 will have these claims:

  • aud: API2
  • scopes: read write

If you combine the scopes with the audience, you get a unique set of “permissions” for each API. If you would try to govern access with identity tokens, there is no way to represent such permissions, which would result in an authorization problem at the API-side of things.

In a nutshell, it is recommended to respect the meaning of the tokens. Identity tokens are consumed by the client, and access tokens are consumed by APIs.

Hope this helps!

Thanks for the follow-up on that @PhilippeDeRyck!