Skip to content

[Auth & Security] JWT 인증·사업장 권한·멀티테넌시 구현 #4

Closed

Description

@hywznn

한 줄 목표

사업장 사용자가 안전하게 로그인하고, 자신의 사업장 데이터만 역할에 맞게 사용하도록 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

구현 체크리스트

  • Company, UserAccount, RefreshToken 모델과 V2 Flyway migration
  • 비밀번호 BCrypt 단방향 hash 저장
  • 로그인과 JWT Access Token 발급·검증
  • Refresh Token 원문 비저장, SHA-256 hash 저장
  • Refresh Token rotation과 이전 토큰 사용 처리
  • 재사용 탐지 시 token family 전체 폐기
  • 멱등 로그아웃과 HttpOnly 쿠키 삭제
  • JWT에서 user_id, company_id, roles를 ActorContext로 구성
  • ADMIN·HR·VIEWER 역할 검사
  • user_id + company_id 조회와 타 사업장 리소스 404 은닉
  • privacy-safe 인증 감사 이벤트와 AuthAuditPort 정의
  • 기본 비활성·Secret 필수인 데모 Company·ADMIN Seed 제공
  • OpenAPI·README·ADR-0002·환경변수 예시 갱신

감사 이벤트 경계

#35는 로그인 성공·실패, 재발급, 재사용 탐지, token family 폐기, 로그아웃 action을 원본 토큰·email·비밀번호 없이 안전한 ID로 정의합니다. 현재 adapter는 request_id가 포함된 진단 로그입니다. append-only 영구 감사 테이블과 검색 API는 소유 Issue #11에서 이 port에 연결합니다.

검증 체크리스트

  • 정상 로그인·JWT claims·/auth/me
  • 잘못된 email과 비밀번호가 동일한 외부 오류
  • VIEWER 쓰기 차단, HR 쓰기 허용
  • 다른 사업장 리소스 404 은닉
  • 정상 Refresh와 교체 chain·family 검증
  • 누락·변조·미존재·폐기·재사용 토큰의 동일한 401
  • 재사용 뒤 새 교체 토큰까지 폐기
  • 로그아웃 반복 호출과 서로 다른 로그인 family 격리
  • 계정·사업장 정지 시 Refresh 차단과 family 폐기
  • 데모 Seed 멱등성·BCrypt 저장·Secret 비노출
  • 로컬 ./gradlew clean test와 ./gradlew build
  • feat: Refresh Token 회전·로그아웃과 안전한 데모 인증 기반 구현 #35 GitHub Actions의 실제 PostgreSQL 동시성 테스트
  • 팀원 리뷰와 main 병합

보안 규칙

  • 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 방식
  • 멀티테넌시: 여러 사업장이 한 서버를 쓰되 서로의 데이터를 볼 수 없게 분리하는 구조

Activity

  1. added
    area:serverSpring Boot API·도메인·DB·tenant·Task Workflow 영역; Prompt·모델·Provider 구현 제외
    priority:P0MVP 진행을 막는 최우선 핵심 작업
    security:privacy개인정보·접근권한·토큰·보안 영향이 있는 작업
    status:backlog해야 하지만 아직 시작 조건이 갖춰지지 않은 작업
    type:feature사용자 또는 Agent가 사용하는 기능 개발
    on Jul 21, 2026
  2. changed the title [-][Security] JWT 인증·사업장 권한·멀티테넌시 구현[/-] [+][Auth & Security] JWT 인증·사업장 권한·멀티테넌시 구현[/+] on Jul 21, 2026
  3. added
    status:ready범위가 확정되어 바로 시작할 수 있는 작업
    and removed
    status:backlog해야 하지만 아직 시작 조건이 갖춰지지 않은 작업
    on Jul 21, 2026
  4. self-assigned this
    on Jul 22, 2026
  5. added
    status:in-progress담당자가 현재 구현 중인 작업
    status:in-review구현을 마치고 리뷰 또는 병합을 기다리는 작업
    and removed
    status:ready범위가 확정되어 바로 시작할 수 있는 작업
    status:in-progress담당자가 현재 구현 중인 작업
    on Jul 22, 2026
  6. removed
    status:in-review구현을 마치고 리뷰 또는 병합을 기다리는 작업
    on Jul 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:serverSpring Boot API·도메인·DB·tenant·Task Workflow 영역; Prompt·모델·Provider 구현 제외priority:P0MVP 진행을 막는 최우선 핵심 작업security:privacy개인정보·접근권한·토큰·보안 영향이 있는 작업type:feature사용자 또는 Agent가 사용하는 기능 개발

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions