How to use refresh token in reactjs

Viewed 28212

I am working on a admin app in reactjs which uses redux for state management. In my app when user log in it gets access_token and refresh _token. access_token which gets expired after 5 min. after 5 min token becomes invalid to make any api endpoint request.

I want to know how am I suppose to use this refresh_token to update my access_token which is stored in localStorage of the browser. I had no idea about this refresh_token before this. This is how I make login request and save my access_token and refresh_token.

authentication:

export  const Authentication = async(payload) =>{
    try{
    const response = await fetch(`${generalConfig.baseURL}/oauth/token`, {
        method: 'POST',
        cache: 'no-cache',
        headers: {
            'Authorization': `Basic ${btoa("topseller:topseller")}`,
            'Accept': '*/*',
            // 'Content-Type': 'multipart/form-data',
            'accept-encoding': 'gzip, deflate',
            
        },
        body: payload
    })
    .then((response)=>{
        console.log(response)
        return response.json()
    },err=>{
       console.log(err,'############')
    })
    console.log(response,'@@@@@@@@@')
    return response;
}catch(err){
    console.log(err,'############')
}
}

authentication.action:

export const getAccessToken = (dataToSend) => async (dispatch) => {
  try {
    var formData = ConvertToFormData(dataToSend);
    const authResponse = await Authentication(formData);   
    <-- See above about this Authentication function

    const response = await fetch("http://api.smartocart.com/userType", {
      method: "GET",
      cache: "no-cache",
      headers: {
        Authorization: `Bearer ${authResponse.access_token}`,
      },
    });
    const payload = await response.json();

    if (payload.status === "admin") {
      SaveToLocalStorage("access_token", authResponse.access_token);
      SaveToLocalStorage("refresh_token", authResponse.refresh_token);
      dispatch({
        type: GET_ACCESS_TOKEN,
        payload: {
          access_token: authResponse.access_token,
          refresh_token: authResponse.refresh_token,
        },
      });
    } else {
      dispatch({
        type: ERROR_ACCESS_TOKEN,
        buttonPressed: true,
      });
    }
  } catch (exception) {
    console.log("Log In again");
  }
};

I did read about this in some of the blog post but i did get this. https://nmajor.com/posts/access-and-refresh-token-handling-with-redux Any help would be highly appreciated.

2 Answers

You can add token expiry time validation on app.js so if you reload you application or move to next page or if you make api call it will check token expiry time validation always if token expired it will make call to fetch update token

check below example : i gave example with react axios

axios.interceptors.request.use(async (config) => {
  const expireAt = localStorage.getItem('expiresAt');
  let token = localStorage.getItem('authToken');
  if (dayjs(expireAt).diff(dayjs()) < 1) {
    const data = onGetForcedToken();
    token = typeof data === 'string' ? data : await data();
  }
  // setting updated token
  localStorage.setItem('authToken', token);
  return config;
}, (err) => {
   console.log("error in getting ",err)
});

If you are using Axios, you can intercept a request with the help of interceptor and call api to get a new token in case token got expired.

Another approach to get a new token is by periodically calling api after certain interval before the token gets expired.

For example in App.js

// Get new Token
const getNewUserToken = async () => {
    const submitUrl = apiRoot + "/v1/user/refreshtoken";
    try {
        const res = await fetch(submitUrl, {
            method: "GET",
            headers: {
                token: localStorage.getItem("token"),
                "Content-Type": "application/json",
            },
        });

        if (res.status === 200) {
            const data = await res.json();
            localStorage.setItem("token", data.token);
        } else {
            // New token didnt received.Remove the previous token and user 
            localStorage.removeItem("token");
            localStorage.removeItem("user");
            setUser({});
            navigate("/");
        }
    } catch (err) {
        console.log(err);
    }
};
const intervalRef = useRef();
const getToken = useCallback(() => {
    // Get new token if and only if existing token is available
    if (localStorage.getItem("token") != null) {
        getNewUserToken();
    }
}, []);

// Trigger API to get a new token before token gets expired.
useEffect(() => {
    const interval = setInterval(() => getToken(), 1000 * 60 * 6); // 6 minutes interval as our token will expire after 7 minutes.
    intervalRef.current = interval;
    return () => clearInterval(interval);
}, [getToken]);

Hope this will help you to automatically refresh the token without forcing user to login.

Related