세션 인증 방식
- 로그인 요청 (ID/PassWord 전송)
- 사용자 확인 후 세션 생성 및 메모리/DB에 저장
- 생성된 Session ID(SESSIONID)를 쿠키(Set-Cookie)에 담아 응답
- 인증이 필요한 API 요청 시, 쿠키의 Session ID를 자동 포함하여 전송
- 전달받은 Session ID가 저장소에 있는지 조회 및 검증 후 데이터 응답
단점
서버 메모리를 사용하다보니 서버 확장(Scale-Out)이 어려움
프론트엔드와 API 서버 도메인이 다르면 쿠키 전송 자체에 별도 설정이 필요(CORS 정책 이슈)
토큰 인증 방식
- 로그인 요청(ID/Password 전송)
- Store에서 사용자 정보 조회 및 인증
- 사용자 확인 후, 비밀키를 사용하여 서명된 JWT 생성 (저장소에 토큰/세션 저장 안 함)
- 생성된 JWT를 응답(클라이언트가 로컬에 저장)
- API 요청 시 HTTP 헤더(Authorization:
Bearer <token>)에 JWT를 포함하여 전송 - 서버의 비밀키로 토큰의 서명(Signature)을 검증하고 유효성(만료일 등) 확인 후 데이터 응답
세션 vs 토큰 인증
| 세션 인증 | 토큰 인증 | |
|---|---|---|
| 상태 저장 | 서버(메모리/DB)에 세션을 보관 | 서버에 저장하지 않음 |
| 전달 | 쿠키(Set-Cookie)로 자동 전송 | Authorization 헤더(Bearer)에 직접 실어 전송 |
| 검증 | 매 요청마다 저장소를 조회해야 함 | 서명만 확인, 저장소 조회 없음 |
| 확장(Scale-out) | 세션 공유 설정이 필요해 까다로움 | 어느 서버로 가도 확장이 자유로움 |
JWT(JSON Web Token)
JWT는 사용자의 인증/인가 정보를 JSON 형태로 안전하게 전송하기 위한 웹 표준(RFC7519)
디지털 서명이 되어 있으므로 신뢰할 수 있음 (암호화 알고리즘 사용)
JSON 기반이므로 대부분의 언어, 플랫폼에서 독립적으로 사용 가능
JWT 자체가 필요한 모든 정보를 갖고 있기 때문에 검증하기 위해 다른 검증 수단이 필요하지 않음
권한을 부여하거나, 정보를 교환할 때 등의 상황에서 사용 가능
서버는 토큰을 저장하지 않음
JWT 구조
JWT는 .(dot)을 이용하여 3가지의 영역으로 구성된다.
- header(헤더) - 토큰의 메타정보
- payload(내용) - 실제 담고자 하는 정보 (Claim, 정보의 key-value쌍)
- signature(서명) - 위변조 탐지용 서명
Header
헤더는 일반적으로 두 부분으로 구성
- 토큰의 유형 -> “JWT” (보통 “JWT”로 고정)
- 암호화 알고리즘 (HMAC SHA256 or RSA 등)
해당 정보를 Base64URL 방식으로 인코딩하여 헤더 부분을 완성함
Payload
Claim(토큰의 정보)들의 집합
Registered claims(표준 클레임)
- JWT 스펙에서 미리 정해 놓은 클레임
- iss(Issuer)
- sub(Subject - 토큰의 주체, 사용자 ID 등)
- lat(발급시각), exp(만료시각) 등
Public claims(공용 클레임)
- 자유롭게 정의하여 넣는 클레임(충돌 방지 필요)
Private claims
- 발급자와 사용자 간에 약속한 값
해당 정보를 Base64URL 방식으로 인코딩하여 페이로드 부분을 완성함
Signature
헤더 + 페이로드를 비밀키로 서명(암호화)한 결과
해당 토큰이 조작되었거나 변경되지 않음을 확인하는 용도로 사용
JWT 동작 흐름(로그인)
- 로그인 요청
- 서버에서 ID/PW 검증
- 서버가 JWT 발급(Access Token)
- 클라이언트가 발급 받은 토큰 저장 (localStorage 등)
- Axios 요청 시 JWT를 헤더에 넣어 요청
- 서버에서 JWT 검증 -> 이상 없으면 요청 수행
JWT 장점 & 단점
장점
- 서버가 상태를 저장할 필요 없음(세션 관리 부담 감소)
- DB 호출을 하지 않고 서명이 유효한지 검증만 하기 때문에 속도가 빠르다
- SPA에서 주로 사용
- 다양한 서비스 간 공유가 쉽다
단점
- 토큰이 유효기간 내에는 무효화가 불가능하다(탈취되면 위험)
- 토큰이 길다
- XSS에 노출되어 JS 공격을 받을 수 있다
- JWT를 디코딩하면 내용이 보이기 때문에 민감한 개인정보를 작성하면 안된다.
따라서 Access Token + Refresh Token 방식을 많이 사용한다.
Access Token
로그인 성공하면 발급 받ㅇ서 클라이언트에 저장
누구인지, 권한은 어떻게 되는지, 언제까지 유효한지 등의 정보가 포함되어 있다.
탈취 시 피해를 줄이기 위해서 유효 기간을 짧게(보통 5분~1시간 내외) 설정한다.
LocalStorage(혹은 메모리에 임시 저장)에 주로 저장한다.
- 설계의 유연함(CORS)과 CSRF 공격을 방어하기 위해 자바스크립트 코드로 명시적 전송
- 쿠키로 설정하게 되면 자동 전송 성질에 따라서 URL(+Path)만 맞으면 전송해버리므로 위험
Refresh Token
Access Token이 만료되었을 때, 새 Access Token을 발급
유효 기간은 길게(보통 7일~30일)로 설정한다.
HttpOnly Cookie에 주로 저장한다.(JS 접근 불가능)
(갱신 시에만 사용하도록 Path를 한정 권장한다. Path=/api/auth/refresh)
서버(DB/Redis)에 저장해서 관리하는 경우가 많다.