OAuth2와 JWT는 다른 개념이다

OAuth2 = 인증/인가 프레임워크 (규약/프로토콜)
JWT = 토큰 형식 (데이터 포맷)

OAuth2는 “어떻게 인증할지”를 정의하고, JWT는 “토큰을 어떤 형식으로 만들지”를 정의한다.

비유

OAuth2 = 택배 시스템 (절차/규칙)
JWT = 택배 상자 형태 (포장 방식)

택배 시스템(OAuth2)에서 상자(토큰)를 어떤 형태로 쓸지는 선택할 수 있다.


OAuth2 토큰 종류

OAuth2에서 사용하는 토큰은 크게 두 가지 형식이 있다.

1. Opaque Token (불투명 토큰)

토큰: a1b2c3d4-e5f6-7890-abcd-ef1234567890

랜덤 문자열로, 토큰 자체에는 아무 정보가 없다.

검증 방식:

Client ──────▶ Resource Server ──────▶ Auth Server
                                        "이 토큰 유효해?"
               ◀─────────────────────── "응, user_id=123이야"
장점 단점
토큰 탈취 시 즉시 무효화 가능 매번 Auth Server 호출 필요
토큰에 정보 노출 없음 Auth Server 장애 시 전체 장애
구현 단순 네트워크 오버헤드

2. JWT (JSON Web Token)

토큰: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJmYXgtc2NoZWR1bGVyIi...

토큰 자체에 정보가 포함되어 있다.

JWT 구조:

┌─────────────────────────────────────────────────────┐
│  Header (헤더)                                       │
│  { "alg": "RS256", "typ": "JWT" }                   │
├─────────────────────────────────────────────────────┤
│  Payload (페이로드)                                  │
│  {                                                  │
│    "sub": "fax-scheduler",                          │
│    "scope": ["user:read", "user:write"],            │
│    "session": "{\"userId\":100}",                   │
│    "iat": 1699999000,                               │
│    "exp": 1699999999                                │
│  }                                                  │
├─────────────────────────────────────────────────────┤
│  Signature (서명)                                    │
│  RSASHA256(base64(header) + "." + base64(payload))  │
└─────────────────────────────────────────────────────┘

검증 방식:

Client ──────▶ Resource Server
               └─ 서명 검증 (공개키로)
               └─ 만료 시간 확인
               └─ Claim 추출
               └─ 요청 처리

Auth Server 호출 없이 자체 검증 가능.

장점 단점
Auth Server 호출 불필요 토큰 탈취 시 만료까지 유효
빠른 검증 토큰 크기가 큼
Stateless Payload 정보 노출 (암호화 아님)

Opaque Token vs JWT 비교

구분 Opaque Token JWT
토큰 내용 랜덤 문자열 정보 포함 (Base64)
검증 방법 Auth Server 호출 자체 검증 (서명)
무효화 즉시 가능 만료까지 불가
크기 작음
상태 Stateful Stateless
적합한 환경 보안 중요, 단일 서버 MSA, 분산 시스템

OAuth2 Grant Types

OAuth2는 상황에 따라 다른 인증 방식(Grant Type)을 제공한다.

1. Authorization Code Grant

사용자가 로그인하는 일반적인 웹 애플리케이션용.

┌────────┐     ┌────────┐     ┌─────────────┐     ┌──────────┐
│  User  │────▶│ Client │────▶│ Auth Server │────▶│ Resource │
└────────┘     └────────┘     └─────────────┘     └──────────┘
    │              │                │
    │  1. 로그인 요청  │                │
    │──────────────▶│                │
    │              │  2. 로그인 페이지  │
    │              │───────────────▶│
    │              │                │
    │  3. ID/PW 입력  │                │
    │──────────────────────────────▶│
    │              │  4. Auth Code   │
    │              │◀───────────────│
    │              │  5. Token 교환   │
    │              │───────────────▶│
    │              │  6. Access Token│
    │              │◀───────────────│

2. Client Credentials Grant

서버 간 통신용 (사용자 없음).

┌────────────────┐     ┌─────────────┐     ┌──────────────┐
│ fax-scheduler  │────▶│ Auth Server │────▶│   fax-api    │
│   (Client)     │     │             │     │  (Resource)  │
└────────────────┘     └─────────────┘     └──────────────┘
        │                    │                    │
        │ 1. 토큰 요청         │                    │
        │ (client_id/secret) │                    │
        │───────────────────▶│                    │
        │                    │                    │
        │ 2. JWT 토큰 발급     │                    │
        │◀───────────────────│                    │
        │                    │                    │
        │ 3. API 호출 (Bearer Token)              │
        │────────────────────────────────────────▶│
        │                    │                    │
        │ 4. 응답             │                    │
        │◀────────────────────────────────────────│

MSA 환경에서 서비스 간 통신에 주로 사용.

spring:
  security:
    oauth2:
      client:
        registration:
          internal:
            authorization-grant-type: client_credentials
            client-id: fax-scheduler
            scope: scheduler

OAuth2 구성 요소

역할 분리

구성요소 역할 예시
Authorization Server 토큰 발급 Auth Server
Resource Server 토큰 검증, API 제공 fax-api
Client 토큰 요청, API 호출 fax-scheduler
Resource Owner 리소스 소유자 사용자 (또는 서비스)

MSA에서의 구성

┌─────────────────────────────────────────────────────────────┐
│                      MSA 환경                                │
│                                                              │
│  ┌──────────────┐                                           │
│  │ Auth Server  │◀─── 토큰 발급 요청                         │
│  │              │                                           │
│  └──────────────┘                                           │
│         │                                                    │
│         │ JWT (동일한 RSA 키페어 공유)                         │
│         ▼                                                    │
│  ┌──────────────┐     ┌──────────────┐     ┌──────────────┐ │
│  │ user-service │     │order-service │     │ file-service │ │
│  │ (Resource)   │     │ (Resource)   │     │ (Resource)   │ │
│  └──────────────┘     └──────────────┘     └──────────────┘ │
│         ▲                   ▲                   ▲           │
│         │                   │                   │           │
│         └───────────────────┴───────────────────┘           │
│                             │                                │
│                    ┌──────────────┐                         │
│                    │   scheduler  │                         │
│                    │   (Client)   │                         │
│                    └──────────────┘                         │
└─────────────────────────────────────────────────────────────┘

Spring Security의 OAuth2 지원 변화

과거: Spring Security OAuth2 (Deprecated)

// Resource Server 설정
@EnableResourceServer
public class Config extends ResourceServerConfigurerAdapter {

	@Bean
	public JwtAccessTokenConverter accessTokenConverter() { ...}

	@Bean
	public TokenStore tokenStore() { ...}

	@Bean
	public DefaultTokenServices tokenServices() { ...}
}
  • 2022년 5월 프로젝트 종료
  • 별도 라이브러리: spring-security-oauth2

현재: Spring Security 6.x

// Resource Server 설정
@EnableWebSecurity
class Config {

    @Bean
    fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
        return http
            .oauth2ResourceServer { it.jwt { } }
            .build()
    }

    @Bean
    fun jwtDecoder(): JwtDecoder {
        return NimbusJwtDecoder.withPublicKey(publicKey).build()
    }
}
  • Spring Security 코어에 통합
  • Nimbus JOSE+JWT 라이브러리 사용

변경 비교

구분 Spring Security OAuth2 Spring Security 6.x
상태 Deprecated 현재 표준
어노테이션 @EnableResourceServer @EnableWebSecurity
설정 방식 Adapter 상속 SecurityFilterChain Bean
JWT 처리 JwtAccessTokenConverter NimbusJwtDecoder
빈 개수 3개+ 1~2개

JWT 검증 방식

공개키/개인키 (RSA)

Auth Server (토큰 발급)          Resource Server (토큰 검증)
┌─────────────────────┐         ┌─────────────────────┐
│                     │         │                     │
│  개인키로 서명        │         │  공개키로 검증        │
│  (Private Key)      │         │  (Public Key)       │
│                     │         │                     │
└─────────────────────┘         └─────────────────────┘
         │                               ▲
         │         JWT 토큰              │
         └───────────────────────────────┘
  • Auth Server만 개인키 보유 (서명 가능)
  • Resource Server는 공개키로 검증만

대칭키 (HMAC)

Auth Server & Resource Server 모두 동일한 Secret 공유
  • 설정 간단
  • Secret 유출 시 위험

정리

개념 역할 관계
OAuth2 인증/인가 프로토콜 JWT를 토큰 형식으로 선택 가능
JWT 토큰 데이터 형식 OAuth2에서 사용될 수 있음
Opaque Token 토큰 데이터 형식 OAuth2에서 사용될 수 있음
Spring Security 보안 프레임워크 OAuth2, JWT 구현 제공
Spring Security 6.x
├── oauth2ResourceServer { }    ← Resource Server 설정
├── oauth2Client { }            ← Client 설정
├── oauth2Login { }             ← 로그인 설정
└── NimbusJwtDecoder            ← JWT 검증

OAuth2는 프로토콜이고, JWT는 토큰 형식이다. 둘은 독립적이지만 함께 사용되는 경우가 많다.