Fun with Auth0, React and tokens

I am working on a React-based Single-Page App (SPA) using Auth0 for authentication. For a while, I have been maintaining my own little helper library to do this. It uses the auth0/auth0-js library (which is described as “Client Side JavaScript toolkit for Auth0 API”) under the hood.

I’ve been aware of a new-ish recommended way to work with Auth0 for a while, and finally decided to migrate my sloppy integration over. I first started with auth0/auth0-spa-js, but soon realized that Auth0 maintains a React SDK, which uses auth0-spa-js under the hood, so I went with auth0/auth0-react instead.

Most of the steps are pretty straightforward as documented in this quick start guide. The part I struggled with the most was getting the Access Token to call a backend API.

Before, in my sloppy integration, I was using the ID token returned from the OAuth flow to call my backend API. It is actually a bad/ wrong implementation, as called out by Auth0 tokens documentation:

Do not use ID tokens to gain access to an API.

So in order to get a proper access token, I have the following code in the App.jsx component.

import React, { useState, useEffect } from 'react';
import { useAuth0 } from '@auth0/auth0-react';

function App() {
  const [token, setToken] = useState();
  const { getAccessTokenSilently } = useAuth0();

  useEffect(() => {
    (async () => {
      const accessToken = await getAccessTokenSilently();
      setToken(accessToken);
    })();
  });
}

However, I could not understand why the accessToken I received was not in JWT format, but a small string of maybe 15 characters. It wasn’t a Bearer token I could use to make XHR call against the REST API server.

The Auth0 doc page on Access Tokens mentions 2 different kinds – “opaque” and “JWT”, but it didn’t mention how to get the JWT token. I was guessing that the small token I got back was the opaque token.

Not able to find any reference to this issue online, I randomly tried adding the audience to the call to get the token, which turned out to be exactly the missing piece for me.

  const token = await getAccessTokensSilently({
    audience: 'https://myapi.com'
  })

In hindsight, I’m guessing I was getting the opaque token because by default, Auth0 was returning the access token needed for the /userinfo endpoint only. If anyone knows the answer to this, I would love to know.

UPDATE: This behavior is documented in this post https://community.auth0.com/t/why-is-my-access-token-not-a-jwt-opaque-token/31028

In order to receive a JWT you must include an audience parameter with your token request.

comments powered by Disqus