How to implement jwt authentication in authProvider?

I have followed this link https://refine.dev/docs/api-reference/core/providers/auth-provider/#setting-authorization-credentials to set my authorization credentials and it is working fine. But now how do I use a refresh token to generate a new access token on every request. What I have done so far is below:
axiosInstance.interceptors.response.use(
(response) => {
return response;
},
(error) => {
const prevRequest = error?.config;
if (error?.response?.status === 401 && !prevRequest?.sent) {
prevRequest.sent = true;
axiosInstance.post(
`${API_BASE_URL}/token/refresh/`,
{ refresh: localStorage.getItem(TOKEN_REFRESH_KEY) }
).then((res => {
prevRequest.headers = { ...prevRequest.headers, ...authHeader(res.data.access) };
return axiosInstance(prevRequest);
}))
.catch((err) => {
if(err.response.status === 401) {
sessionStorage.removeItem(TOKEN_KEY);
return Promise.reject(new Error('Your login session expired. Please login again.'));
}
return Promise.reject(err);
});
}
const customError: HttpError = {
...error,
message: error.response?.data?.message,
statusCode: error.response?.status,
};
return Promise.reject(customError);
},
);
axiosInstance.interceptors.response.use(
(response) => {
return response;
},
(error) => {
const prevRequest = error?.config;
if (error?.response?.status === 401 && !prevRequest?.sent) {
prevRequest.sent = true;
axiosInstance.post(
`${API_BASE_URL}/token/refresh/`,
{ refresh: localStorage.getItem(TOKEN_REFRESH_KEY) }
).then((res => {
prevRequest.headers = { ...prevRequest.headers, ...authHeader(res.data.access) };
return axiosInstance(prevRequest);
}))
.catch((err) => {
if(err.response.status === 401) {
sessionStorage.removeItem(TOKEN_KEY);
return Promise.reject(new Error('Your login session expired. Please login again.'));
}
return Promise.reject(err);
});
}
const customError: HttpError = {
...error,
message: error.response?.data?.message,
statusCode: error.response?.status,
};
return Promise.reject(customError);
},
);
After using this code I can get new access token there isn't any problem. But once the refresh token is expired then how can I logout user. By using above code the request for refresh token is request infinitely.
Auth Provider | refine
refine let's you set authentication logic by providing the authProvider property to the `` component.
29 Replies
Omer
Omer2y ago
Hey @dipbazz , @yildirayunlu can help us 🎯
conscious-sapphire
conscious-sapphire2y ago
Okay @Omer.
subsequent-cyan
subsequent-cyan2y ago
Hi @dipbazz I did this using the axios-auth-refresh package. I am posting the authProvider as an example.
// Function that will be called to refresh authorization
const refreshAuthLogic = () => {
const auth = getAuth();
if (auth && auth.refreshToken) {
const { refreshToken } = auth;

return axios
.post<IAuth>("/api/auth/refresh-token", {
refreshToken,
})
.then(({ data }) => {
setToken(data);

const { accessToken } = data;
axios.defaults.headers.common[
"Authorization"
] = `Bearer ${accessToken}`;

return Promise.resolve();
})
.catch(() => {
logout();
return Promise.reject();
});
}
logout();
return Promise.reject();
};

createAuthRefreshInterceptor(axios, refreshAuthLogic);
// Function that will be called to refresh authorization
const refreshAuthLogic = () => {
const auth = getAuth();
if (auth && auth.refreshToken) {
const { refreshToken } = auth;

return axios
.post<IAuth>("/api/auth/refresh-token", {
refreshToken,
})
.then(({ data }) => {
setToken(data);

const { accessToken } = data;
axios.defaults.headers.common[
"Authorization"
] = `Bearer ${accessToken}`;

return Promise.resolve();
})
.catch(() => {
logout();
return Promise.reject();
});
}
logout();
return Promise.reject();
};

createAuthRefreshInterceptor(axios, refreshAuthLogic);
You should follow this method in authProvider.checkAuth as well.
checkAuth: async () => {
// qs accessToken && refreshToken check
const params = new URLSearchParams(window.location.search);
const accessToken = params.get("accessToken");
const refreshToken = params.get("refreshToken");

if (accessToken && refreshToken) {
const { data, status } = await axios.get<IUser>(`/api/auth/me`, {
headers: {
Authorization: `Bearer ${accessToken}`,
},
});

if (status === 200) {
setToken({
...data,
accessToken,
refreshToken,
});
axios.defaults.headers.common[
"Authorization"
] = `Bearer ${accessToken}`;

// TODO: Must be better solution
window.location.href = "/";
return Promise.resolve();
}
}

const auth = getAuth();
if (auth) {
const { accessToken } = auth;
axios.defaults.headers.common["Authorization"] = `Bearer ${accessToken}`;
return Promise.resolve();
}

return Promise.reject();
},
checkAuth: async () => {
// qs accessToken && refreshToken check
const params = new URLSearchParams(window.location.search);
const accessToken = params.get("accessToken");
const refreshToken = params.get("refreshToken");

if (accessToken && refreshToken) {
const { data, status } = await axios.get<IUser>(`/api/auth/me`, {
headers: {
Authorization: `Bearer ${accessToken}`,
},
});

if (status === 200) {
setToken({
...data,
accessToken,
refreshToken,
});
axios.defaults.headers.common[
"Authorization"
] = `Bearer ${accessToken}`;

// TODO: Must be better solution
window.location.href = "/";
return Promise.resolve();
}
}

const auth = getAuth();
if (auth) {
const { accessToken } = auth;
axios.defaults.headers.common["Authorization"] = `Bearer ${accessToken}`;
return Promise.resolve();
}

return Promise.reject();
},
We are preparing a sample document on this subject. We will publish it soon.
conscious-sapphire
conscious-sapphire2y ago
Hi @yildirayunlu thank you for your response. I have some question regarding refreshAuthLogic function you have created. In this function where you are catching an error from axios request how exactly is logout() function logging out the user. Can I know the logout code logic implementation? I am completely stuck on how can I log out the current user when the refresh token is expired.
Omer
Omer2y ago
The logout function only clears localstorage. The important point here is that Promise.reject is returned. So it falls into the checkError function of your authProvider. Then the user will be considered logged out already https://refine.dev/docs/api-reference/core/providers/auth-provider/#checkerror
conscious-sapphire
conscious-sapphire2y ago
Okay Thank you @Omer
Omer
Omer2y ago
It's works now?
conscious-sapphire
conscious-sapphire2y ago
I will test and let you know. Thank you @Omer and @yildirayunlu it is working now. Whenever the refresh token is expired user will be redirected to login page. But now I am facing a new issues. Whenever the user is logged out after the refresh token is expired they will be redirected to login page but the redirect url will be to=/login instead of redirect url as the resource that I am trying to access. For example: let us say I am trying to access the users resource from the menu but my refresh token is expired then I will be redirected to login page with url as <domain>/login?to=%2Flogin instead of <domain/login?to=%2Fusers I don't know if that's an issue or expected solution but the issue is when I am logged in and try to go to /login page I get 404 page not found message. Shouldn't the user should be redirected to dashboard or other page if they are logged in?
Omer
Omer2y ago
hmm let me check Do you have a chance to provide an environment where we can reproduce this issue? You can fork here, https://refine.dev/docs/examples/authentication/headless/
conscious-sapphire
conscious-sapphire2y ago
I will create it tomorrow if that's okay?
Omer
Omer2y ago
of course!
conscious-sapphire
conscious-sapphire2y ago
Refine Headless Example (forked) - StackBlitz
Run official live example code for Refine Headless, created by Refinedev on StackBlitz
conscious-sapphire
conscious-sapphire2y ago
Hello @Omer here is the exact code environment that I am using in my code-base.
Omer
Omer2y ago
Hey @dipbazz , Thank you! Let's take a look 👀 Hey @dipbazz , We were able to reproduce the issue. The solution seems a bit complicated. Can you open a GitHub issue? 👀
conscious-sapphire
conscious-sapphire2y ago
Hey @Omer I have created an issue and here is the link for the issue https://github.com/refinedev/refine/issues/2927
GitHub
[BUG] Issue on redirect url after user is logged out on jwt refresh...
Describe the bug I am using the JWT authentication on my project and it works fine when I log in and save the access token in my local or session storage. But whenever my refresh token is expired a...