Auth0 Home Blog Docs

How to renew id_token based on a refresh token?

id_token
refresh-tokens

#1

I’m able to use a refresh token to renew an access token, but the ID token is missing from the response payload.

To get the refresh token, I did a POST to https://mydomain/oauth/token with:

 {
"grant_type": "authorization_code",
"client_id": "my client id",
"client_secret": "my client secret",
"code": "my access code",
"redirect_uri": "my url",
"scope": "openid user_metadata offline_access"
}

and got:

{
  "access_token": "new access token",
  "expires_in": 86400,
  "refresh_token": "U1olGgd...tmu8nCH",
  "id_token": "eyJ0eXAiOiJKV1QiLCJhbGci......81iRvHgfKk85-0AveB5yoEP0BFBBOeDP8kXn9Z6qLTY",
  "token_type": "Bearer"
}

Then to get a new ID token using the refresh token, I tried POST to https://mydomain/oauth/token with:

{
"grant_type": "refresh_token",
"client_id": "my client id",
"client_secret": "my client secret",
"refresh_token": "my refresh token",
"scope: "openid user_metadata offline_access"
}

However, the response does not include an ID token:

{
  "access_token": "8HE...VO",
  "expires_in": 86400,
  "token_type": "Bearer"
}

What I need is to also obtain a new ID token. Note that I used the same scope to obtain the refresh token and the initial ID token.


#2

Based on the information you provided, more specifically the inclusion of user_metadata as a scope, it seems that you’re using a client application that has the OIDC Conformant toggle disabled (available on the advanced OAuth settings of the client application in your Auth0 Dashboard).

When you’re not using the OIDC conformant authentication the refresh token obtained as part of an authorization code grant is meant to be used against the /delegation endpoint if you want to obtain an ID token and not an access token.

If you want to use the /oauth/token endpoint to perform a refresh token based request then you’ll need to update your client application configuration so that the OIDC Conformant toggle is enabled. Have in mind that enabling OIDC compliant authentication, although being the currently recommended approach, introduces breaking changes so you should review the available documentation (https://auth0.com/docs/api-auth/tutorials/adoption#compare-differences-between-the-two-pipelines) before choosing to go down that route.

One of the breaking changes that would immediately affect you would be that user_metadata or any other non-OIDC claim would no longer be automatically included in the generated token just because you included it as a scope. In order to include custom information/claim in the token you would have to do it explicitly through rules and using namespaces claims; see (https://auth0.com/docs/api-auth/tutorials/adoption/scope-custom-claims).

If at this time is not feasible for you to move to OIDC compliant authentication, then you’ll need to call the delegation endpoint with the refresh token you have. This should return to you an ID token instead of an access token.


#3

So even using OIDC how would you refresh the id_token?
[OIDC Section 12][1]: Using Refresh Tokens has the following statement about the Refresh Token Response:
Upon successful validation of the Refresh Token, the response body is the Token Response of Section 3.1.3.3 except that it might not contain an id_token.
It appears many Authorization servers do
The use case is:
Originally when the id_token is acquired, it is a signed, and perhaps encrypted, JWT.
The id_token is then forward to other services within the same security domain.
These other services require an assurance that the end-user has authenticated the request.
This works well on the original request.
However, in the refresh scenario, and if the id_token is expired, the “other services” have no method to confirm the user.
Sure the same information is available at the user info endpoint but this requires the “other services” to obtain the access token.
Based on the least principle principals the Access Token has more privileges than the id_token being forwarded.
The only other option I am aware of is to copy the id_token into another JWT and send it but this is of course more “make work”.
It seems to me that NOT returning an id_token is an issue if there were not scope changes from the original request.
[1]: http://openid.net/specs/openid-connect-core-1_0.html#RefreshTokens


#4