앞선 글에서는 Session 기반 인증에서 서버가 로그인 상태를 Session Store에 저장하고, 브라우저는 해당 Session을 찾기 위한 Session ID를 전달하는 구조를 살펴봤다.
Token 기반 구조에서는 Client가 서버가 검증할 수 있는 Credential을 요청과 함께 전달한다.
Client → Token 전달 → Server가 Token 검증 → Resource 접근 여부 결정
하지만 Token이라고 해서 모두 같은 형태나 같은 역할을 가지는 것은 아니다.
- 실제 API 요청에 사용하는 Access Token이 있고,
- 새로운 Access Token을 발급받는 데 사용하는 Refresh Token이 있다.
- 또 Token 자체도 서버 측 상태를 조회해야 의미를 알 수 있는 Opaque Token일 수도 있고,
- 검증에 필요한 정보를 Token 안에 포함하는 Self-contained Token일 수도 있다.
그리고 API에서 자주 사용하는 Bearer는 Token의 내부 형식이 아니라 Token을 제시하고 사용하는 방식을 의미한다.
이번 글에서는 이 개념들을 역할과 검증 방식에 따라 구분해서 살펴본다.
목차
- Token은 Client가 Server에 제시하는 Credential이다
- Token 발급과 API 요청
- Session과 Token의 차이 - Bearer Token은 Token을 가진 주체가 사용할 수 있다
- Bearer의 의미
- Bearer Token을 보호해야 하는 이유
- Bearer와 JWT의 차이 - Access Token과 Refresh Token은 역할이 다르다
- Access Token
- Refresh Token
- Refresh Token Rotation - Opaque Token과 Self-contained Token은 검증 방식이 다르다
- Opaque Token
- Self-contained Token - Token은 만료와 폐기를 함께 고려해야 한다
- Expiration
- Token Revocation
- 검증과 즉시 통제의 Trade-off
1. Token은 Client가 Server에 제시하는 Credential이다
사용자가 로그인을 요청한다고 하자.
POST /login HTTP/1.1
Content-Type: application/json
{
"email": "user@example.com",
"password": "..."
}
서버는 전달받은 Credential을 이용해 사용자를 인증한다.
인증에 성공하면 이후 요청에서 사용할 Token을 발급할 수 있다.
Login Request → 사용자 인증 → Token 발급
Client는 발급받은 Token을 보관하고, 보호된 API를 호출할 때 해당 Token을 함께 전달한다.
대표적인 전달 방식이 HTTP Authorization Header다.
GET /profile HTTP/1.1
Authorization: Bearer <access-token>
서버는 요청에 포함된 Token이 유효한지 검증하고, Token이 나타내는 권한에 따라 Resource 접근 여부를 판단한다.

Session과 Token의 차이
Session 방식에서는 Client가 Session ID를 전달하고, 서버는 Session Store에서 해당 Session을 찾아 사용자 상태를 확인한다.
Session ID → Session Store 조회 → 사용자 상태 확인
Token 방식에서는 Client가 Credential인 Token을 전달하고, 서버는 정해진 방식으로 Token을 검증한다.
Token → Token 검증 → 사용자와 권한 확인
하지만 이 차이만 보고 다음처럼 단순하게 구분하면 정확하지 않다.
Session = Stateful
Token = Stateless
Token도 서버의 저장소를 조회해서 검증하는 구조가 존재하기 때문이다.
따라서 Token의 핵심은 Client가 Server에 제시하는 Credential이라는 점이고, 서버가 그 Token을 어떤 방식으로 검증하는지는 별개의 문제다.
2. Bearer Token은 Token을 가진 주체가 사용할 수 있다
API 요청에서는 다음과 같은 Header를 자주 볼 수 있다.
Authorization: Bearer <access-token>
Bearer의 의미
Bearer는 Token의 내부 구조를 나타내는 형식이 아니라 Token을 제시하고 사용하는 방식을 의미한다.
Bearer 방식에서는 유효한 Token을 가지고 있다는 사실 자체가 해당 Token의 권한을 사용하기 위한 증명이 된다.
유효한 Bearer Token 보유 → Server에 제시 → Token 검증 → 허용된 Resource 접근
즉 Token과 별개로 소유자를 추가 증명하지 않는다면, 유효한 Token을 획득한 다른 주체도 같은 Token을 사용할 수 있다.
Bearer Token을 보호해야 하는 이유
Bearer Token이 탈취되면 공격자는 Token이 유효한 동안 해당 Token의 권한으로 API를 호출할 수 있다.

따라서 Bearer Token은 비밀번호처럼 민감하게 다뤄야 한다.
Token 전체 값을 Application Log나 Access Log에 남기는 것은 피하는 것이 좋다.
Authorization: Bearer eyJ...
URL Query Parameter에 Token을 직접 넣는 것도 피해야 한다.
/profile?access_token=...
URL은 Browser History, Proxy Log, Server Access Log, 분석 도구 등에 남을 가능성이 있기 때문이다.
일반적인 API에서는 Authorization Header를 사용하고 HTTPS를 통해 Token을 전송한다.
Bearer와 JWT의 차이
Bearer와 JWT는 서로 다른 관점의 개념이다.
- Bearer → Token을 제시하고 사용하는 방식
- JWT → Token을 표현할 수 있는 형식
따라서 Bearer Token이 반드시 JWT일 필요는 없다.
다음처럼 의미를 직접 해석할 수 없는 임의 문자열도 Bearer Token으로 사용할 수 있다.
f83a91d0e7b2481a...
반대로 JWT 형식의 Token을 Bearer 방식으로 전달할 수도 있다.
xxxxx.yyyyy.zzzzz
JWT의 구조와 검증 방식은 다음 글인 JWT 파트에서 자세히 알아보자.
3. Access Token과 Refresh Token은 역할이 다르다
Token 기반 인증에서는 Access Token과 Refresh Token을 함께 사용하는 경우가 많다.
두 Token은 같은 Token 계열이지만 사용 목적이 다르다.
Access Token
Access Token은 보호된 Resource에 접근할 때 사용하는 Credential이다.
예를 들어 사용자 프로필 API를 호출할 때 다음처럼 전달할 수 있다.
GET /profile HTTP/1.1
Authorization: Bearer <access-token>
Resource Server는 Access Token을 검증한 뒤 Token에 부여된 권한에 따라 Resource를 반환할지 결정한다.
Access Token에는 일반적으로 유효 기간이 존재한다.
예를 들어 수명이 15분이라면 오후 1시에 발급된 Token은 오후 1시 15분 이후에는 사용할 수 없게 할 수 있다.
13:00 발급 → 15분 동안 사용 → 13:15 만료
Access Token의 수명을 제한하면 Token이 탈취되었을 때 사용할 수 있는 시간도 제한할 수 있다.
하지만 Access Token이 만료될 때마다 사용자가 ID와 Password를 다시 입력해야 한다면 사용자 경험이 좋지 않다.
이를 보완하기 위해 Refresh Token을 사용할 수 있다.
Refresh Token
Refresh Token은 일반적인 Resource API에 직접 접근하기 위한 Token이 아니다.
새로운 Access Token을 발급받는 데 사용한다.
Access Token 만료 → Refresh Token 제시 → Authorization Server 검증 → 새로운 Access Token 발급

| 구분 | Access Token | Refresh Token |
| 주요 목적 | 보호된 Resource 접근 | 새로운 Access Token 발급 |
| 주요 전달 대상 | Resource Server | Authorization Server의 Token Endpoint |
| 일반적인 수명 | 비교적 짧음 | Access Token보다 길게 설정하는 경우가 많음 |
| 탈취 시 위험 | 유효한 동안 Resource 접근 가능 | 새로운 Access Token 발급에 악용 가능 |
Refresh Token은 일반적으로 Access Token보다 오래 유지되기 때문에 유출되면 더 오랫동안 새로운 Access Token을 발급받는 데 악용될 수 있다.
따라서 Refresh Token은 Access Token보다 더 엄격한 저장과 폐기 정책을 적용하는 경우가 많다.
Refresh Token Rotation
Refresh Token을 계속 같은 값으로 사용하는 대신 Token 갱신 요청이 성공할 때마다 새로운 Refresh Token으로 교체하는 방식도 있다.
이를 Refresh Token Rotation이라고 한다.
Refresh Token A 사용 → Access Token B + Refresh Token B 발급 → Refresh Token A 폐기
다음 갱신에서는 Refresh Token B를 사용한다.
이전 Refresh Token을 더 이상 사용할 수 없게 만들면 탈취된 Refresh Token의 재사용을 제한하거나, 구현 방식에 따라 재사용 시도를 탐지하는 데 활용할 수 있다.
4. Opaque Token과 Self-contained Token은 검증 방식이 다르다
Token이라고 하면 JWT를 먼저 떠올리기 쉽지만 Token이 반드시 JWT 형식일 필요는 없다.
다음과 같은 임의의 문자열도 Token으로 사용할 수 있다.
f83a91d0e7b2481a...
이 값을 보는 것만으로는 어떤 사용자에게 발급되었는지, 어떤 권한을 가지는지 알 수 없다.
Opaque Token
Token 문자열 자체에서는 의미를 알 수 없고 서버 측 상태와 연결해야 의미를 확인할 수 있는 Token을 Opaque Token이라고 한다.
Token Store에는 다음과 같은 정보가 연결되어 있을 수 있다.
| Token | user_id | scope | expires_at | active |
| f83a91d0e7b2481a... | 42 | profile:read | ... | true |
Resource Server가 Opaque Token을 받으면 Token Store를 직접 조회하거나 Authorization Server의 Introspection Endpoint를 이용해 Token의 상태와 권한을 확인할 수 있다.
Opaque Token → Token Store / Introspection → Token 정보 확인

이 구조는 Session ID와 비슷해 보일 수 있다.
둘 다 전달받은 문자열만으로 모든 의미를 알 수 없고 서버 측 정보와 연결해야 하기 때문이다.
하지만 역할은 다르다.
- Session ID는 주로 서버가 관리하는 Session을 찾는 식별자이고,
- Access Token은 Resource 접근 권한을 나타내는 Credential이다.
Self-contained Token
반대로 Token 내부에 서버가 검증하는 데 필요한 정보를 포함할 수도 있다.
예를 들어 Token 내부에 Subject, Scope, Expiration 같은 정보와 Token의 무결성을 확인하기 위한 정보가 포함될 수 있다.
Resource Server는 중앙 Token Store를 매 요청마다 조회하지 않고 Token 자체를 검증하는 구조를 만들 수 있다.
Self-contained Token → 서명·만료·Claim 검증 → 사용자와 권한 확인
대표적으로 JWT가 Self-contained Token 형태에 사용될 수 있다.
| 구분 | Opaque Token | Self-contained Token |
| Token 자체의 정보 | 문자열만으로 의미 확인이 어려움 | 검증에 필요한 정보를 Token 내부에 포함 가능 |
| 검증 방식 | Token Store 또는 Introspection 조회 | Token 자체의 서명, 만료, Claim 등을 검증 |
| 중앙 상태 조회 | 필요한 구조가 일반적 | 매 요청마다 필요하지 않은 구조를 만들 수 있음 |
| 즉시 상태 변경 반영 | 서버 측 상태 변경으로 처리하기 쉬움 | 별도의 Revocation 구조가 필요할 수 있음 |
Opaque Token은 서버 측 상태를 직접 변경하기 때문에 특정 Token을 즉시 비활성화하는 구조를 만들기 쉽다.
반면 Self-contained Token은 중앙 저장소 조회 없이 검증할 수 있는 구조를 만들 수 있지만, 이미 발급된 Token을 만료 전에 즉시 무효화하려면 별도의 상태 조회나 Revocation 정책이 필요할 수 있다.
따라서 Token = Stateless라고 단순하게 보는 것은 정확하지 않다.
정확히는 Token의 형태와 검증 구조에 따라 서버 측 상태가 필요할 수도 있고 필요하지 않을 수도 있다.
5. Token은 만료와 폐기를 함께 고려해야 한다
Token도 Session과 마찬가지로 유효 기간과 폐기 방법을 함께 설계해야 한다.
Expiration
가장 기본적인 방법은 Token에 유효 기간을 두는 것이다.
Token 발급 → 일정 시간 동안 사용 → Expiration → 더 이상 사용 불가
특히 Access Token의 수명을 짧게 두면 Token이 탈취되었을 때 사용할 수 있는 시간을 줄일 수 있다.
하지만 만료 시간만으로 모든 요구사항을 해결할 수 있는 것은 아니다.
예를 들어 Access Token이 오후 1시에 발급되어 오후 2시에 만료된다고 하자.
오후 1시 10분에 사용자의 권한을 회수하더라도 Self-contained Token을 별도의 상태 조회 없이 검증한다면 기존 Token은 오후 2시까지 형식상 유효할 수 있다.
즉 Token의 Expiration과 서버의 현재 권한 상태가 항상 동시에 변경되는 것은 아니다.
이 때문에 실제 시스템에서는 요구사항에 따라 여러 방법을 조합할 수 있다.
- Access Token의 수명을 짧게 설정
- Refresh Token 폐기
- Token Revocation
- Denylist / Blocklist 사용
- Opaque Token의 서버 측 상태 변경
- 필요한 요청에서 최신 권한 상태 추가 확인
Token Revocation
Token Revocation은 특정 Token을 더 이상 사용할 수 없도록 폐기하는 것이다.
예를 들어 Refresh Token을 서버의 저장소에서 관리한다고 하자.
refresh_abc → active=true
사용자가 로그아웃하거나 Token을 폐기해야 한다면 상태를 변경하거나 저장소에서 제거할 수 있다.
refresh_abc → active=false
이후 Client가 같은 Refresh Token을 사용해 새로운 Access Token 발급을 요청하면 서버가 거부할 수 있다.
Access Token을 즉시 폐기할 수 있는지는 Token의 형태와 검증 구조에 따라 달라진다.
- Opaque Access Token처럼 서버 측 상태를 조회하는 구조라면 상태를 변경해 이후 요청을 즉시 거부하기 쉽다.
- Self-contained Access Token을 중앙 상태 조회 없이 검증한다면 짧은 만료 시간을 사용하거나, 별도의 Revocation 상태를 확인하는 구조를 추가할 수 있다.
검증과 즉시 통제의 Trade-off
Token 설계에서는 다음 두 요구사항이 충돌할 수 있다.
- 중앙 상태 조회 없이 각 Resource Server가 독립적으로 검증
- 서버에서 이미 발급된 Token의 상태를 즉시 변경
매 요청마다 중앙 상태를 확인하면 최신 상태를 즉시 반영하기 쉽지만, 중앙 저장소에 대한 의존성이 커질 수 있다.
반대로 Token 자체만으로 검증하면 중앙 상태 조회를 줄일 수 있지만, 이미 발급된 Token을 즉시 통제하는 구조가 더 복잡해질 수 있다.
따라서 Token 설계는 단순히 JWT를 사용할지를 결정하는 문제가 아니라 Token의 역할, 수명, 저장 위치, 검증 방법, 폐기 방법을 함께 결정하는 문제다.

정리
Token은 Client가 Server에 제시하는 Credential이다.
다만 Token과 관련된 용어들은 서로 다른 기준으로 나뉜다.
| 구분 기준 | 용어 | 의미 |
| 사용 방식 | Bearer Token | Token을 가진 주체가 해당 Token을 제시해 사용 |
| 역할 | Access Token | 보호된 Resource 접근에 사용 |
| 역할 | Refresh Token | 새로운 Access Token 발급에 사용 |
| 검증 구조 | Opaque Token | 서버 측 상태 조회를 통해 Token 정보를 확인하는 형태 |
| 검증 구조 | Self-contained Token | 검증에 필요한 정보를 Token 자체에 포함할 수 있는 형태 |
| 표현 형식 | JWT | Claim과 서명 등을 구조화해서 표현할 수 있는 Token 형식 |
따라서 다음 용어들은 같은 의미가 아니다.
Bearer / Access / Refresh / Opaque / Self-contained / JWT
각각 Token을 바라보는 기준이 다르다.
- Bearer: Token을 어떻게 사용하는가
- Access / Refresh: Token을 어디에 사용하는가
- Opaque / Self-contained: Token을 어떻게 해석하고 검증하는가
- JWT: Token을 어떤 형식으로 표현하는가
이 구분을 이해하면 JWT를 단순히 "로그인 Token"으로 보는 대신, 어떤 역할을 하는 Token을 어떤 형식으로 만들고 어떤 방식으로 검증할 것인가라는 관점에서 이해할 수 있다.
다음 글에서는 JWT의 Header, Payload, Signature 구조와 Claim, 서명 검증, 그리고 여러 서비스가 Public Key를 가져와 Token을 검증할 수 있게 하는 JWKS를 알아보자.
'보안' 카테고리의 다른 글
| JWT와 JWKS — Token을 서명하고 검증하는 방법 (0) | 2026.09.27 |
|---|---|
| 공개키와 개인키 — 암호화와 디지털 서명의 원리 (0) | 2026.09.27 |
| Session의 동작 원리 — Session ID와 서버 측 상태 관리 (1) | 2026.09.26 |
| Cookie의 동작 원리 — Scope와 보안 속성 (0) | 2026.09.25 |
| 웹 인증의 기본 — Cookie / Session / Token (0) | 2026.09.25 |