JWT Access·Refresh Token 수명주기
발급, 저장, Rotation, Reuse Detection, Logout과 Key 교체까지 Token의 전체 수명을 설계한다.
이 문서의 목차
Overview
JWT 검증이 정확해도 Token이 탈취되면 만료 전까지 공격자가 Bearer 자격으로 사용할 수 있다. 그래서 발급·전달·저장·갱신·폐기·Key Rotation의 전체 수명주기를 함께 설계해야 한다.
한 문장 설명: 짧은 Access Token으로 노출 시간을 제한하고, 통제 가능한 Refresh Token Rotation으로 Login 수명을 연장한다.
왜 필요한가
Access Token을 길게 만들면 편하지만 즉시 Logout과 권한 회수가 어렵다. 매 요청마다 Session DB를 조회하면 통제는 쉬우나 분산 API의 의존성과 지연이 늘어난다. Access는 짧게, Refresh는 엄격히 저장·회전하는 구조가 흔한 절충안이다.
세션 기반 인증은 서버가 인증 상태를 계속 들고 있어 강제 Logout과 권한 변경 반영이 쉽다. JWT 기반 인증은 각 API가 Token만 보고 판단할 수 있어 수평 확장이 쉽다. 둘 중 하나가 항상 정답은 아니며, 사용자 위험도와 제품 UX에 따라 혼합한다.
핵심 원리
- Access Token: Resource API에 보내는 짧은 수명의 Token이다. 정확한 Audience와 최소 Scope를 가진다.
- Refresh Token: 새 Access Token을 받는 Credential이다. Resource API에 보내지 않으며 더 강하게 보호한다.
- Rotation: Refresh할 때 기존 Refresh Token을 폐기하고 새 Token으로 교체한다.
- Reuse Detection: 이미 사용된 옛 Refresh Token이 다시 오면 Token Family 탈취로 보고 연관 Session을 폐기한다.
- Revocation: Refresh Session 또는 고위험 Access Token의
jti를 Server-side 상태로 차단한다.
내부 동작
sequenceDiagram; participant U as Client; participant I as Identity; participant A as API; U->>I: Login/SSO; I-->>U: 짧은 Access + Refresh; U->>A: Access Token; A->>A: Signature/iss/aud/exp 검증; A-->>U: 응답; U->>I: Refresh Token; I->>I: Rotation + 기존 Token 폐기; I-->>U: 새 Access + 새 Refresh; alt 옛 Refresh 재사용; U->>I: 폐기된 Token; I->>I: Reuse Detection, Family Revocation; end
API는 JWKS에서 kid에 맞는 Public Key를 Cache해 Signature를 검증한다. Identity Provider는 새 Key를 먼저 JWKS에 공개하고 서명 Key를 전환한 뒤, 기존 Token 최대 수명이 지난 후 옛 Key를 제거한다.
Example
Browser 기반 Application의 한 선택은 Refresh Token을 HttpOnly; Secure; SameSite Cookie에 두고 Access Token을 짧게 Memory에 보관하는 것이다. Cookie 인증 Endpoint는 CSRF 방어가 필요하고, JavaScript가 읽지 못해도 XSS가 사용자의 Browser에서 요청을 수행할 수 있으므로 CSP와 출력 Encoding이 여전히 필요하다.
Service-to-Service Token은 사람용 Refresh Token을 공유하지 않는다. Workload Identity나 Client Credential을 쓰고 aud=inventory-api, 최소 Scope, 짧은 만료로 대상과 권한을 제한한다.
실무에서 발생하는 문제
Logout과 즉시 무효화
Client에서 Token을 지우는 Logout은 해당 사본만 제거한다. 탈취된 Access Token은 exp까지 유효할 수 있다. 보안 사건, 퇴사, 권한 회수처럼 즉시 차단이 필요하면 Session Version, jti Denylist, API Gateway introspection 같은 상태 기반 방식을 위험도에 맞게 사용한다.
XSS와 CSRF
LocalStorage Token은 XSS로 읽힐 수 있다. HttpOnly Cookie는 직접 읽기 어렵지만 Browser가 자동 전송하므로 CSRF를 고려한다. “어디에 저장하면 완벽히 안전하다”가 아니라 공격 경계, Application 구조, CSP, SameSite, CSRF Token을 함께 결정한다.
Refresh Token 탈취
Rotation만 하고 Reuse Detection을 하지 않으면 공격자와 사용자가 번갈아 갱신할 수 있다. Refresh Token은 원문 대신 Hash를 저장하고 Device/Session별 Family와 사용·폐기 시간을 기록한다. 무제한 Session과 영구 Refresh를 피한다.
Trade-off
짧은 Access 수명은 탈취 창을 줄이지만 Refresh Traffic과 일시적 인증 실패를 늘린다. Denylist는 즉시 폐기를 주지만 무상태 장점을 줄인다. Cookie는 Browser 보안 속성을 활용하지만 CSRF와 Domain 경계를 관리해야 하고 Header 방식은 명시적이지만 JavaScript 저장 위험이 있다.
Sticky Session은 Access Token 검증 문제의 해법이 아니라 서버 메모리 Session을 유지하기 위한 Load Balancing 전략이다. JWT를 쓰면 Sticky가 덜 필요해질 수 있지만, Refresh Token 저장소나 Revocation Store는 여전히 고가용성으로 운영해야 한다.
흔한 오해
- Refresh Token도 JWT일 필요는 없다. 추측 불가능한 Opaque Token이 폐기 관리에 단순할 수 있다.
- Logout이 이미 복사된 Access Token을 자동 파괴하지 않는다.
- Key Rotation은
kid만 바꾸는 작업이 아니라 JWKS Cache와 옛 Token 유효기간을 포함한다. - HTTPS는 Token 저장과 권한 과다 문제까지 해결하지 않는다.
Production Considerations
발급·Refresh 성공/실패, Reuse Detection, Revocation, Issuer/Audience 오류, Key 조회 실패를 관측한다. Token 본문은 Log에 남기지 않고 jti도 필요 범위에서 Hash/마스킹한다. Rotation Runbook에는 새 Key 게시, 서명 전환, Cache 갱신, 옛 Key 제거와 Rollback이 포함된다.
Interview Questions / Follow-up Questions
- Access Token과 Refresh Token을 분리하는 이유는?
- Rotation과 Reuse Detection은 각각 무엇을 막는가?
- Logout 후 Access Token이 남을 수 있는 이유는?
- 후속: LocalStorage와 HttpOnly Cookie의 공격 경계를 비교하라.
- 후속: JWKS Key Rotation을 무중단으로 수행하는 순서는?
Related Topics
SOURCE REFERENCES
이 문서의 근거
본문은 Dev Atlas 안에서 완결되며, 검증이 필요할 때만 원문을 확인할 수 있습니다.