How to get Auth0 token from outside React components?

Viewed 1041

I am using axios to make requests to my APIs. Currently I use an axios interceptor to set the token to every request that gets sent (so I don’t have to repeat getting the token from within the component). Is there any way to do this? My first attempt looks something like this:

// axios.ts
import { useAuth0 } from "@auth0/auth0-react";
import axios from "axios";

const fetchClient = axios.create();

fetchClient.interceptors.request.use(
  async (config) => {
    const { user, getAccessTokenSilently } = useAuth0();

    if (!user || !user.sub) return Promise.reject("No user");

    const token = await getAccessTokenSilently({
      audience: process.env.REACT_APP_AUTH0_API_AUDIENCE,
    });

    const userId = user.sub.split("|")[1];
    config.headers["Authorization"] = `Bearer ${token}`;
    config.headers["userId"] = userId;
    return config;
  },
  (error) => {
    Promise.reject(error);
  }
);

export default fetchClient;

But of course you can’t call Hooks and therefore can’t call getAccessTokenSilently from non functional components. Any way to get around this? Thanks all

2 Answers

I solved this problem by passing the getAccessTokenSilently as a parameter to a function in my axios file.


import axios from "axios";

const httpClient = axios.create();

// adds access tokens in all api requests
// this interceptor is only added when the auth0 instance is ready and exports the getAccessTokenSilently method
export const addAccessTokenInterceptor = (getAccessTokenSilently) => {
  httpClient.interceptors.request.use(async (config) => {
    const token = await getAccessTokenSilently();
    config.headers.Authorization = `Bearer ${token}`;
    return config;
  });
};

export default httpClient;

Then in my App.jsx I used an useEffect to execute this function once the Auth0 instance is ready:


import { useEffect } from "react";
import { useAuth0 } from "@auth0/auth0-react";
import { addAccessTokenInterceptor } from "./api/httpClient";

const App = () => {

  const { getAccessTokenSilently } = useAuth0();

  useEffect(() => {
    addAccessTokenInterceptor(getAccessTokenSilently);
  }, [getAccessTokenSilently]);

   return (
    <div>
      Your app here...
    </div>
  );
}

export default App;

Hope this helps!

I faced the same issue and I solved it in a similar way. The difference is that I separated the axios client creation from the interceptor.

import axios from 'axios';

const client = axios.create({
  baseURL: process.env.REACT_APP_API_BASE_URL,
  headers: {
      'Content-type': 'application/json',
  },
});

export default client;

And I created the interceptor function inside the component that has access to Auth0.

import client from "../../../services/client";

const setAxiosTokenInterceptor = async (getAccessTokenSilently: any): Promise<void> => {
  const accessToken = await getAccessTokenSilently();
  client.interceptors.request.use(async config => {
    const requestConfig = config
    if (accessToken) {
      requestConfig.headers.common.Authorization = `Bearer ${accessToken}`
    }
    return requestConfig
  })
}

And I called if from the same component as such

const { isAuthenticated, getAccessTokenSilently } = useAuth0();
setAxiosTokenInterceptor(getAccessTokenSilently);

To use this, I just import the client and use it as normal axios client.

Related