I created an Axios instance to set up the baseURL and the headers. The header also needs to contain the token for authorization. So when a user logs in I call an API to fetch some data related to the user using useEffect. So the API gets called immediately after the login is completed. This API needs permissions and hence requires the token. On login, I store the token in local storage but for some reason, the token is not loaded on the first call of the instance and I get an Unauthorised error from the backend. But then if I manually reload the page, the API gets called again but this time the token is received by the instance and the data is fetched. Below is my code.
axios instance
const baseURL = "http://127.0.0.1:8000"; // getting the token from the localstorage let authTokens = localStorage.getItem("token") ? JSON.parse(localStorage.getItem("token")) : null; const axiosInstance = axios.create({ baseURL, headers: { Authorization: `Bearer ${authTokens?.access}` }, });
api call
export const fetchTeacherDetail = async () => { try { let response = await axiosInstance.get(`/teacher/get-detail/`); return response; } catch (error) { ToastNotification( "We are facing some errors. Please trying again later.", "error" ); } };
I followed a youtube video to learn this, he is not getting this error but for some reason I am getting this error. Please suggest to me what should I do.
Update
code to show where I store the token in the local storage
action that stores the token and user details in redux
export const loginUser = (email, password) => async (dispatch) => { try { // before calling the api dispatch(loginPending()); //calling the api const response = await userLogin(email, password); if (response.status !== 200) { return dispatch(loginFail(response.status)); } else { dispatch(loginSuccess(response.data)); } } catch (error) { dispatch(loginFail(error.message)); } };
userLogin() API code
export const userLogin = async (email, password) => { const config = { headers: { "Content-Type": "application/json", }, }; const body = JSON.stringify({ email, password }); try { const response = await axios.post(`${url}/token/`, body, config); if (response.status === 200) { localStorage.setItem("token", JSON.stringify(response.data)); return response; } } catch (error) { ToastNotification("Credentials provided are not valid", "error"); } };
mocking value of the response.data received int the above function
refresh: 'eyJ0eXAiOiJKV1QUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTY1ODU4NTUxMSwiaWF0IjoxNjUwODA5NTExLCJqdGkiOiI4NDRjZWFjNTFkOWI0OGNkOWE0MTFlYzU4ZWY4ZDMxYiIsInVzZXJfaWQiOiI0YjdhODEzYmFkYi05VzZXIiOmZhbHNlLCJpc19zdGFmZiI6ZmFsc2V9.zlGb4tPtJ9HlUvSUZW6QrHHfDsUU8hZ6rliYc3RbJXQ', access: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjU4NTg1NTExLCJpYXQiOjEk1MTEsImp0aSI6ImEyYzg1NzAyZmY0ZjQ4YmRiZjEwZjEzNTUwYjk0MzE2IiwidXNlcl9pZCI6lciI6dHJ1Zsc2UsImlzX3N1cGVydXNlciI6ZmFsc2UsImlzX3N0YWZmIjpmYWxzZX0.qrictVbES22dGpA0dpVA5KLTZkrMsCM0hDHq2Yrs
Advertisement
Answer
Your issue probably happens because you set the axios instance token on the application startup, but never update it upon login.
You would need to “refresh” the value when a login happens by checking again for the localStorage data.
A quick solution would be to calculate the headers every time you call the API
const baseURL = "http://127.0.0.1:8000"; export const getToken = () => localStorage.getItem("token") ? JSON.parse(localStorage.getItem("token")) : null; export const getAuthorizationHeader = () => `Bearer ${getToken()}`; export const axiosInstance = axios.create({ baseURL, headers: { Authorization: getAuthorizationHeader() }, });
And then in the API call
export const fetchSomething = async () => { try { const response = await axiosInstance.get("/foo", { headers: { Authorization: getAuthorizationHeader() } }); return response; } catch (error) { // error handling } };
Another solution would be mutating the axios instance when a login happens by doing something like this
axiosInstance.defaults.headers.Authorization = `Bearer ${result.access}`