Token Authentication vs. JWT

토큰 인증과 JWT는 모두 현대적인 웹 애플리케이션에서 사용자 인증을 관리하는 방법이지만, 이 둘 사이에는 중요한 차이점이 있다.

토큰 인증(Token Authentication)

토큰 인증은 사용자의 인증 정보를 검증한 후 서버가 고유한 토큰을 발급하고, 클라이언트가 이후 요청 시 이 토큰을 제시하여 자신을 인증하는 광범위한 인증 패러다임이다.

기본 개념 및 특징

  1. 일반적 작동 방식:
    • 사용자가 자격 증명(username/password)을 제출한다.
    • 서버는 이를 검증하고 고유한 토큰을 생성한다.
    • 클라이언트는 이 토큰을 저장하고 향후 요청 시 제시한다.
    • 서버는 토큰을 검증하여 사용자를 식별한다.
  2. 토큰 형태:
    • 단순 무작위 문자열(UUID 등)
    • 해시된 값
    • 인코딩된 데이터 구조(JWT, SAML 등)
    • 암호화된 페이로드
  3. 서버 측 저장:
    • 대부분의 전통적인 토큰 시스템은 서버 측 저장소(데이터베이스, 캐시 등)에 토큰 정보를 보관한다.
    • 토큰 자체는 단순한 식별자 역할을 하며, 관련 정보는 서버에서 조회한다.
  4. 토큰 관리:
    • 서버가 발급한 토큰의 유효성을 관리한다.
    • 만료, 폐기, 갱신 등의 작업이 서버 측에서 제어된다.

JWT(JSON Web Token)

JWT는 토큰 인증의 한 형태로, 정보를 안전하게 전송하기 위한 컴팩트하고 자체 포함적인(self-contained) JSON 객체이다. JWT는 RFC 7519에 정의된 개방형 표준이다.

기본 개념 및 특징

  1. 구조:
    • 헤더(Header): 토큰 유형과 사용된 서명 알고리즘 정보
    • 페이로드(Payload): 클레임(사용자 정보, 권한 등)
    • 서명(Signature): 토큰의 무결성을 보장하는 서명
  2. 형식:
    • xxxxx.yyyyy.zzzzz 형태의 점으로 구분된 세 부분으로 구성
    • Base64Url로 인코딩된 JSON 객체
  3. 자체 포함성:
    • JWT는 사용자 식별에 필요한 모든 정보를 토큰 내에 포함한다.
    • 서버 측 세션 저장소가 필요 없다(무상태 인증).
  4. 서명 검증:
    • 비밀 키(HMAC) 또는 공개/개인 키 쌍(RSA, ECDSA)을 사용하여 토큰에 서명한다.
    • 서버는 토큰의 서명을 검증하여 내용이 변조되지 않았는지 확인한다.

토큰 인증 vs. JWT 비교

특성일반 토큰 인증JWT
정의토큰을 통한 인증 패러다임토큰 인증의 특정 구현 형태
관계상위 개념(일반적 접근법)하위 개념(특정 기술)
구조다양함(구현에 따라 다름)표준화된 형식(헤더.페이로드.서명)
정보 포함일반적으로 식별자만 포함사용자 정보, 권한 등 다양한 클레임 포함
서버 저장소대부분 필요함필요 없음(자체 포함적)
상태 관리주로 상태 유지(Stateful)무상태(Stateless)
크기작음(보통 단순 문자열)상대적으로 큼(포함된 정보에 따라)
검증 방식서버 측 데이터베이스 조회암호화 서명 검증
유연성구현에 따라 다양한 방식 가능표준화된 구조와 작동 방식
폐기(Revocation)용이함(서버에서 삭제)어려움(블랙리스트 필요)
보안 메커니즘구현에 따라 다양함암호화 서명 기반
표준화표준화되지 않음RFC 7519로 표준화됨
투명성토큰 내용이 불투명함디코딩 가능(내용 확인 가능)
확장성서버 측 저장소에 의존높음(무상태 특성)
마이크로서비스 적합성낮음높음(자체 포함적 특성)
구현 복잡성다양함(구현에 따라)라이브러리를 통해 단순화

심층 분석

  1. 개념적 관계
    토큰 인증은 JWT를 포함하는 상위 개념이다. 토큰 인증이라는 큰 범주 안에 JWT, 단순 문자열 토큰, OAuth 토큰 등 다양한 구현 방식이 존재한다. 즉, “토큰 인증 vs JWT"라는 구도는 정확히는 “일반 범주 vs 특정 구현"의 비교이다.

  2. 전통적인 토큰 인증 방식
    전통적인 토큰 인증에서는 서버가 무작위 문자열(예: UUID)을 생성하고, 이 토큰을 키로 사용하여 사용자 정보를 데이터베이스나 캐시에 저장한다. 클라이언트가 요청할 때마다 이 토큰을 제시하면, 서버는 데이터베이스에서 이 토큰에 해당하는 사용자 정보를 조회하여 인증을 처리한다.

    1
    2
    3
    4
    
    1. 클라이언트: 로그인 요청(username + password)
    2. 서버: 자격 증명 검증 → 무작위 토큰 생성 → 데이터베이스에 토큰과 사용자 정보 저장 → 토큰 반환
    3. 클라이언트: 요청 + 토큰
    4. 서버: 데이터베이스에서 토큰 조회 → 사용자 정보 확인 → 요청 처리
    
  3. JWT의 작동 방식
    JWT에서는 서버가 사용자 정보, 권한, 만료 시간 등을 포함한 JSON 객체를 생성하고, 이를 비밀 키로 서명한 후 Base64Url로 인코딩하여 클라이언트에 전송한다. 클라이언트가 이후 요청 시 이 JWT를 제시하면, 서버는 서명을 검증하고 토큰 내부의 정보를 사용하여 인증을 처리한다.

    1
    2
    3
    4
    
    1. 클라이언트: 로그인 요청(username + password)
    2. 서버: 자격 증명 검증 → JWT 생성(사용자 정보 포함) → 비밀 키로 서명 → JWT 반환
    3. 클라이언트: 요청 + JWT
    4. 서버: JWT 서명 검증 → 토큰 내 포함된 사용자 정보 추출 → 요청 처리
    

장단점

일반 토큰 인증의 장단점

장점:

  • 토큰 폐기(revocation)가 쉽다(데이터베이스에서 삭제만 하면 됨).
  • 토큰 크기가 작아 네트워크 오버헤드가 낮다.
  • 토큰 내용이 클라이언트에게 불투명하여 민감한 정보를 포함할 수 있다.
  • 세션 데이터를 동적으로 갱신할 수 있다.

단점:

  • 서버 측 저장소가 필요하여 확장성이 제한된다.
  • 다중 서버 환경에서는 토큰 데이터 동기화가 필요하다.
  • 모든 인증 요청마다 데이터베이스 조회가 필요하다.
  • 마이크로서비스 아키텍처에 적용하기 어렵다.
JWT의 장단점

장점:

  • 무상태(Stateless) 특성으로 서버 확장성이 우수하다.
  • 서버 측 저장소가 필요하지 않아 데이터베이스 부하가 줄어든다.
  • 마이크로서비스 환경에 적합하다.
  • 토큰 자체에 사용자 정보를 포함하여 추가 조회가 필요 없다.
  • 표준화된 형식으로 다양한 언어와 플랫폼에서 지원된다.

단점:

  • 토큰 폐기가 어렵다(발급된 토큰은 만료 시간까지 유효).
  • 토큰 크기가 커 네트워크 오버헤드가 발생할 수 있다.
  • 민감한 정보를 포함하기 어렵다(서명은 되어 있지만 내용은 디코딩 가능).
  • 토큰 갱신 메커니즘 구현이 복잡할 수 있다.
  • 비밀 키 관리가 중요한 보안 요소이다.

사용 시나리오 및 선택 가이드

일반 토큰 인증이 적합한 경우

  • 토큰 즉시 폐기 기능이 중요한 애플리케이션
  • 사용자 세션 데이터를 동적으로 업데이트해야 하는 경우
  • 토큰 크기를 최소화해야 하는 경우
  • 단일 서버 환경 또는 세션 클러스터링이 구현된 환경

JWT가 적합한 경우

  • 마이크로서비스 아키텍처
  • 서버리스 함수
  • 높은 확장성이 요구되는 애플리케이션
  • 다중 서버/도메인 간 인증이 필요한 경우
  • 데이터베이스 조회를 최소화해야 하는 경우

최신 동향 및 하이브리드 접근법

최근에는 두 방식의 장점을 결합한 하이브리드 접근법이 증가하고 있다:

  1. JWT + 토큰 블랙리스트: JWT의 확장성을 유지하면서 Redis와 같은 인메모리 데이터베이스에 폐기된 토큰 목록을 관리한다.
  2. 짧은 수명 JWT + 리프레시 토큰: 짧은 수명의 JWT와 더 긴 수명의 리프레시 토큰을 함께 사용하여 보안과 사용자 경험을 개선한다.
  3. JWT 서비스 계층: 전용 인증 서비스에서만 JWT를 처리하고, 다른 서비스는 이 서비스의 결정을 신뢰하는 아키텍처를 구축한다.

기술적 구현 예시

일반 토큰 인증 구현 (Node.js)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 토큰 생성 (로그인 시)
function generateToken(user) {
  const token = crypto.randomBytes(32).toString('hex');
  // 토큰을 데이터베이스나 Redis에 저장
  tokenStore.set(token, {
    userId: user.id,
    permissions: user.permissions,
    createdAt: new Date()
  });
  return token;
}

// 토큰 검증 (요청 시)
function verifyToken(token) {
  // 데이터베이스에서 토큰 조회
  const tokenData = tokenStore.get(token);
  if (!tokenData) {
    throw new Error('Invalid token');
  }
  // 선택적으로 만료 검사
  if (isExpired(tokenData.createdAt)) {
    tokenStore.delete(token);
    throw new Error('Token expired');
  }
  return tokenData;
}

JWT 구현 (Node.js)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
// JWT 생성 (로그인 시)
function generateJWT(user) {
  const payload = {
    sub: user.id,
    name: user.name,
    permissions: user.permissions,
    iat: Math.floor(Date.now() / 1000),
    exp: Math.floor(Date.now() / 1000) + (60 * 60) // 1시간 후 만료
  };
  
  return jwt.sign(payload, SECRET_KEY);
}

// JWT 검증 (요청 시)
function verifyJWT(token) {
  try {
    const decoded = jwt.verify(token, SECRET_KEY);
    return decoded;
  } catch (err) {
    throw new Error('Invalid token');
  }
}

용어 정리

용어설명

참고 및 출처