How to Use Refresh Tokens in a SPA?

How to use refresh tokens in a SPA (Single Page Application)?

This is a common design pattern for SPAs implementing authentication and authorization using Auth0. While relatively straightforward, there are several steps required to get an app up and running with refresh tokens.

Step 1: Configure required settings in the Auth0 Dashboard

Important to note:

  • Refresh token grant is not available for the Management API. Management API access tokens require a client credentials exchange and should generally not be handled in a public client (SPA). If your use case permits, Management API access tokens can be requested from a frontend, but will be limited in scope.
  • If an audience param is omitted from the authorize request, the returned access token will be opaque. See below on how to include this param in all Auth0 Single-Page Application (SPA) SDK Libraries.

Step 2: Configure the Auth0 SPA SDK of choice

auth0-react

import React from 'react';
import { createRoot } from 'react-dom/client';
import { Auth0Provider } from '@auth0/auth0-react';
import App from './App';

const root = createRoot(document.getElementById('root'));

root.render(
<Auth0Provider
    domain='{yourDomain}'
    clientId='{yourClientId}'
    useRefreshTokens={true}
    authorizationParams={{
      redirect_uri: window.location.origin
      audience: 'https://your_audience'
    }}
  >
    <App />
  </Auth0Provider>,
);

auth0-angular

import { bootstrapApplication } from '@angular/platform-browser';
import { provideAuth0 } from '@auth0/auth0-angular';
import { AppComponent } from './app.component';

bootstrapApplication(AppComponent, {
  providers: [
    provideAuth0({
      domain: '{yourDomain}',
      clientId: '{yourClientId}',
      useRefreshTokens: true,
      authorizationParams: {
        redirect_uri: window.location.origin,
        audience: 'https://your_audience'
      }
    }),
  ]
});

auth0-vue

import { createAuth0 } from '@auth0/auth0-vue';

const app = createApp(App);

app.use(
  createAuth0({
    domain: '<AUTH0_DOMAIN>',
    clientId: '<AUTH0_CLIENT_ID>',
    authorizationParams: {
      redirect_uri: '<MY_CALLBACK_URL>',
      audience: '<AUTH0_AUDIENCE>',
      useRefreshTokens: true
    }
  })
);

app.mount('#app');

auth0-flutter

  Future<void> login() async {
    try {
      if (kIsWeb) {
        return auth0Web.loginWithRedirect(
             redirectUrl: 'http://localhost:3000',
             audience: 'https://your_audience',
             scopes: 'openid, profile, offline_access'
        );
      }

      var credentials = await auth0
          .webAuthentication(scheme: dotenv.env['AUTH0_CUSTOM_SCHEME'])
          // Use a Universal Link callback URL on iOS 17.4+ / macOS 14.4+
          // useHTTPS is ignored on Android
          .login(useHTTPS: true);

      setState(() {
        _user = credentials.user;
      });
    } catch (e) {
      print(e);
    }
  }

auth0-spa-js

await createAuth0Client({
  domain: '<AUTH0_DOMAIN>',
  clientId: '<AUTH0_CLIENT_ID>',
  useRefreshTokens: true,
  authorizationParams: {
    redirect_uri: '<MY_CALLBACK_URL>',
    audience: 'https://your_audience'
  }
});

Logging

Successful refresh token exchanges will be logged under the event type code sertft - More on Auth0 dashboard logging here.

Additional Useful Material:

  • What are Refresh Tokens?! and…How to Use Them Securely (Video)
  • Auth0 SPA SDK Quickstarts
1 Like