How should I handle JWT token refresh in my Redux app?

Viewed 492

Our Redux application use JWT tokens for authentication. The access_token expires every 15 minutes and the refresh_token expires every 30 days. Both of them are provided by our API every time you log in and stored in the browser's local storage. If a secure endpoint receives a request with an expired token, it returns a 401 HTTP error.

Unfortunately, I don't know how to proceed to handle the refresh process without having a negative impact on the user. From a technical point of view, here is what I would like to achieve:

  • Action creator calls the API with an expired token
  • Client receives a 401 HTTP error
  • Client triggers a function that calls the API to obtain a new token (by providing the refresh token).
  • If the call fails (refresh_token is expired), prompt the user the re-enter its credentials to re-obtain both tokens then re-attempt the original request.
  • If the call succeeds, re-attempt the original request.

I would like to have a function that would handle the refreshing process and that would be called in the error handling portion of the action creator.

Here is what I have tried so far:

    export function handleError(dispatch, current_func, error, handling) {
        if(error.response) {
            if(error.response.status === 401 && readToken("token") !== null) {
                return attemptTokenRefresh(dispatch, current_func)
            }

            if(error.response.status === 422 && readToken("token") === null) {
                return attemptTokenRefresh(dispatch, current_func)
            }
        }

        return(handling())
    }

    export function attemptTokenRefresh(dispatch, on_success) {
        let token = readToken("refresh_token");

        let instance = axios.create({
            headers: {"Authorization": token}
        });

        instance.post("api/refresh").then(response => {
            if (response.data["token"]) {
                storeToken("token", response.data["token"]);
                on_success();
            }
        }).catch(error => {
            //TODO: Allow user to sign back (prevent wiping the state)
        });
    }

dispatch refers to the dispatch function provided by Redux

current_func refers to the action creator

error refers to the error returned by the API

handling refers to the error handling function for other types of errors

Any help would be greatly appreciated :)

0 Answers
Related