I want to check if the token is expired on client side.
My token is stored in localstorage.
Now what I do is: make a call to the server to check if it is valid but I only do it when the path is: https:exp.com/
code:
useEffect(() => {
verifyToken(auth.token).then((res) => {
if (res.status !== 'success' && res.message === 'Token expired') {
signoutClient(() => {
router.push('/auth/login');
});
}
});
}, [auth.token, router]);
Now the problem here is what if the user goes directly to another url exp : https:exp.com/helloworld
I was thinking to use sockets but I don't know if it could work.
Idea is: client stays in listen, whenever token expires server emits a message.
Any idea on how can I do it?
There are different techniques.
Note that handling time on two different machines (expiration in this case) may lead to issues due to time jitter or clock misalignment, so it is not so straightforward
My favorite pattern is to have a dedicated server error.
Your server should respond with a particular error when the token is expired (to be distinguished from the 401 Unauthorized due to role access). You then add an HTTP middleware to your client that:
/auth/loginOr if you have a renew token:
JWTThis is a passive system that allows you to treat the JWT as an obscure string and does not have time-related issues.
If, for security reasons, you want to hide sensible information when the session expires even when the user is not interacting with the UI (like Banking sites do) you need to know when the token will expire. A common technique is to return expiration time together with the token (within the authentication response).
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.JFDV4mOKKh0sMfkBKvsbvm8iWjHEGBXtPvC49ob3qiI",
"expiresAt": 1234567890
}
Or even better
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.JFDV4mOKKh0sMfkBKvsbvm8iWjHEGBXtPvC49ob3qiI",
"expiresIn": 600
}
The first one returns you the UNIX time of token expiration relative to server time. This is subject to time jitter or clock misalignment (this may lead to errors). The second one is better as it lets the UI know within how many seconds (since the Response was received) the token will expire, this can be then used to calculate the UNIX time according to the local clock.
It is common to remove a small time step from expiresAt and expiresIn to avoid clock jitter and clock drift issues.
If you have no other solution, you can always parse the JWT:
const JWT = `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjEyMzQ1Njc4OTAsIm5hbWUiOiJKb2huIERvZSIsImlhdCI6MTUxNjIzOTAyMn0.1c_yQjnMZfKUb4UTDE_WvbC71f8xxtyMsdqKKkI1hF8`;
const jwtPayload = JSON.parse(window.atob(JWT.split('.')[1]))
console.log(jwtPayload.exp);
You can use a lib(like jwt_decode) to decode your JWT token, where it's most likely contains an expiration timestamp that you can check(compare it with the current timestamp for this moment) and if it exceeded(expired) just delete it from local storage and redirect user to login page.
But you also have to consider add a catch block for functions which calls your API to check for any 401 response status code to also do the same (in case the token was valid then while the user is moving around its expiry date ends)