한 줄 목표
사업장 사용자가 안전하게 로그인하고, 자신의 사업장 데이터만 역할에 맞게 사용하도록 JWT 인증·권한·Refresh Token 수명주기를 구현합니다.
현재 진행 상태
초보자 설명: Access Token은 API를 잠깐 사용하는 출입증이고, Refresh Token은 출입증을 다시 발급받는 수단입니다. 서버는 Refresh Token을 매번 새 값으로 교체하며, 이미 쓴 값이 다시 오면 해당 로그인 묶음을 모두 폐기합니다.
공식 API
/api/v1을 생략한 /auth/** 별칭은 만들지 않습니다.
| API |
인증 |
하는 일 |
주요 응답 |
POST /api/v1/auth/login |
Public, JSON email/password |
로그인하고 Access Token과 HttpOnly Refresh 쿠키 발급 |
200, 실패 401 INVALID_CREDENTIALS |
POST /api/v1/auth/refresh |
Refresh 쿠키만 |
기존 쿠키를 한 번 사용하고 Access/Refresh Token 회전 |
200, 실패 401 INVALID_REFRESH_TOKEN |
POST /api/v1/auth/logout |
선택적 Refresh 쿠키 |
현재 로그인 family 폐기와 쿠키 삭제 |
항상 204; DB 장애는 성공으로 숨기지 않음 |
GET /api/v1/auth/me |
Bearer Access Token |
현재 user_id, company_id, roles 확인 |
200, 실패 401 |
구현 체크리스트
감사 이벤트 경계
#35는 로그인 성공·실패, 재발급, 재사용 탐지, token family 폐기, 로그아웃 action을 원본 토큰·email·비밀번호 없이 안전한 ID로 정의합니다. 현재 adapter는 request_id가 포함된 진단 로그입니다. append-only 영구 감사 테이블과 검색 API는 소유 Issue #11에서 이 port에 연결합니다.
검증 체크리스트
보안 규칙
- Refresh Token은 JSON·일반 로그·감사 이벤트에 넣지 않고 HttpOnly 쿠키로만 전달합니다.
- 쿠키는 운영에서 Secure이며, CSRF/Origin 보호 전에는
SameSite=None을 금지하고 Strict/Lax만 허용합니다.
- 같은 쿠키의 동시 Refresh는 보수적으로 재사용으로 판단할 수 있으므로 Client는 single-flight로 한 번만 호출합니다.
- 로그아웃 뒤 이미 발급된 stateless Access Token은 기본 TTL 기준 최대 15분 유효할 수 있어 Client가 즉시 삭제합니다.
- Seed는 기본 비활성이며
DEMO_SEED_ADMIN_PASSWORD를 실행 환경 Secret으로 줄 때만 동작합니다.
- JWT Secret, 초기 비밀번호, 실제 토큰을 GitHub·Notion·로그에 올리지 않습니다.
이번 Issue에서 하지 않는 것
선행·후속 관계
용어 도움말
- JWT Access Token: API 요청자가 누구인지 짧은 시간 동안 증명하는 문자열
- Refresh Token rotation: 재발급할 때 기존 Refresh Token을 폐기하고 새 값으로 교체하는 방식
- Token family: 한 번의 로그인에서 이어진 Refresh Token 교체 묶음
- Single-flight: 동시에 여러 재발급을 보내지 않고 한 요청의 결과를 함께 기다리는 Client 방식
- 멀티테넌시: 여러 사업장이 한 서버를 쓰되 서로의 데이터를 볼 수 없게 분리하는 구조
한 줄 목표
사업장 사용자가 안전하게 로그인하고, 자신의 사업장 데이터만 역할에 맞게 사용하도록 JWT 인증·권한·Refresh Token 수명주기를 구현합니다.
현재 진행 상태
main에 병합될 때 이 Issue가 자동으로 닫힙니다.공식 API
/api/v1을 생략한/auth/**별칭은 만들지 않습니다.POST /api/v1/auth/login200, 실패401 INVALID_CREDENTIALSPOST /api/v1/auth/refresh200, 실패401 INVALID_REFRESH_TOKENPOST /api/v1/auth/logout204; DB 장애는 성공으로 숨기지 않음GET /api/v1/auth/me200, 실패401구현 체크리스트
감사 이벤트 경계
#35는 로그인 성공·실패, 재발급, 재사용 탐지, token family 폐기, 로그아웃 action을 원본 토큰·email·비밀번호 없이 안전한 ID로 정의합니다. 현재 adapter는
request_id가 포함된 진단 로그입니다. append-only 영구 감사 테이블과 검색 API는 소유 Issue #11에서 이 port에 연결합니다.검증 체크리스트
/auth/me./gradlew clean test와./gradlew buildmain병합보안 규칙
SameSite=None을 금지하고 Strict/Lax만 허용합니다.DEMO_SEED_ADMIN_PASSWORD를 실행 환경 Secret으로 줄 때만 동작합니다.이번 Issue에서 하지 않는 것
선행·후속 관계
용어 도움말