개발공부/JavaScript
[JavaScript]리프레시 토큰(Refresh Token)
hani:)
2024. 1. 9. 14:21
오늘은 토큰 관련된 내용을 다뤄보고자 한다. (Access Token, Refresh Token)
최근에 진행하고 있는 프로젝트에서 토큰 관련 작업을 담당하게 되었는데 기록한 후 다른 사람들과 공유하면 좋을 거 같아서 글을 쓰게 되었다!
우선 토큰 개념을 알아야 하는 이유부터 찾아봤다.
- 권한과 보안
- 사용자가 로그인 상태에서 특정 서비스, 앱에 대한 권한을 부여받은 것을 의미 (사용자가 특정 리소스 접근할 권한)
- 이를 통제하여 개인 정보 접근에 제한을 둘 수 있어 보안을 강화할 수 있음
- 인증과 인가 분리
- 사용자의 인증은 Access Token을 받는 단계에서 이루어지는데, 이를 통해 리소스에 대한 인가를 받을 수 있음
- 사용자 경험 향상
- Access Token 정보로 여러 서비스나 앱에 접근할 수 있음
- API 보호
- 클라이언트는 Access Token을 API에 제공하여 자원에 대한 요청을 진행
- API는 Access Token을 사용해 유요한 권한을 가진 요청만 처리하고, 무단 접근 시도를 방어할 수 있음
즉, 토큰은 보안 및 사용자 경험 개선에서 핵심적인 역할을 함
위와 같은 이유로 웹이나 앱에서 토큰 관리하는 방식이 매우 중요하다.
Access Token
Refresh Token이란?
Refresh Token은 Access Token이 만료되어 갱신되어야 할 때 사용된다.
(Access Token은 짧은 기간 동안만 유효, Refresh Token은 더 오랜 기간 유효)
사용 흐름을 간단하게 정리하면 아래와 같다.
- 사용자가 인증을 통해 Access Token 발급
- Access Token이 만료되면, Refresh Token을 사용해 새로운 Access Token을 받급
- 1, 2번 과정을 반복하여 사용자가 계속해서 서비스에 접근할 수 있음
프로젝트에서 이 과정을 수행하기 위해 아래와 같이 코드를 작성했다.
(나는 세션 스토리지에 토큰 값을 저장했었다. )
import { getSession } from "@/utils/getSession";
import { removeSession } from "@/utils/removeSession";
import { saveSession } from "@/utils/saveSession";
import axios from 'axios';
// create 메서드를 사용해 HTTP 클라이언트의 인스턴스 생성하여 i저장
export const instance = axios.create({
baseURL: process.env.NEXT_PUBLIC_API_URL,
});
// axios 인스턴스에 요청 인터셉터를 등록
// 요청 전송 전에 실행되는 함수로, 여기서 세션에 있는 토큰을 가져와 헤더에 추가
instance.interceptors.request.use(
function (config) {
const accessToken = getSession("access_Token");
if (accessToken) config.headers.Authorization = accessToken;
const refreshToken = getSession("refresh_Token");
if (refreshToken) config.headers.RefreshToken = refreshToken;
return config;
},
function (error) {
return Promise.reject(error);
}
);
// axios에 응답 인터셉터를 등록 (토큰 갱신)
// 서버 응답을 처리하는 로직 존재
instance.interceptors.response.use(
(response) => {
return response;
},
async (error) => {
const { response } = error; // 디스트럭처링을 통해 response를 가져옴
if (!response) { // response가 없을 경우에 대한 예외 처리
return Promise.reject(error);
}
const { status, headers } = response;
if (status === 401) {
const config = { ...error.config };
const newToken = headers.authorization;
if (newToken) {
// 기존 토큰 제거 및 새로운 토큰 추가
removeSession("access_Token");
saveSession("access_Token", newToken);
config.headers.Authorization = newToken;
// 실패했던 기존 request 재시도
return instance(config);
}
}
return Promise.reject(error);
}
);
export default instance;
728x90