Search code examples
reactjsaxiosauth0

Creating an axios instance with token inside a custom hook only works for the first request


I currently try to create a custom hook, which creates a custom axios instance that has a token in the authorization header.

My current approach is this one:

export default function useAxiosAuthenticated() {

    const {getAccessTokenSilently} = useAuth0();
    const AxiosAuthenticated: AxiosInstance = axios.create({
        baseURL: GeneralHelper.APIUrl
    });


    useEffect(() => {

        AxiosAuthenticated.interceptors.request.use(async (config) => {

            const token: string = await getAccessTokenSilently();
            config.headers.Authorization = `Bearer ${token}`;

            return config;

        });


    }, [getAccessTokenSilently]);


    return AxiosAuthenticated;

}

If I do it this way, it works perfectly fine for the first request, every other request fails with 401 - Unauthorized. I've tried to save the AxiosAuthenticated object as state, but then not even the first request works and throws another 401.

Maybe it has something to do with the async/await part of the code? Maybe I'm not getting a "finished" object the second time?

My old approach was that I had this TypeScript file:


export const AxiosAuthenticated: AxiosInstance = axios.create({
    baseURL: GeneralHelper.APIUrl
});

export const AddTokenInterceptor = (tokenObtainFunction: Function): void => {

    AxiosAuthenticated.interceptors.request.use(async (config) => {

        const token: string = await tokenObtainFunction();
        config.headers.Authorization = `Bearer ${token}`;

        return config;

    });
};

And in my component I used it like this:

useEffect(() => {

        AddTokenInterceptor(getAccessTokenSilently);

        getAccessTokenSilently().then(token => tempToken.current = token);


    }, [getAccessTokenSilently]);

This approach however, worked perfectly fine, but was duplicated in some components. And since the custom hooks used to reduce duplication of logic I thought they would be a better approach.


Solution

  • You can do like this.

    export const axiosInstance = axios.create({
      baseURL: GeneralHelper.APIUrl,
      headers: {
        Authorization: '',
      }
    });
    

    And you can add this in one place (for ex: in App component or AuthenticatedRoutes)

    useEffect(() => {
        const token: string = await getAccessTokenSilently();
        axiosInstance.defaults.headers.Authorization = `Bearer ${token}`;
    }, [getAccessTokenSilently]);