Files
keycloak-pattern/docs/evidence/b3-refresh-contention/README.md
T
DongHyeonkaandClaude Opus 5 b16e1dccf7 docs: B-3 — concurrent refresh does not lose a race, it destroys the session
Five simultaneous refreshes with one token return a single 200, and that winner's new token is already dead. Reuse detection removes the client session while the user session stays, which is why the other responses read Session doesn't have required client rather than a reuse error.

Comparing policies shows rotation off passes all five and keeps the session, while raising refreshTokenMaxReuse to one still destroys it. Since no retry can recover a removed client session, Q2's own criterion resolves to a lock, and a database row lock is the natural place because its lifetime is tied to the connection.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 14:20:04 +09:00

1.4 KiB
Raw Blame History

B-3 — Refresh Token 동시 갱신 경쟁 증거

2026-09-04 15:1515:25 KST 해설: docs/experiment-b3-refresh-token-contention.md

파일 무엇을 보여주는가
01-concurrent-refresh.txt 같은 토큰으로 동시 5회 — 1개만 200, 나머지는 Maximum allowed refresh token reuse exceededSession doesn't have required client 두 종류 오류
02-session-impact.txt ★ 이긴 요청의 새 토큰조차 400. user_session 행은 남아 있고 revoked_token 은 0건
03-client-session-removed.txt 기제 확정 (대조군 포함) — 경쟁 세션 client_sessions=0, 정상 세션 client_sessions=1
04-policy-comparison.txt 정책 3종 비교 — rotation OFF 는 5/5 성공·세션 생존, maxReuse=1 은 여전히 세션 파괴

핵심 네 줄

  1. "하나는 성공"이 아니다. 이긴 요청이 받은 토큰도 곧바로 쓸 수 없다.
  2. 재사용 탐지가 client session 을 제거한다. user session 은 껍데기로 남아 Session doesn't have required client 가 된다.
  3. refreshTokenMaxReuse 를 올려도 안 된다. 동시 요청 수만큼 올려야 하고 그러면 rotation 의 목적이 사라진다.
  4. 재시도로 회복되지 않으므로 Q2 의 답은 lock 이다. 그리고 lock 은 저장소 쪽(가급적 DB 행 잠금)에 있어야 한다.