React Token Renewal

Sample Project

Download a sample project specific to this tutorial configured with your Auth0 API Keys.

System Requirements
  • React 15.5
Show requirements

For security, keep the expiry time of a user's access token short.

When you create an API in the Auth0 dashboard, the default expiry time for browser flows is 7200 seconds (2 hours).

This short expiry time is good for security, but can affect user experience. To improve user experience, provide a way for your users to automatically get a new access token and keep their client-side session alive. You can do this with Silent Authentication.

You can control the expiry time of an access token from the APIs section. You can control the expiry time of an ID token from the Clients section. These settings are independent.

Server Setup

To renew the user's access token, you need to serve a static HTML file. You can choose any server setup to do this.

The example below uses Node.js and Express.

Create a simple server with Express and add a file called silent.html.

The silent.html file receives and parses the result of a token renewal. An instance of the WebAuth object from auth0.js is created. The parseHash method returns an object from the hash with the authentication result. The object is then posted back to the parent window and the client-side session starts again.

// server.js

const express = require('express');
const app = express();
const cors = require('cors');
const staticFile = require('connect-static-file');

app.use(cors());
app.use('/silent', staticFile(`${__dirname}/silent.html`));

app.listen(3001);
console.log('Listening on http://localhost:3001');
<!-- silent.html -->

<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <script src="https://cdn.auth0.com/js/auth0/8.9/auth0.min.js"></script>
  <script>
    var webAuth = new auth0.WebAuth({
      domain: 'YOUR_AUTH0_DOMAIN',
      clientID: 'YOUR_CLIENT_ID',
      scope: 'openid profile',
      responseType: 'token id_token',
      redirectUri: 'http://localhost:3000'
    });
  </script>
  <script>
    webAuth.parseHash(window.location.hash, function (err, response) {
      parent.postMessage(err || response, 'http://localhost:3000');
    });
  </script>
</head>
<body></body>
</html>

Add http://localhost:3001/silent to the Allowed Callback URLs section in your application's Client Settings.

Add Token Renewal

To the Auth service, add a method which calls the renewAuth method from auth0.js. If the renewal is successful, use the existing setSession method to set new tokens in local storage.

The method loads the silent callback page added earlier in an invisible iframe, makes a call to Auth0, and gives back the result.

// src/Auth/Auth.js

renewToken() {
  this.auth0.renewAuth(
    {
      audience: '{YOUR_API_IDENTIFIER}',
      redirectUri: 'http://localhost:3001/silent',
      usePostMessage: true
    }, (err, result) => {
      if (err) {
        console.log(err);
      } else {
        this.setSession(result);
      }
    }
  );
}

The access token should be renewed when it expires. In this tutorial, the expiry time of the token is stored in local storage as expires_at.

Define a timing mechanism for renewing the token.

You can define any timing mechanism you want. You can choose any library that handles timers. This example shows how to use a setTimeout call.

In the Auth service, add a property called tokenRenewalTimeout which refers to the setTimeout call.

Add a method called scheduleRenewal to set up the time when the authentication is silently renewed. The method subtracts the current time from the access token's expiry time and calculates delay. The setTimeout call uses the calculated delay and makes a call to renewToken.

The setTimeout call call is assigned to the tokenRenewalTimeout property. When the user logs out, the timeout is cleared.

// src/Auth/Auth.js

tokenRenewalTimeout
// ...
scheduleRenewal() {
  const expiresAt = JSON.parse(localStorage.getItem('expires_at'));
  const delay = expiresAt - Date.now();
  if (delay > 0) {
    this.tokenRenewalTimeout = setTimeout(() => {
      this.renewToken();
    }, delay);
  }
}

You can now include a call to the scheduleRenewal method in the setSession method.

// src/Auth/Auth.js

// ...
setSession(authResult) {
  // Set the time that the access token will expire at
  let expiresAt = JSON.stringify(
    authResult.expiresIn * 1000 + new Date().getTime()
  );

  localStorage.setItem('access_token', authResult.accessToken);
  localStorage.setItem('id_token', authResult.idToken);
  localStorage.setItem('expires_at', expiresAt);

  // schedule a token renewal
  this.scheduleRenewal();

  // navigate to the home route
  history.replace('/home');
}

To schedule renewing the tokens when the page is refreshed, in the constructor of the Auth service, add a call to the scheduleRenewal method.

// src/Auth/Auth.js

// ...
constructor() {
  // ...
  this.scheduleRenewal();
}

Since client-side sessions should not be renewed after the user logs out, call clearTimeout in the logout method to cancel the renewal.

// src/Auth/Auth.js

logout() {
  // ...
  clearTimeout(this.tokenRenewalTimeout);
}

Troubleshooting

If you're having problems with token renewal (for example, you get the login_required error), make sure you're not using Auth0 dev keys for social login. You must use your own social authentication keys.

Previous Tutorial
4. Authorization
Use Auth0 for FREECreate free Account