I have recently finished a react web portal where we have used JWT to initiate, maintain and expire user's session.
- Upon login, sending user credentials to login API. Upon success, get the token back from back-end API. Back-end maintains the token generation and expiration.
- Store the token in react state (we use redux store) and in session storage (in case page is refreshed, we can get it back from session storage).
- (Optional) Start a per second counter in session storage (to check how long user is idle)
- After login, every API call requires the token to be sent in header. API calls are made using fetch. If API call is successful, we get the token back from back-end and we replace it with existing token (stay fresh).
- All API calls are 'fetch'ed via a generic customFetch function. Idea is to have a generic fetch to see if back-end response is 401 (access denied). If it is 401, the token is expired or invalid (user is trying to access something without login). In this case, we throw user out of portal, back to login/home page (displaying the error that access is denied).
- (Optional) If user is idle for too long (checking the second counter > 900 i.e. 15 min), we show warning to user that session is about to expire, gives user a choice to continue. If user clicks continue, we call an API to retrieve user's profile again, thus making sure that token is still valid. If API is not successful, we log user out and send back to login/home page. The second counter sets back to 1 just before any API call is made (user is active and doing something).
- Needless to say that before sending user to login/home page by any of the above scenarios, we clear the session storage and reset the state (redux store).
- In case of any refresh happens, we retrieve token from session storage and dispatch initial actions to build the state (redux store) again. If any of the actions (API) fail, we display the message to user that session is expired or invalid and you need to login thus sending user back to login/home page.
Code snippets
Assume that you have retrieved the token from login API call:
set token in session storage and state (redux store)
window.sessionStorage.setItem('partyToken', token)
store.dispatch({type: 'profile/setToken', payload: { token }})
retrieval token from session storage or state (redux store)
const token = window.sessionStorage.getItem('token')
const token = store.getState().profile && store.getState().profile.token
Of course you can define a common function where you can set/refresh the token after every API call. Similar for retrieval because you need the token before you make API call.