Dev/etc.

JWT 인증과 인가 흐름

takeU 2025. 3. 12. 00:16
반응형

JWT 인증과 인가 흐름

1. Axios 인터셉터를 활용한 자동 토큰 갱신 예시

Axios 인터셉터 설정

  • Axios를 사용하여 Access Token의 만료를 감지하고, Refresh Token을 사용하여 새로운 Access Token을 발급받는 방식으로 자동화할 수 있음.
import axios from 'axios';

// Axios 인스턴스 생성
const api = axios.create({
  baseURL: 'https://example.com/api',
  timeout: 10000,
  headers: { 'Content-Type': 'application/json' },
});

// 요청 인터셉터 (요청이 보내지기 전에 처리)
api.interceptors.request.use(
  config => {
    // localStorage에서 Access Token을 가져와 Authorization 헤더에 넣음
    const accessToken = localStorage.getItem('accessToken');
    if (accessToken) {
      config.headers['Authorization'] = `Bearer ${accessToken}`;
    }
    return config;
  },
  error => Promise.reject(error)
);

// 응답 인터셉터 (응답이 돌아왔을 때 처리)
api.interceptors.response.use(
  response => {
    // 정상적인 응답 처리
    return response;
  },
  async error => {
    // 401 에러 (Access Token 만료된 경우) 처리
    if (error.response && error.response.status === 401) {
      try {
        // Refresh Token을 사용하여 새로운 Access Token 요청
        const refreshToken = localStorage.getItem('refreshToken');
        const response = await axios.post('/api/refresh-token', { refreshToken });

        // 새로운 Access Token을 localStorage에 저장
        const { accessToken } = response.data;
        localStorage.setItem('accessToken', accessToken);

        // 원래의 요청을 새로운 Access Token으로 재요청
        const originalRequest = error.config;
        originalRequest.headers['Authorization'] = `Bearer ${accessToken}`;

        return api(originalRequest);  // 재요청
      } catch (refreshError) {
        // Refresh Token이 만료되었거나 에러가 발생한 경우, 로그아웃 처리
        console.error('Refresh Token도 만료되었거나 에러가 발생했습니다.');
        // 예: 로그아웃 처리
        window.location.href = '/login';
      }
    }

    // 401 외의 오류는 그대로 처리
    return Promise.reject(error);
  }
);

export default api;

작동 원리

  1. 요청 인터셉터: 모든 API 요청 전에 Access Token을 Authorization 헤더에 추가.
  2. 응답 인터셉터: 응답에서 401 Unauthorized 에러가 발생하면, Refresh Token을 사용하여 새로운 Access Token을 요청하고, 이를 사용해 원래 요청을 재전송.
  3. 자동 토큰 갱신: Access Token이 만료되면, Refresh Token을 통해 새로운 토큰을 발급받아 자동으로 재요청함.

2. Access Token과 Refresh Token의 정의 및 저장 방법

Access Token

  • 정의:

    • 인증된 사용자의 권한을 증명하는 짧은 유효 기간을 가진 JWT 토큰.
    • 서버에서 생성하고, 클라이언트는 이를 사용하여 보호된 리소스에 접근할 수 있음.
  • 저장 방법:

    • 보통 localStorage 또는 쿠키에 저장됨.
  • 장점:

    • 서버에 요청 시 빠르게 인증을 처리할 수 있음.
    • 클라이언트에서 쉽게 헤더에 추가하여 요청할 수 있음.
  • 단점:

    • 유효 기간이 짧아, 만료 후 갱신이 필요함.
    • localStorage에 저장 시 XSS 공격에 취약할 수 있음.
    • 쿠키에 저장CSRF 공격에 취약할 수 있음.

Refresh Token

  • 정의:

    • Access Token의 만료 후, 새로운 Access Token을 발급받기 위한 긴 유효 기간을 가진 JWT 또는 임의의 문자열.
    • 일반적으로 서버에서만 저장되며, 클라이언트는 이를 통해 Access Token을 갱신할 수 있음.
  • 저장 방법:

    • 보통 httpOnly 쿠키에 저장하여 XSS 공격으로부터 보호.
  • 장점:

    • 긴 유효 기간을 가지므로 Access Token의 만료 시 계속해서 새로운 Access Token을 발급받을 수 있음.
    • httpOnly 쿠키에 저장하면 XSS 공격에 강한 보안을 제공함.
  • 단점:

    • Refresh Token의 탈취가 발생하면 액세스 권한을 부여받은 상태로 새로운 Access Token을 발급받을 수 있기 때문에 보안상 위험이 있음.
    • 만약 로그아웃 처리가 제대로 되어 있지 않으면, Refresh Token이 계속해서 사용될 수 있음.

3. Access Token과 Refresh Token의 저장 방법 비교

저장 방법 장점 단점
localStorage - 쉽게 접근 가능하고, 다른 요청에서 사용하기 용이함. - XSS 공격에 취약함.
쿠키 (일반 쿠키) - CSRF 공격에 취약할 수 있음. - 쿠키의 크기에 제한이 있어, 저장할 수 있는 정보에 제한이 있음.
쿠키 (httpOnly) - XSS 공격에 강함. - CSRF 공격에 취약할 수 있음.
세션 저장소 - 세션이 끝날 때 토큰이 자동으로 삭제됨. - 페이지 새로 고침 시 토큰이 삭제됨.

추천

  • Access TokenlocalStorage에 저장하고, Refresh TokenhttpOnly 쿠키에 저장하는 것이 보안성편리성을 고려한 좋은 방법임.
    • localStorageAccess Token을 저장하면 서버 요청 시 빠르게 Authorization 헤더에 추가할 수 있음.
    • httpOnly 쿠키에 Refresh Token을 저장하면 XSS 공격으로부터 보호받을 수 있음.

4. 요약

  • 프런트엔드Access TokenAuthorization 헤더에 포함하여 API 요청을 보냄.
  • 서버는 Access Token검증하여 유효하면 요청을 처리하고, 유효하지 않으면 401 Unauthorized를 반환함.
  • 401 오류가 발생하면, 프런트엔드Refresh Token을 사용하여 새로운 Access Token을 발급받고, 이를 사용해 원래의 요청을 다시 보냄.
  • Access Token짧은 유효 기간을 가지며 localStorage 또는 쿠키에 저장됨.
  • Refresh Token긴 유효 기간을 가지며, 보통 httpOnly 쿠키에 저장됨.
반응형