axios interceptor로 jwt token 관리 하기

김석진·2023년 3월 3일
6
post-thumbnail
post-custom-banner

interceptor란?

axios interceptor는 HTTP 요청과 응답을 가로채서 처리할 수 있는 기능이다

어디에 필요한가요?

1. 중복되는 코드들을 줄여준다

interceptor의 특징 중 하나는 요청과 응답을 가로채기 때문에 공통적으로 중복되는 코드들을 줄일 수 있다는 장점이 있다

2. 유지보수에 좋다

api 요청에 대해 일괄적으로 처리할 수 있어서 코드의 유지 보수성을 높일 수 있다

interceptor 알아보기

instance 생성

const customAxios = axios.create({
  baseURL: 'http://localhost:8080',
  timeout: 10000,
  headers: {
    'Content-Type': 'application/json',
  },
});

사용자 지정 config로 새로운 axios 인스턴스를 만들 수 있다

instance를 썼을 때 장점은 api를 호출하는 과정에서 반복되는 코드 baseURL, timeout, headers와 같은 코드들을 줄일 수 있다

request

customAxios.request.use(
  function (config) {
    // 요청을 보내기 전에 수행할 일
    return config;
  },
  function (error) {
    // 오류 요청을 보내기전 수행할 일
    return Promise.reject(error);
  });

request는 server에 요청을 보내기 전에 실행된다

response

customAxios.response.use(function (response) {
    // 응답 데이터가 있는 작업 수행
    return response;
  }, function (error) {
    // 응답 오류가 있는 작업 수행
    return Promise.reject(error);
  });

response는 서버로부터의 응답을 받은 후 실행된다

토큰 재발급 받기

그럼 interceptor를 사용해서 refreshToken을 활용한 jwt 토큰 관리를 해보자

우선 jwt에 대해 알아야 한다 jwt를 모른다면 이것을 읽고 오자

customAxios.ts

customAxios.interceptors.response.use(
  (response) => {
    return response;
  },
  (error) => {
    const { status, code, message } = error.response.data;
    if (message) {
      if (status === 401 && code === 'EXPIRED_TOKEN') {
        tokenExpired();
      }
    }
    return Promise.reject(error);
  },
);

서버에서 401과 EXPIRED_TOKEN을 던져주면 tokenExpired를 불러와 refreshToken을 이용해서 accessToken을 재발급할 것이다

tokenExpired.ts

import { customAxios } from 'lib/axios/customAxios';
import { ACCESS_KEY, REFRESH_KEY } from 'constants/token.constant';

export const tokenExpired = async () => {
  try {
    const { data } = await customAxios.put('/auth', null, {
      headers: {
        'Refresh-Token':
        `${localStorage.getItem(REFRESH_KEY)}`,
      },
    });
    localStorage.setItem(ACCESS_KEY, data.accessToken);
  } catch (err) {
    useErrorToast('세션이 만료되었습니다');
  }
};

toeknExpired에서는 서버에게 재발급 요청을 headers에 refreshToken을 집어넣어 보내주고
서버는 정상적인 refreshToken이라면 accessToken을 줄 것이다
그리고 우리는 새로운 accessToken을 storage에 저장함으로써 로그인 수명을 연장할 수 있게 된다

전체 코드

customAxios.ts

import axios from 'axios';
import { tokenExpired } from 'lib/token/tokenExpired';

const customAxios = axios.create({
  baseURL: 'http://localhost:8080',
  timeout: 10000,
  headers: {
    'Content-Type': 'application/json',
  },
});

customAxios.interceptors.request.use(
  (config) => {
    return config;
  },
  (error) => {
    return Promise.reject(error);
  },
);

customAxios.interceptors.response.use(
  (response) => {
    return response;
  },
  (error) => {
    const { status, code, message } = error.response.data;
    if (message) {
      if (status === 401 && code === 'EXPIRED_TOKEN') {
        tokenExpired();
      }
    }
    return Promise.reject(error);
  },
);
export { customAxios };

tokenExpired.ts

import { customAxios } from 'lib/axios/customAxios';
import { ACCESS_KEY, REFRESH_KEY } from 'constants/token.constant';

export const tokenExpired = async () => {
  try {
    const { data } = await customAxios.put('/auth', null, {
      headers: {
        'Refresh-Token':
        `${localStorage.getItem(REFRESH_KEY)}`,
      },
    });
    localStorage.setItem(ACCESS_KEY, data.accessToken);
  } catch (err) {
    useErrorToast('세션이 만료되었습니다');
  }
};

잘못된 내용이 있으면 언제든지 지적해 주세요

참고 한 자료

https://axios-http.com/kr/docs/interceptors
https://axios-http.com/kr/docs/instance

profile
해탈의 경지에 이르자
post-custom-banner

0개의 댓글