ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [JavaScript]리프레시 토큰(Refresh Token)
    개발공부/JavaScript 2024. 1. 9. 14:21

    오늘은 토큰 관련된 내용을 다뤄보고자 한다. (Access Token, Refresh Token)

    최근에 진행하고 있는 프로젝트에서 토큰 관련 작업을 담당하게 되었는데 기록한 후 다른 사람들과 공유하면 좋을 거 같아서 글을 쓰게 되었다!

     

     

    우선 토큰 개념을 알아야 하는 이유부터 찾아봤다.

    1. 권한과 보안
      • 사용자가 로그인 상태에서 특정 서비스, 앱에 대한 권한을 부여받은 것을 의미 (사용자가 특정 리소스 접근할 권한)
      • 이를 통제하여 개인 정보 접근에 제한을 둘 수 있어 보안을 강화할 수 있음
    2. 인증과 인가 분리
      • 사용자의 인증은 Access Token을 받는 단계에서 이루어지는데, 이를 통해 리소스에 대한 인가를 받을 수 있음
    3. 사용자 경험 향상
      • Access Token 정보로 여러 서비스나 앱에 접근할 수 있음
    4. API 보호
      • 클라이언트는 Access Token을 API에 제공하여 자원에 대한 요청을 진행
      • API는 Access Token을 사용해 유요한 권한을 가진 요청만 처리하고, 무단 접근 시도를 방어할 수 있음
    즉, 토큰은 보안 및 사용자 경험 개선에서 핵심적인 역할을 함

     

     

    위와 같은 이유로 웹이나 앱에서 토큰 관리하는 방식이 매우 중요하다.

     

    Access Token

     

     

    Refresh Token이란?

    Refresh Token은 Access Token이 만료되어 갱신되어야 할 때 사용된다.

    (Access Token은 짧은 기간 동안만 유효, Refresh Token은 더 오랜 기간 유효)

     

    사용 흐름을 간단하게 정리하면 아래와 같다.

    1. 사용자가 인증을 통해 Access Token 발급
    2. Access Token이 만료되면, Refresh Token을 사용해 새로운 Access Token을 받급
    3. 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
Designed by Tistory.