리프레시토큰 조회 및 재발급되는 로직에 대해 설명

리프레시 토큰 로직은 크게

(1) 토큰 조회/검증과 (2) 재발급(회전, rotation)으로 동작

1) 조회(검증) 로직

  • 요청 엔드포인트: POST /auth/refresh (api/routes/api.php)

  • 컨트롤러 AuthController::refresh()가 먼저 쿠키에서 토큰을 꺼냅니다.

  • $_COOKIE[CookieHelper::getRefreshCookieName()] (기본 이름 refreshToken)

  • 서비스 AuthService::refresh()에서:

  1. 토큰 누락이면 AUTH_REFRESH_MISSING (401)

  2. RefreshTokenStore::validateAndGetUser() 호출

  • 토큰 원문을 SHA-256 해시

  • refresh_tokens.token_hash로 DB 조회 + users 조인

  • 상태 판정

  • 레코드 없음/만료: 유효하지 않음

  • revoked_at 있음: 재사용(reuse) 탐지

  • 정상: 사용자 정보 반환 + last_used_at 갱신


2) 재발급(회전) 로직

  • AuthService::refresh()에서 검증 통과 후 RefreshTokenStore::rotate() 실행

  • rotate() 핵심 순서:

  1. 트랜잭션 시작

  2. 기존 refresh 토큰 row를 FOR UPDATE로 잠금 조회

  3. 기존 토큰이 revoked/expired면 실패

  4. 새 refresh 토큰 생성 후 DB insert

  5. 기존 토큰 revoked_at = NOW()로 폐기

  6. 커밋

  • 이후 새 Access Token(JWT) 발급

  • 쿠키 갱신:

  • 새 refresh 쿠키 설정

  • 새 access 쿠키 설정

  • 응답 바디에 access_token, expires_in 반환


3) 재사용 공격 방어

  • 이미 폐기된 refresh 토큰이 다시 들어오면 reused=true

  • AuthService::refresh()에서:

  • 기본 정책(REUSE_REVOKE_SCOPE)에 따라

  • device: 같은 user_id + device_id 활성 토큰 revoke

  • user: 해당 사용자 전체 revoke

  • 인증 쿠키 삭제 후 401 AUTH_REUSE


4) 조회를 세션 목록 조회로 본다면

  • GET /auth/sessions (AuthController::sessions())

  • refresh_tokens에서 revoked_at IS NULL AND expires_at  NOW()만 조회

  • 현재 쿠키 refresh 토큰 해시와 각 row의 token_hash를 비교해 is_current 표시


23

댓글