JWT (JSON Web Token)
✅ JWT란?
JWT는 로그인한 사용자 정보를 토큰 형태로 안전하게 주고받기 위해 사용하는 인증 수단
JWT는 서버가 세션 없이도 사용자의 인증 상태를 유지할 수 있게 도와준다.
✅ JWT 구조
JWT는 다음과 같이 3가지 부분으로 나뉜다.
xxxxx.yyyyy.zzzzz
부분 | 이름 | 설명 |
---|---|---|
xxxxx |
Header | 알고리즘 및 타입 정보 (ex. HS256, JWT) |
yyyyy |
Payload | 사용자 정보: userId, 이름, 권한 등 |
zzzzz |
Signature | 서명. 위 내용이 변조되지 않았는지 검증 |
1. Header
{
"alg": "HS256",
"typ": "JWT"
}
- 어떤 알고리즘을 서명했는지
- 타입음 JWT 을 명시
2. Payload
{
"sub": "1234567890",
"name": "shin0park",
"email": "test@test.com",
"role": "USER",
"iat": 1712715300,
"exp": 1712718900
}
- Payload는 Base64로 인코딩된 것이며, 누구나 디코딩은 가능하다.
→ 그래서 비밀번호, 주민번호 등의 민감 정보는 절대 넣지 말아야 한다.
3. Signature (서명)
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret
)
- 토큰의 무결성을 검증하는 역할을 한다.
- 클라이언트가 토큰을 조작해도, 해당 부분이 다르면 검증 실패로 처리된다.
JWT (JSON Web Token) VS Session
✅ Stateless vs Stateful의 핵심 차이
1. JWT = Stateless
"서버는 아무것도 기억하지 않는다"
클라이언트(브라우저 또는 앱)가 인증 상태(토큰)를 들고 있다.
서버는 매 요청마다 토큰만 검증하고, 별도의 세션 저장 없이 처리함
2. Stateless인 이유:
서버는 클라이언트가 누군지 기억하지 않는다.
클라이언트가 매 요청마다 자기 정보를 토큰에 담아 보내야 한다.
서버 입장에서 상태(State)를 유지하지 않는다
=> "JWT는 Stateless인데, 리프레시 토큰은 DB나 Redis에 저장하던데요?"
Access Token 기반 인증 구조는 본질적으로 Stateless이다. 그러나 보안을 강화하기 위해 Refresh Token에 한해서 부분적으로 상태를 저장하는 구조를 사용하는 것이다.
✅ JWT (Stateless의 장점)
1. 서버 확장성 (Scalability)
JWT는 클라이언트가 토큰을 가지고 있기 때문에, 서버는 사용자 상태를 기억할 필요가 없다.
서버를 여러 대 늘리더라도 세션 공유(Sticky Session, Redis 등)를 하지 않아도 되니까 수평 확장에 매우 유리하다.
예: AWS Auto Scaling 환경에서 서버가 늘어나도 문제가 없다.
2. 요청 시 빠른 인증
JWT는 디코딩만으로 사용자 정보와 권한을 확인할 수 있어서 DB 조회 없이 인증 가능하다.
예를 들어, 토큰 안에 role=ADMIN이 들어있으면 바로 관리자 권한을 알 수 있다.
3. 모바일, SPA 앱에 적합
JWT는 API 서버에 적합한 인증 방식이다.
쿠키 대신 로컬스토리지에 저장해서 API 요청마다 헤더에 토큰만 실어 보내면 끝이다.
CORS 걱정도 적고, RESTful한 구조와 잘 어울린다.
4. 보편적인 표준 (인터페이스 일관성)
JWT는 RFC 7519로 정해진 표준이라, 다양한 언어/플랫폼에서 쉽게 구현 가능해.
Authorization: Bearer {token} 형태로 사용하는 게 전 세계적으로 통일돼 있어서 협업, 유지보수에 강함.
✅ Session (Stateful 방식의 한계)
1. 서버에 상태 유지 필요
사용자의 로그인 상태를 서버가 기억하고 있어야 해. 즉, 서버가 세션 ID ↔ 사용자 정보를 저장해야 한다.
서버 수가 늘어날수록 이 세션을 공유해야 하는 문제가 발생한다.
Redis 같은 외부 저장소를 도입해야 하고, Sticky Session 설정이 필요할 수 있다. (부담 + 복잡도 증가)
2. 매 요청마다 DB 조회
세션 ID만으로는 사용자 정보를 알 수 없으니, 보통 서버는 세션 DB나 메모리에서 한 번은 조회해야 해.
즉, DB I/O가 발생하고 성능에도 영향을 줘.
3. 모바일/SPA와 궁합이 나쁨
세션 기반은 주로 쿠키에 의존한다.
쿠키를 쓰기 위해선 CORS, CSRF 설정 등 여러 보안 세팅이 필요하고, 모바일에서는 관리 복잡도가 커진다.
4. 무한 세션 증가 문제
많은 사용자가 로그인을 하면, 서버 메모리나 Redis에 세션 데이터가 계속 쌓이게 된다.
가비지 컬렉션이나 만료 처리 설정을 해주지 않으면 메모리 누수의 위험이 있다.
JWT (JSON Web Token) 설명
✅ JWT 인증 흐름
[1] 클라이언트(브라우저)
|
| 로그인 성공 후 JWT 발급
v
[2] JWT 저장 (localStorage / cookie 등)
|
| 요청할 때마다 JWT 포함 (Authorization 헤더)
v
[3] 서버(Spring 등) 도착
|
| → JWT 필터나 인터셉터에서 토큰 꺼냄
|
v
[4] JWT 유효성 검증
├─ 유효한 토큰
│ └─ 사용자 정보 추출 (userId, role 등)
│ └─ SecurityContextHolder 에 저장
│ └─ 컨트롤러로 진입 (인증된 사용자로)
│
└─ 유효하지 않음 (없거나 만료됨 등)
└─ 인증 실패 → 401 Unauthorized 에러 응답
✅ 로그인된 사용자라는 건 어떻게 알까?
→ Payload에 담긴 유저 정보 (ex. userId, role)를 꺼내서, 해당 사용자가 유효한 사용자인지 확인하는 식으로 인증이 된다.
✅ Signature가 중요한 이유
Payload는 쉽게 디코딩할 수 있지만, Signature는 서버가 가진 비밀 키(secret key)로 서명되었기 때문에:
누군가 Payload를 위조해도, Signature를 위조할 수는 없다. 서버는 이 Signature로 정상적인 토큰인지 검증하는 것이다.
✅ Payload 탈취되면 위험하지 않나요?
→ 그러하다. JWT가 탈취되면 로그인된 사용자 권한을 도용당할 수 있다. 그래서 반드시 HTTPS 사용 + 저장 위치(localStorage/cookie) 신중히 선택해야 한다.
✅ 정리
항목 | 요약 |
---|---|
JWT 목적 | 로그인 상태 유지 (stateless 인증) |
중요한 요소 | Signature (위조 방지), Payload (인증 정보 포함) |
민감 정보? | 절대 넣지 말기! |
저장 위치 | localStorage 또는 cookie (주의 필요) |
인증 흐름 | 클라이언트 → 서버, 매 요청마다 JWT 전달 및 검증 |
JWT (JSON Web Token) 코드 흐름
1. 로그인 요청 처리
클라이언트가 로그인할 때, 이메일과 비밀번호를 서버로 보낸다.
서버는 해당 정보가 DB 또는 메모리에 저장된 유저와 일치하는지 확인한다.
2. JWT 토큰 생성
로그인 정보가 유효하면, 서버는 해당 사용자 정보를 기반으로 JWT 토큰을 생성한다.
이 토큰 안에는 보통 사용자 이메일, 이름, 권한(ROLE) 등 식별 가능한 정보를 담는다.
토큰은 서명(서버의 비밀키로 HMAC 암호화) 되어, 위조 방지가 가능하다.
토큰은 access token으로 주고, 필요하면 refresh token도 같이 발급한다.
3. 클라이언트에게 토큰 응답
생성한 JWT 토큰을 응답으로 클라이언트에게 전달한다.
클라이언트는 이 토큰을 로컬스토리지(localStorage) 또는 쿠키에 저장한다.
4. 보호된 API 요청 시 토큰 전송
클라이언트가 인증이 필요한 API에 접근할 때는, HTTP 헤더의 Authorization: Bearer {토큰} 형태로 서버에 토큰을 같이 전송한다.
5. 요청 시 토큰 검증
요청을 받은 서버는 다음을 수행한다.
- Authorization 헤더에서 토큰을 추출하고
- 서명을 검증하여 위조되지 않았는지 확인하고
- 만료되지 않았는지 exp 값을 체크함
- 내부 정보(sub, email, role)를 꺼내 사용자 인증 상태로 인식
6. 사용자 정보를 API 처리 로직에 활용
검증된 사용자 정보는 컨트롤러, 서비스 등에서 활용된다.
예: "이 사용자가 맞는지?", "이 유저의 역할은 USER인가 ADMIN인가?" 등을 체크할 수 있다.
7. 인증이 완료되면 요청 처리
모든 검증이 성공하면, 요청을 정상적으로 처리한다.
인증에 실패하면 401 Unauthorized 같은 상태 코드를 리턴한다.
'백엔드 부트캠프 > TIL' 카테고리의 다른 글
[내일배움캠프Spring-40일차] 객체지향 (0) | 2025.04.14 |
---|---|
[내일배움캠프Spring-39일차] @Builder 어노테이션 (0) | 2025.04.11 |
[내일배움캠프Spring-37일차] 클린아키텍처 (1) | 2025.04.09 |
[내일배움캠프Spring-36일차] Race Condition (경쟁 조건) 정리 (0) | 2025.04.08 |
[내일배움캠프Spring-35일차] JWT(JSON Web Token) 기반 인증 방식 정리 (3) | 2025.04.07 |