How to use refresh token in reactjs
Asked Answered
P

2

10

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.

Pinchpenny answered 6/6, 2020 at 9:2 Comment(0)
E
9

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)
});
Explorer answered 6/6, 2020 at 9:59 Comment(8)
what is this dayjs here can you please explain about this.Pinchpenny
The example is based on axios as you mention but the code of the question is based on fetch.Shanly
Expiry time of the token is just one of the reasons that access-token validation might fail (such as jwt secret change that invalidated all tokens for everyone). Hence you would need to have a similar logic in response interceptors as well for the case that validation fails on the server side.Lungi
what if the token is stored in cookieFairspoken
@Fairspoken in this case you need an endpoint on server side to check the token that is stored in cookie. Server checks that token and if it is expired or not valid return 403, front-end then sees the status 403 of refresh-token endpoint response, removes any stored data (access_token from localStorage) and redirects the user to the login page. Through the login page user should login and get fresh access and refresh tokensErectile
You also should set the token in cookies to the empty string or remove the cookies. This is done by server.Erectile
@adityakumar dayjs is a minimalist js library for handling dates. It's a modern alternative to the popular moment.js library. Read here: day.jsTodhunter
How can we update the auth context with the updated token?Todhunter
P
0

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.

Plea answered 30/3, 2022 at 8:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.