Auth0-spa-js: Not getting refresh tokens when switching from PKCE + silent auth to PKCE + refresh token rotation

Created on 23 Dec 2020  路  4Comments  路  Source: auth0/auth0-spa-js

Using the SDK, refresh tokens are not coming back with the /oauth/token call. The response does not contain the scopes requested during authorization.

SDK configuration:

const initOptions: Auth0ClientOptions = {
  redirect_uri: <redirect_uri>,
  domain: <domain>,
  client_id: <client_id>,
  audience: <audience>,
  useRefreshTokens: true
};

The /authorize call is requesting the appropriate scopes:

GET /authorize
    ?redirect_url=<redirect_uri>
    &client_id=<client_id>
    &audience=<audience>
    &response_type=code
    &respones_mode=web_message
    &state=<state>
    &nonce=<nonce>
    &code_challenge=<code_challenge>
    &code_challenge_method=S256
    &prompt=none
    &auth0Client=<client>
    &scope=openid profile email offline_access

Notice the offline_access scope added, thanks to useRefreshTokens option

However, when the /oauth/token call is made, the incorrect scopes come back, and no refresh_token exists:

POST /oauth/token
    ?client_id=<client_id>
    &code=<code>
    &code_verifier=<code_verifier>
    &grant_type=authorization_code
    &redirect_uri=<redirect_uri>

I am not sure if grant_type=authorization_code is expected here or not. I would assume it would be refresh_token.

...and the response:

{
  "access_token": <access_token>,
  "expires_in": 60,
  "id_token": <id_token>,
  "scope": "openid profile email"
  "token_type": "Bearer"
}

Notice that scope does not include offline_access.

Additionally, the console logs a warning from the SDK package:

The requested scopes (openid profile email offline_access) are different from the scopes of the retrieved token (openid profile email). This could mean that your access token may not include all the scopes that you expect. It is advised to resolve this by either:

  - Removing `offline_access` from the scope when requesting a new token.
  - Ensuring `offline_access` is returned as part of the requested token's scopes.

I can confirm the following to be true:

  • We are using a SPA
  • We have Refresh Token Rotation enabled for the application client
  • We have configured the SDK according to the documentation
  • The application is OIDC conformant
  • The Refresh Token grant type is enabled

What was the expected behavior?

We expect the /oauth/token call to respond as follows:

{
  "access_token": <access_token>,
  "expires_in": 60,
  "id_token": <id_token>,
  "refresh_token": <refresh_token>
  "scope": "openid profile email offline_access"
  "token_type": "Bearer"
}

Added offline_access scope and refresh_token property

Environment

Please provide the following:

  • Using latest auth0-spa-js (1.13.5)
  • Tested only in chrome
  • Using react
  • Everything works perfectly with standard silent auth w/o rotation. We are migrating due to the deprecation of third party tracking cookies.

Thanks.

bug report

Most helpful comment

Great you solved it. I think it's a fair point about the documentation.

For future readers, I also want to point out there is a section explaining all kinds of settings for the API's: https://auth0.com/docs/get-started/dashboard/api-settings

That said, I understand it's not always clear where to go when approaching it from the application side.
I will have a conversation to see how we can improve the documentation by adding a note referring to the API setting or whatsoever.

All 4 comments

Hey @justinhelmer,

Refresh Tokens by itself should work fine with the SDK, I always use them instead of IFrames myself.

I am not sure if grant_type=authorization_code is expected here or not. I would assume it would be refresh_token.

The initial call to /token is expected to be grant_type=authorization_code, as we can not use grant_type=refresh_token before we actualy received our first refresh token. However, it is expected that that first call, which includes grant_type=authorization_code, returns a refresh token when offline_access is send as part of the scope.

However, it looks like you are still using iframes, because of these arguments in the /authorize request:

&response_type=code
&respones_mode=web_message

Can you verify that the user is not actualy being redirected to Auth0, but instead the /authorize call is happening in the iframe?
If this is the case, this is not expected. When using the non iframe approach, it is expected for the /authorize call to contain the following instead:

&response_type=code
&respones_mode=query

I am wondering if there is a problem when switching from using Iframes to using Refresh Tokens in the same browser. Could you verify this using another browser (or incognito Chrome)?

Could you also check if there is anything being logged in your tenant logs? I am wondering if you are seeing something along the lines of:

Type: Failed Silent Auth
Description: The specified redirect_uri 'http://localhost:4200' does not have a registered origin.

However, it looks like you are still using iframes, because of these arguments in the /authorize request:

I want to add one thing here ... The SDK is configured to still use iframes if you do not have a refresh token. So it might be the case that you are still seeing the iframe approach (response_mode web_message) being used if you are calling getTokenSilently without having a refreshToken available.

On some browsers that do not support 3rd party cookies, the iframe approach is not supported. So it is important to handle the login_required error when calling getTokenSilently and call loginWithRedirect or loginWithPopup if that error is being thrown.

I think it is important to verify the Tenant logs here, so if you could provide some information about errors being logged in your tenant, that would be helpful.

Thanks

@frederikprijck - I appreciate the thoughtful reply.

You are correct that the SDK was falling back to this behavior when using getTokenSilently(). I managed to resolve this (thanks to the help of the Auth0 support team) by simply switching "Allow Offline Access" through the Auth0 Management Dashboard for the particular API (http://localhost:9445).

Screen Shot 2021-01-04 at 10 58 58 AM

I have updated the support ticket to include a suggestion to add this to the documentation on how to Configure with the Auth0 SPA SDK, since this setting is not mentioned.

You may also want to update the README for this repo in the Refresh Token section. There is a Note: that mentions the "Rotating Refresh Tokens" configuration must be enabled through the Auth0 configuration, but nothing about this setting for the API.

Apologies for taking your time with what ultimately was resolved by flipping a switch in the configuration.

Cheers.

Great you solved it. I think it's a fair point about the documentation.

For future readers, I also want to point out there is a section explaining all kinds of settings for the API's: https://auth0.com/docs/get-started/dashboard/api-settings

That said, I understand it's not always clear where to go when approaching it from the application side.
I will have a conversation to see how we can improve the documentation by adding a note referring to the API setting or whatsoever.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

devuxer picture devuxer  路  7Comments

Arnaud73 picture Arnaud73  路  7Comments

szilagyikinga picture szilagyikinga  路  6Comments

stupidSheep picture stupidSheep  路  4Comments

alexislucas-toast picture alexislucas-toast  路  3Comments