Im making a user authorization process with JWT tokens.
How does the flow look like?
- User logs in - gets an access token and a refresh token from a server, as a response
- Access token comes in json body and is saved in local storage. Refresh token comes in a httpOnly cookie.
- User can use
getAllUsersmethod untill access token is valid. - Whenever
getAllUsersmethod returns401 unauthorized(when access token expires), there is a request being sent to refresh token endpoint -getRefreshToken, which returns new access token that is being saved to local storage - Refresh token expires and user is being logged out.
Whole flow in Postman works but i have got problem at frontend side.
Function getAllUsers works until access token expires.
Thats why I made a global function in a util file that checks if a response is 401 and if so, it sends a request to get a new access token and calls a function which returned that error.
However it does not work.
I think that the problem is in getAllUsers function which immediately goes to catch block (when cant fetch list of users because of 401) and does not invoke that global function from util file. Console logs from both functions (getDataFromResponse, getRefreshToken) does not work so it does not even get there.
Any ideas??
API utils file
import { AxiosResponse } from "axios";
import { apiService } from "./api.service";
type ApiServiceMethods = keyof typeof apiService;
export const getDataFromResponse = async (
response: AxiosResponse,
funName: ApiServiceMethods,
...args: any
): Promise<any> => {
if (response.status === 401) {
console.log("error");
await apiService.getRefreshToken();
return await apiService[funName](args);
}
return response.data;
};
API Service:
import { getDataFromResponse } from "./api.utils";
import axios from "./axios";
type LoginArgs = {
password: string;
username: string;
};
const apiServiceDef = () => {
const login = async (args: LoginArgs) => {
try {
const response = await axios.post("/login", {
username: args.username,
password: args.password,
});
const { data } = response;
const { token } = data;
localStorage.setItem("accessToken", token);
return response;
} catch (e) {
throw new Error("Custom");
}
};
/* problem here */
const getAllUsers = async () => {
const Token = localStorage.getItem("accessToken");
try {
const response = await axios.get("/users", {
headers: {
Token,
},
});
return await getDataFromResponse(response, "getAllUsers");
} catch (e) {
console.log(e);
}
};
/* problem here */
const getRefreshToken = async () => {
try {
console.log("fetch new access token");
const response = await axios.get("/refreshToken");
if (response.status === 401) {
localStorage.removeItem("accessToken");
throw new Error("TokenExpiredError");
}
const { data } = response;
const { token } = data
localStorage.setItem("accessToken", token);
return response;
} catch (e) {
console.log(e);
}
};
return { login, getRefreshToken, getAllUsers };
};
export const apiService = apiServiceDef();