개발이야기/웹개발

[코드잇 스프린트 풀스택 4기] React 애플리케이션에서 JWT를 사용하여 인증 시스템 구현하기

스탠다드 2025. 3. 30. 08:59
반응형

1. 개요

JWT(JSON Web Token)는 서버가 사용자를 인증한 후 클라이언트에게 토큰을 발급하여, 클라이언트가 이후 요청 시 토큰을 포함시켜 인증 상태를 유지하도록 하는 방식이다. React와 같은 SPA(Single Page Application)에서는 이 토큰을 활용해 사용자의 로그인/로그아웃 상태를 관리할 수 있다.

JWT의 기본 개념, React 내에서의 인증 상태 관리, 그리고 로그아웃 구현 로직에 대해

 

알아보자.

 

2. JWT 인증 흐름

  1. 로그인 과정
    • 사용자가 로그인 폼에 자격 증명을 입력하면, 백엔드 서버는 해당 정보를 검증
    • 인증에 성공하면 서버는 사용자의 정보를 포함한 JWT를 생성하여 클라이언트에 전달
    • 클라이언트는 이 토큰을 안전한 저장소(예: localStorage, sessionStorage 또는 보안 쿠키)에 저장
      (보안상의 이유로 XSS 공격에 취약할 수 있는 localStorage 대신 httpOnly 쿠키 사용 고려 가능)
  2. 인증된 요청
    • 클라이언트는 이후의 API 요청 시 JWT를 HTTP 헤더(주로 Authorization: Bearer <토큰>)에 포함하여 전송
    • 서버는 요청마다 JWT의 유효성을 확인하고, 인증이 필요한 리소스에 대한 접근 권한을 부여
  3. 토큰 갱신 및 만료
    • JWT에는 보통 만료 시간이 포함되어 있어, 만료 시 재인증이나 리프레시 토큰을 통해 새로운 JWT를 발급이 가능

 

3. React 애플리케이션에서의 인증 구현

 

3.1 전역 상태 관리

  • React에서는 Context API나 Redux와 같은 상태 관리 라이브러리를 활용하여 인증 상태를 전역으로 관리
  • 예를 들어, AuthContext를 생성하여 로그인, 로그아웃, 그리고 사용자 정보 등의 관리가 가능

3.2 토큰 저장 및 사용

  • 저장 위치:
    • localStorage: 간단하지만 XSS 공격에 취약할 수 있음
    • httpOnly 쿠키: 스크립트 접근이 불가능하여 보안성이 높음
  • 요청 시 토큰 사용:
    Axios나 Fetch API를 사용할 때 인터셉터(interceptor)를 설정하여, 모든 요청에 JWT를 자동으로 포함시킬 수 있음

 

4. 로그아웃 구현 로직

로그아웃은 기본적으로 클라이언트 측에서 JWT를 제거하고, 인증 상태를 업데이트하는 방식으로 구현

4.1 클라이언트 측 로그아웃

  • 토큰 삭제:
    • 사용자가 로그아웃 버튼을 클릭하면 localStorage(또는 해당 저장소)에서 JWT를 삭제
  • 상태 초기화:
    • 전역 인증 상태(예: user 또는 isAuthenticated)를 초기화하여 사용자가 더 이상 인증된 상태로 간주되지 않도록 함
  • UI 업데이트:
    • 로그인 페이지로 리다이렉션하거나, 사용자 관련 데이터를 초기화

 

예시 코드 

// AuthContext.js
import React, { createContext, useState, useEffect } from 'react';

export const AuthContext = createContext();

export const AuthProvider = ({ children }) => {
  const [user, setUser] = useState(null);
  
  useEffect(() => {
    // 초기 토큰 존재 여부 확인
    const token = localStorage.getItem('token');
    if (token) {
      // 필요한 경우 토큰 검증 및 사용자 정보 복호화
      setUser({ token });
    }
  }, []);

  const login = (token) => {
    localStorage.setItem('token', token);
    setUser({ token });
  };

  const logout = () => {
    // 토큰 제거 및 인증 상태 초기화
    localStorage.removeItem('token');
    setUser(null);
    // 필요 시 애플리케이션 캐시나 기타 상태 초기화
  };

  return (
    <AuthContext.Provider value={{ user, login, logout }}>
      {children}
    </AuthContext.Provider>
  );
};

 

4.2 서버 측 고려사항

  • 토큰 블랙리스트 처리:
    서버에서 JWT 자체는 상태를 갖지 않는(stateless) 방식이므로, 단순히 클라이언트가 토큰을 삭제하는 것으로 로그아웃 처리 가능
  • 하지만 보안 강화가 필요한 경우, 서버 측에서 JWT를 블랙리스트에 추가하여 더 이상 해당 토큰을 사용할 수 없도록 할 수 있음
  • 세션 관리:
    만약 httpOnly 쿠키를 사용한다면, 로그아웃 시 서버에서 쿠키를 삭제하거나 만료시키는 API를 호출할 수 있음

 

5. 추가 고려사항

  • 보안 강화:
    • XSS 공격으로부터 토큰을 보호하기 위해 httpOnly 쿠키 사용을 고려
    • CSRF 공격에 대비하여 CSRF 토큰 사용 또는 SameSite 쿠키 속성 설정
  • 토큰 만료 및 갱신:
    • JWT 만료 시간에 따른 자동 로그아웃 기능 구현
    • 리프레시 토큰을 활용하여 만료된 토큰을 갱신하는 로직 추가
  • 에러 처리:
    • 만약 토큰이 만료되었거나 유효하지 않은 경우, API 응답에 따라 자동 로그아웃 처리 및 사용자에게 재로그인을 요청하는 UI 제공

 

6. 결론

  • React 애플리케이션에서 JWT 기반 인증 시스템은 클라이언트와 서버 간의 안전한 통신을 보장하면서 사용자의 로그인 상태를 효과적으로 관리할 수 있는 방법
  • 로그아웃 구현은 주로 클라이언트 측에서 JWT를 제거하고 전역 인증 상태를 업데이트하는 방식으로 진행되며, 보안 요구사항에 따라 서버 측에서 추가적인 토큰 무효화 로직을 적용할 수도 있음
반응형
댓글수0