-- 0015 · users.token_version — refresh 토큰 무효화 키 -- -- ★ 왜 필요한가 (보안 점검, 2026-09-15) -- auth_service.refresh_token() 은 지금까지 refresh 토큰을 서명만 검증하고 그 안의 sub -- (user_id·id·role)를 그대로 새 access 토큰에 옮겨 찍었다 — DB 를 한 번도 보지 않았다. -- 비밀번호를 바꾸거나(다른 기기의 세션을 끊고 싶을 때) 계정을 차단해도, 이미 발급된 -- refresh 토큰(7일)을 쥔 클라이언트는 만료 전까지 계속 새 access 토큰을 받을 수 있었다. -- token_version 을 JWT 의 sub 에 같이 싣고 refresh 할 때 DB 의 지금 값과 대조하면, -- bump_token_version() 을 부른 시점 이후의 refresh 시도는 전부 거절된다. -- -- ★ 옛 토큰(token_version 없이 발급된 것)도 읽힌다 — UserInfo 가 기본값 1 을 먼저 깔고 -- 그 위에 없는 키는 안 덮으므로(common/models/gmodel.py UserInfo.__init__), 새 컬럼의 -- DEFAULT 1 과 맞아떨어진다. 배포 순간 전원 강제 로그아웃이 되지 않는다. ALTER TABLE public.users ADD COLUMN IF NOT EXISTS token_version SMALLINT NOT NULL DEFAULT 1; COMMENT ON COLUMN public.users.token_version IS 'refresh 토큰 무효화 키. JWT(access·refresh)의 sub 에 실려 나간다 — 이 값을 올리면(bump_token_version) 그 전에 발급된 refresh 토큰은 다음 재발급에서 전부 거절된다.';