I’m building a system that is using Auth0 for authentication, and I’m unsure how to properly use the id_token
and access_token
. Or rather, I’m confused about which roles to assign to the various services in my setup.
I have a fully static frontend-application (SPA, HTML + JS) that ensures that the user is authenticated using the implicit flow against Auth0. The frontend-application then fetches data from an API that I am also building. Is the frontend the OAuth client, and my API service an OAuth protected resource, or are both the frontend and the backend API together the client?
If both my frontend and backend API can be considered to be the client, I see no real harm in using the id_token
as the bearer token on requests from my frontend to my backend - this is appealing because then I can simply verify the signed token on the backend, and I have all the information about the user that I need. If the API is considered a protected resource, I should probably use the access token, but then I have to connect to Auth0’s servers on every API request to both verify the token, and get basic user info?
I’ve read this: Access Tokens which seems to suggest that the access_token
is the only valid token for use with my API. But like I said, I’m not sure about the roles of the individual services. And using the id_token
is tempting, because it requires no network connections on the backend, and contains information I need to extract the right data.
What is the right way to go about this?
1 Like
In your described scenario the SPA is an OAuth2 client application and the backend API is an OAuth2 resource server. The way you map this to Auth0 configuration is by:
- creating a client application record in the Clients section of your dashboard to represent your SPA (ensure you set the correct client type).
- creating an API record in the APIs section of your dashboard to represent your backend API.
You then setup your SPA to perform an implicit grant request that is both:
- an OpenID Connect end-user authentication request (the
scope
includes openid
among other relevant OIDC scopes associated with particular end-user information and the response_type
includes id_token
).
- an OAuth2 authorization request targeting your backend API (you include the
audience
parameter containing the API identifier value you configured during API creation in dashboard and the response_type
includes token
).
The above means a successful response will deliver an ID token meant to be consumed by the client application in order to know which end-user is associated with the completed authentication request and also an access token suitable to be sent to your own API. Since you included the audience
parameter pointing to your own API the issued access token will be a JWT (in the future other token formats may also be supported) which means the API can also validate it and retrieve some end-user information from it without actually having to make individual calls to the authorization server.
Have in mind that by default the access token will only include the Auth0 user identifier so if you want to include a bit more information about the user in the token itself in order to not have to query it again by user identifier you can consider the use of custom claims; see the reference documentation for additional details on how to accomplish this.
In conclusion, the ID token is meant to be consumed solely by the corresponding client application so you should use access tokens when calling the resource server. Although the ID token is always a JWT because the specification mandates it, an access token can also use that format and currently it is the format that is used when Auth0 issues access tokens meant to be consumed by your own API.
Thank you for a thorough and informative answer. This makes a lot of sense.
We’ve looked into this some more, and set up a rule to add custom claims to the access token, and it is working perfectly. Just what we wanted, and it no longer feels wrong
Glad you got this sorted, I used to do development full-time and totally understand what you’re saying. It’s a much nicer feeling when we are able to make it work right without having to resort to what we would perceive as hacks.