ReactAuth0 - Get AccessToken in a none ReactHook code

Hi

I’ve a react app and want to get a Bearer Token inside a TypeScript component
When I use the following code useAuth0() is only allowed inside a react hook.

Whats the intended way to do so?

import { getApiHost } from '@/conf';
import { useAuth0, withAuthenticationRequired } from "@auth0/auth0-react";
const {
getAccessTokenSilently,
} = useAuth0();

import {
TraineesClient,
}
from './api.clients'


const apiHost = getApiHost();

const fetchWrapper: { fetch: typeof window.fetch } = {
async fetch(request, init?): Promise<Response> {
    const token = await getAccessTokenSilently();

    return window.fetch(request, {
        ...init,
        headers: {
            ...init?.headers,
            Authorization: `Bearer ${token}`
        }
    });
}
};

export const traineesClient = new TraineesClient(apiHost, fetchWrapper);

That is correct. React allows calling a hook only from a React component or from another hook.

There are few approaches you can take.

  1. Use useAuth0 hook in every React component that needs to make an API call to de-structure getAccessTokenSilently. And use it to obtain the access token. And then pass it to the API call as an argument. With this approach, you will be required to modify the API signatures to accept accessToken argument.

  2. A slight improvement to approach 1 is, creating an AuthProvider component that wraps your app. The AuthProvider calls getAccessTokenSilently to obtain the accessToken and then provides it to the children components. The children components use the provided accessToken and pass it to the API. This still requires you to modify the API signatures to accept access Token but it avoids calling useAuth0 in every component that calls an API.

  3. Create a useAPI hook and wrap your API with it. This approach is explained in following example. https://github.com/auth0/auth0-react/blob/master/EXAMPLES.md#4-create-a-useapi-hook-for-accessing-protected-apis-with-an-access-token

  4. Similar to approach 2, you can create an AuthProvider that obtains the accessToken once. But instead of providing it to the children, it calls an API provided by your API library to set the accessToken globally. This accessToken can be used by all the API calls in the library. I’m currently trying this option out myself.

I’m using Axios which allows global defaults.

const axios = require(“axios”);
axios.defaults.baseURL = “http://localhost:3031/api/”;
axios.defaults.timeout = 2500;
axios.defaults.headers[‘Authorization’] = null;

Following function is exported from the library to allow the AuthProvider to set the default ‘Authorization’ header above.

function setAuthorizationHeader() {

}

Hi @support12, Thanks for explaining the 4 approaches. Currently we are struggling to implement this solution. Is it possible to provide some git reference or some sample code for approach 2 and 4.

Regards

1 Like

bump I need reference code to this I assumpe using auth0-spa-js and add to singleton the useAuth0?

@evan.gillogley I just recently implemented something for this and wrote about it Maffin Blog - Next.js feature flags with auth0 (full example of retrieving access token with roles and injecting it to a class to it can be used in the server actions). The snippet:

export default class AccessTokenHolder {
  static _accessToken: string;

  static get accessToken() {
    return Actions._accessToken;
  }

  static set accessToken(token: string) {
    Actions._accessToken = token;
  }
}

and how to set it

import { useAuth0 } from '@auth0/auth0-react';
import AccessTokenHolder from './AccessTokenHolder';

export default function useSession(): SessionReturn {
  const { getAccessTokenSilently, isAuthenticated } = useAuth0();
  const [accessToken, setAccessToken] = React.useState();

  React.useEffect(() => {
    async function load() {
      const token = await getAccessTokenSilently();
      AccessTokenHolder.setAccessToken(token);
      setAccessToken(token);
    }

    if (isAuthenticated) {
      load();
    }
  }, [isAuthenticated, getAccessTokenSilently]);

  return {
    accessToken,
  };

Hope it helps!