📋 개요
이 문서는 Spring Boot 기반 WAS의 인증 도메인에 대한 기술 기획서입니다.
JWT 토큰과 PKCE(Proof Key for Code Exchange) 방식을 활용한 보안성 높은 인증 시스템을 제공합니다.
🎯 주요 기능
1. OAuth2 인증 지원
- Google OAuth2
- Kakao OAuth2
- PKCE 방식으로 보안성 강화
2. JWT 토큰 기반 인증
- Access Token: 짧은 만료 시간 (API 요청 인증)
- Refresh Token: 긴 만료 시간 (토큰 갱신)
- 쿠키 기반 토큰 저장
3. 보안 기능
- CSRF 공격 방지 (State 매개변수)
- 토큰 자동 갱신
- 안전한 로그아웃
🏗️ 시스템 아키텍처
계층 구조
1
2
3
4
5
6
7
8
9
| ┌─────────────────────┐
│ Presentation │ ← API Controller, Request/Response DTO
├─────────────────────┤
│ Application │ ← Service, Repository Interface
├─────────────────────┤
│ Domain │ ← Business Logic, Domain Model
├─────────────────────┤
│ Infrastructure │ ← External Client, JPA Entity, Redis
└─────────────────────┘
|
주요 컴포넌트
계층 | 컴포넌트 | 역할 |
---|
Presentation | AuthenticationController | REST API 엔드포인트 제공 |
Application | AuthenticationService | 인증 비즈니스 로직 처리 |
Application | OAuth2UrlService | OAuth2 URL 생성 |
Domain | JwtProvider/JwtResolver | JWT 토큰 생성/검증 |
Domain | OAuth2TokenService | OAuth2 토큰 획득 |
Infrastructure | GoogleTokenClient | Google OAuth2 API 호출 |
Infrastructure | KakaoTokenClient | Kakao OAuth2 API 호출 |
🔄 인증 플로우
1. OAuth2 로그인 프로세스
sequenceDiagram
participant Client
participant API
participant OAuth2Provider
participant Redis
participant DB
Client->>API: 1. OAuth2 URL 요청 (code_verifier, redirect_path)
API->>Redis: 2. OAuth2Context 저장 (state, code_verifier, redirect_path)
API->>Client: 3. OAuth2 URL 반환 (state 포함)
Client->>OAuth2Provider: 4. 사용자 인증 및 권한 동의
OAuth2Provider->>Client: 5. Authorization Code 반환 (code, state)
Client->>API: 6. 로그인 요청 (code, state)
API->>Redis: 7. OAuth2Context 조회 및 검증
API->>OAuth2Provider: 8. Access Token 요청 (code, code_verifier)
OAuth2Provider->>API: 9. Access Token 반환
API->>OAuth2Provider: 10. 사용자 프로필 요청
OAuth2Provider->>API: 11. 사용자 프로필 반환
API->>DB: 12. 회원 정보 조회/생성
API->>API: 13. JWT 토큰 생성 (Access + Refresh)
API->>Redis: 14. Refresh Token 저장
API->>Client: 15. 로그인 성공 (쿠키로 토큰 전달)
2. 토큰 갱신 프로세스
sequenceDiagram
participant Client
participant API
participant Redis
participant DB
Client->>API: 1. 토큰 갱신 요청 (Refresh Token)
API->>API: 2. Refresh Token 검증
API->>Redis: 3. 저장된 Refresh Token 조회
API->>API: 4. 토큰 일치 검증
API->>DB: 5. 회원 정보 조회
API->>API: 6. 새로운 Access Token 생성
API->>Redis: 7. Refresh Token 사용 횟수 증가
API->>Client: 8. 새로운 Access Token 반환
📊 데이터 모델
JWT Claims 구조
Access Token Claims
1
2
3
4
5
6
7
| {
"id": "회원 ID (Long)",
"nickname": "회원 닉네임",
"profileImage": "프로필 이미지 URL",
"email": "이메일 주소",
"authorities": ["ROLE_NORMAL"]
}
|
Refresh Token Claims
1
2
3
| {
"id": "회원 ID (Long)"
}
|
Redis 저장 데이터
OAuth2Context (임시 저장)
1
2
3
4
5
6
7
8
| {
"state": "CSRF 방지용 랜덤 문자열",
"provider": "GOOGLE | KAKAO",
"codeVerifier": "PKCE code verifier",
"redirectPath": "클라이언트 리다이렉트 경로",
"expiresAt": "만료 시간 (5분)",
"ttl": "Redis TTL (초)"
}
|
RefreshToken
1
2
3
4
5
6
7
| {
"memberId": "회원 ID",
"token": "Refresh Token 문자열",
"useCount": "사용 횟수",
"expiresAt": "만료 시간",
"ttl": "Redis TTL (초)"
}
|
🔐 보안 정책
1. PKCE (Proof Key for Code Exchange)
- Code Verifier: 클라이언트가 생성하는 43-128자의 랜덤 문자열
- Code Challenge: Code Verifier의 SHA256 해시값 (Base64 URL 인코딩)
- Authorization Code Interception Attack 방지
2. State 매개변수
- CSRF 공격 방지
- 32바이트 랜덤 값을 Base64 URL 인코딩
- 5분 만료 시간 설정
3. JWT 토큰 정책
- Access Token: 짧은 만료 시간 (일반적으로 15분-1시간)
- Refresh Token: 긴 만료 시간 (일반적으로 7-30일)
- HttpOnly, Secure, SameSite=None 쿠키 설정
4. 토큰 저장 정책
- Access Token: 메모리 내 저장 (쿠키)
- Refresh Token: Redis에 저장 (회원 ID 기준)
- 로그아웃 시 모든 토큰 무효화
🌐 API 명세
1. OAuth2 URL 생성
1
2
3
4
5
6
7
8
| POST /auth/oauth2/url
Content-Type: application/json
{
"provider": "GOOGLE",
"codeVerifier": "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk",
"redirectPath": "/home"
}
|
응답:
1
2
3
4
5
6
| {
"url": "https://accounts.google.com/oauth/authorize?client_id=...",
"state": "BjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk",
"provider": "GOOGLE",
"expiresAt": "2024-01-15T10:05:00"
}
|
2. OAuth2 로그인
1
2
3
4
5
6
7
8
| POST /auth/oauth2/login
Content-Type: application/json
{
"provider": "GOOGLE",
"code": "4/0AX4XfWjJKZ...",
"state": "BjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"
}
|
응답:
1
2
3
4
5
6
7
8
9
| {
"memberInfo": {
"id": 1,
"nickname": "홍길동#1234",
"profileImage": "member/profile/image/01234567.jpg",
"email": "user@example.com"
},
"redirectPath": "/home"
}
|
3. 로그아웃
1
2
| POST /auth/logout
Cookie: access-token={access_token}
|
4. 토큰 갱신
1
2
| POST /auth/token/refresh
Cookie: refresh-token={refresh_token}
|
⚙️ 설정 및 환경변수
OAuth2 설정
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| app:
oauth2:
google:
client-id: ${GOOGLE_CLIENT_ID}
client-secret: ${GOOGLE_CLIENT_SECRET}
authorization-url: https://accounts.google.com/o/oauth2/v2/auth
token-url: https://oauth2.googleapis.com/token
user-info-url: https://www.googleapis.com/oauth2/v2/userinfo
redirect-uri: http://localhost:3000/auth/callback/google
scope: email
kakao:
client-id: ${KAKAO_CLIENT_ID}
client-secret: ${KAKAO_CLIENT_SECRET}
authorization-url: https://kauth.kakao.com/oauth/authorize
token-url: https://kauth.kakao.com/oauth/token
user-info-url: https://kapi.kakao.com/v2/user/me
redirect-uri: http://localhost:3000/auth/callback/kakao
scope: account_email
|
JWT 설정
1
2
3
4
5
6
7
8
9
10
| app:
jwt:
access-token:
token-key: access-token
secret-key: ${JWT_ACCESS_SECRET}
expires-in: 1800 # 30분
refresh-token:
token-key: refresh-token
secret-key: ${JWT_REFRESH_SECRET}
expires-in: 2592000 # 30일
|
🚨 예외 처리
OAuth2 관련 예외
예외 코드 | 설명 | HTTP 상태 |
---|
OAUTH-001 | 지원하지 않는 OAuth2 제공자 | 400 |
OAUTH-002 | Code Challenge 생성 실패 | 500 |
OAUTH-003 | OAuth2 Context를 찾을 수 없음 | 404 |
OAUTH-004 | OAuth2 제공자에서 토큰 획득 실패 | 500 |
OAUTH-005 | OAuth2 제공자에서 사용자 프로필 획득 실패 | 500 |
인증/인가 관련 예외
예외 코드 | 설명 | HTTP 상태 |
---|
ACT-001 | Access Token을 찾을 수 없음 | 401 |
ACT-002 | 유효하지 않은 Access Token | 401 |
ACT-003 | 만료된 Access Token | 401 |
RFT-001 | Refresh Token을 찾을 수 없음 | 404 |
RFT-002 | 유효하지 않은 Refresh Token | 400 |
RFT-003 | 만료된 Refresh Token | 400 |
RFT-004 | Refresh Token 불일치 | 400 |
🔧 기술 스택
Backend Framework
- Spring Boot 3.2.2
- Spring Security 6
- Spring Data JPA
- Spring Data Redis
외부 연동
- OpenFeign: OAuth2 Provider API 호출
- JWT:
jjwt
라이브러리 사용
데이터 저장소
- Redis: 세션 및 임시 데이터 저장
- MySQL: 회원 정보 저장
📈 확장 계획
1. 추가 OAuth2 제공자 지원
- GitHub OAuth2
- Naver OAuth2
- Facebook OAuth2
2. 보안 강화
- JWT 토큰 블랙리스트 관리
- 비정상적인 로그인 시도 감지
- 디바이스 기반 인증
3. 모니터링
- 로그인 성공/실패 통계
- 토큰 사용 패턴 분석
- 보안 이벤트 로깅
📚 참고 자료