React 토큰 자동 갱신 (refreshToken)

오늘은 React 에서 refreshToken으로 accessToken을 자동으로 갱신 해주는 방법에 대하여 알아보도록 하겠습니다.
시작하기 앞서
jwt
토큰에 대하여 아직 모르시는 분은 [토큰을 사용하여 인증하는 방법] 게시글을 보고 오시면 굉장히 도움이 됩니다.
보안을 위하여 accessToken
의 만료시간을 짧게 하고, refreshToken
도 함께 발급하여 accessToken
이 탈취되더라도 금방 만료되게 하여 최대한 안전하게 인증이 가능합니다.
refreshToken
이란 접근에 필요한 accessToken
이 만료 되었을 때 갱신하기 위하여 필요합니다.
오늘은 이 refreshToken
으로 accessToken
을 자동으로 갱신하게 해주도록 하겠습니다.
(accessToken
과 토큰 만료시간은 로컬 스토리지, refreshToken
은 httpOnly cookie 에 저장되어 있다고 가정합니다.)
시작
axios
라는 http 통신 라이브러리에는 interceptor
가 존재합니다. 이는 http 통신을 하기 직전 함수를 실행하여 AxiosRequestConfig
를 수정할 수 있습니다.
개요
axios.interceptors.request.use()
함수에 실행할 함수를 매개변수로 넘기면 정상적으로 interceptor
가 등록됩니다.
// src/lib/refresh.ts import axios, { AxiosRequestConfig } from "axios"; import Cookie from "js-cookie"; import { RefreshTokenResponse } from "util/types/Response"; import { server } from "config/config.json"; import moment from "moment"; const refresh = async (config: AxiosRequestConfig): Promise<AxiosRequestConfig> => { const refreshToken = Cookie.get("refreshToken"); const expireAt = localStorage.getItem("expiresAt"); let token = localStorage.getItem("accessToken"); // 토큰이 만료되었고, refreshToken 이 저장되어 있을 때 if (moment(expireAt).diff(moment()) < 0 && refreshToken) { const body = { refreshToken, }; // 토큰 갱신 서버통신 const { data } = await axios.post(`${server}/auth/token`, body); token = data.data.accessToken; localStorage.setItem("accessToken", data.data.accessToken); localStorage.setItem( "expiresAt", moment().add(1, "hour").format("yyyy-MM-DD HH:mm:ss") ); } config.headers["Authorization"] = `Bearer ${token}`; return config; }; const refreshErrorHandle = (err: any) => { Cookie.remove("refreshToken"); }; export { refresh, refreshErrorHandle };
// src/lib/customApi.ts import axios from "axios"; import { server } from "config/config.json"; import { refresh, refreshErrorHandle } from "./refresh"; const Api = axios.create({ baseURL: server, timeout: 10000, params: {}, }); Api.interceptors.request.use(refresh, refreshErrorHandle); export default Api;
차근차근 코드를 살펴보면 src/lib/refresh.ts
에서는 토큰이 만료되었고, refreshToken
이 저장되어 있다면, 토큰을 갱신하는 api를 호출 후 새로운 accessToken
을 받아옵니다. 그 이후 config header
에 등록하여 정상적으로 인증을 할 수 있도록 합니다.
src/lib/customApi.ts
는 axios.interceptors.request.use()
로 등록을 하면 전역으로 interceptor
가 등록된 것이 아니기 때문에 axios.create
를 이용하여 전역으로 등록되게 합니다.
마무리
이제 유저 정보를 불러오는 api를 호출 할 때에는
import Api from "lib/customApi.ts"; const getInfo = async (email: string, pw: string) => { const { data } = await Api.get("/auth/getInfo"); return data; }
이런식으로 사용하시면 됩니다.
그러면 localStorage
에 저장된 토큰 만료시간이 초과 되었고, refreshToken
이 저장되어 있다면, 자동으로 새로운 토큰을 발급 받고 api를 호출하게 됩니다.
마치며
refreshToken
이 어떤식으로 돌아가는지는 이해하였지만 실제 프로젝트에 적용 해본적이 처음이라axios interceptor
를 이용하여 적용하였는데 굉장히 편리하더라구요.