본문 바로가기
FE/react

[React] axios interceptor header 토큰 갱신

by s0ojin 2023. 4. 28.

 

이전 글


[React] 리액트 refresh token 구현 (with. axios interceptor)

 

이전 코드


import axios from 'axios';

//토큰이 불필요한 경우
export const publicApi = axios.create({
  baseURL: `${process.env.REACT_APP_SERVER_IP}`,
});

//토큰을 함께 보내는 instance
export const privateApi = axios.create({
  baseURL: `${process.env.REACT_APP_SERVER_IP}`,
  headers: {
    Authorization: `Bearer ${localStorage.getItem('accessToken')}`,
  },
});

//리프레시토큰 요청 api
function postRefreshToken() {
  const response = publicApi.post('/api/v1/auth/refresh', {
    refreshToken: localStorage.getItem('refreshToken'),
  });
  return response;
}

//리프레시 토큰 구현
privateApi.interceptors.response.use(
  (response) => {
    return response;
  },
  async (error) => {
    const {
      config,
      response: { status },
    } = error;

    if (status === 401) {
      if (error.response.data.message === 'Unauthorized') {
        const originRequest = config;
        try {
          const tokenResponse = await postRefreshToken();
          if (tokenResponse.status === 201) {
            const newAccessToken = tokenResponse.data.token;
            localStorage.setItem('accessToken', tokenResponse.data.token);
            localStorage.setItem(
              'refreshToken',
              tokenResponse.data.refreshToken,
            );
            axios.defaults.headers.common.Authorization = `Bearer ${newAccessToken}`;
            originRequest.headers.Authorization = `Bearer ${newAccessToken}`;
            return axios(originRequest);
          }
        } catch (error) {
          if (axios.isAxiosError(error)) {
            if (
              error.response?.status === 404 ||
              error.response?.status === 422
            ) {
              alert(LOGIN.MESSAGE.EXPIRED);
              window.location.replace('/sign-in');
            } else {
              alert(LOGIN.MESSAGE.ETC);
            }
          }
        }
      }
    }
    return Promise.reject(error);
  },
);

 

문제 상황


이전 글에서 axios interceptor를 활용하여 refresh token을 구현했습니다. 이후 문제가 하나 발생했는데, 

 

빨간색 요청이 401에러가 나온것이고, 이후 refresh token 요청이후 진행 중이던 요청을 제대로 완료하는 것을 볼 수 있습니다. 그러나 다시 한번 요청을 해보면 방금 토큰을 갱신했는데 또 유효하지 않은 토큰이라서 401응답이 오고 refresh api를 재요청 하는 것을 반복합니다.

 

위 코드를 읽어보면 알 수 있듯, 저는 새로운 토큰을 발급받아 로컬스토리지에 저장했습니다. 그리고 api 요청을 보낼 때 로컬 스토리지에서 꺼낸 토큰을 담아 보냅니다. 

 

확인해보니 refresh token 응답이 제대로 오고, 로컬스토리지에도 바뀐 토큰이 즉시 저장되고 있었습니다.

그러나 그 다음 요청을 열어보니, 변경된 토큰을 보내지 않고 이전 토큰을 통해 요청하는 것을 확인했습니다.

 

해결 방법


privateApi.interceptors.request.use를 이용해서 요청을 보낼 때 헤더의 토큰을 변경해서 보내주면 됩니다. 

privateApi.interceptors.request.use((config) => {
  const token = localStorage.getItem('accessToken');
  config.headers.Authorization = 'Bearer ' + token;

  return config;
});

 

이후 테스트해보니 변경된 토큰으로 잘 요청하는 것을 확인하였습니다.

 

 

 

 

댓글