I'll share my approach for client side validating while reducing the number of call to server.
Validating with session storage is not a good approach imo as it is not shared between tabs.
When the user logs in to your website and send the request to your server, generate a JWT token with payload as their email id and send it as cookie/json response to client.
If you prefer JWT token in response then save the JWT token in local-Storage with a unique name (eg. myAdminAccessToken) so it doesn't interfere with other keys in their browser. A cookie in response is a much better and robust approach then storing JWT token
Now every time your user makes a network request to your server, before making the network call (fetching the url) check if the token exist in the local-Storage, if not then they are not authorised and redirect them to login page. and if it exist allow them to make the network call to your server.
Parse the cookie/JWT token and validate if the email exist then it means they are authorised send a authorised:true in response and let them fetch the request resource from your server.
If no such email exist or the JWT token parsing failed it means they are not authorised and they tried to bypass your first validation check, which is in step#3.
In this case send a authorised:false response from your server and upon receiving failed authorised your client should log them out and redirect to login page and also remove the accessToken from local-Storage.
i don't have pure js or jquery code for this but if you want i can share react code with you explaining the above mentioned process.
Optimisations
You can even optimise the above solution for more robust and secure app.
- use redis for caching user emails for quick validations.
- use a state management library to provide an extra layer of protection and make your ui in sync.
local-storage, session-storage, state-management libraries are not reliable for protecting your routes/data but they can be used to reduce the no of network calls to your server.