Đăng xuất (revoke refresh token)
Status
shipped
Priority
P1
Owner
team-identity
Platforms
fe · be · mobile
AC progress
7 / 7
Last reviewed
2026-05-22
Mục tiêu
Cho phép user đăng xuất khỏi phiên hiện tại bằng cách vô hiệu hoá refresh token đang dùng. Sau khi đăng xuất, refresh token không còn rotate được — user phải đăng nhập lại để có cặp token mới.
Phạm vi
Trong phạm vi (In scope):
- Endpoint
POST /auth/logoutnhận refresh token và revoke nó - Idempotent: gọi nhiều lần cho cùng token không gây lỗi
- Trả
204 No Contentkhi xử lý xong (kể cả token đã revoke trước đó) - Áp dụng cho mọi nguồn refresh token (đăng nhập phone+password hoặc Google OAuth)
Ngoài phạm vi (Out of scope):
- Logout tất cả thiết bị (revoke tất cả refresh token của user) — cần endpoint riêng nếu cần
- Vô hiệu access token đã phát hành (JWT stateless, không revoke được — chỉ chờ hết hạn 15 phút)
- Xoá HttpOnly cookie ở browser (FE phải tự gọi clear cookie hoặc set cookie expired)
- Lưu lịch sử logout cho audit
User Stories
- Là user, tôi muốn bấm “Đăng xuất” để kết thúc phiên hiện tại an toàn, đảm bảo người khác dùng thiết bị này sau không vào được tài khoản tôi.
- Là FE/Mobile dev, tôi muốn gọi logout nhiều lần (race condition, retry) không bị lỗi — đảm bảo cleanup luôn thành công.
Luồng chức năng
Vòng đời của một refresh token (state diagram):
stateDiagram-v2
[*] --> ACTIVE: Đăng nhập / Đăng ký thành công
ACTIVE --> ACTIVE: Refresh (rotate sang token mới)
ACTIVE --> REVOKED: User logout
ACTIVE --> EXPIRED: Quá 7 ngày không dùng
REVOKED --> REVOKED: Logout lại (idempotent)
EXPIRED --> [*]: Tự dọn
REVOKED --> [*]: Tự dọnLuồng request đăng xuất:
sequenceDiagram
actor User
participant App as FE/Mobile
participant BE
User->>App: Bấm "Đăng xuất"
App->>BE: POST /auth/logout {refreshToken}
BE->>BE: Tìm refresh token trong DB
alt Token tồn tại và đang ACTIVE
BE->>BE: Đánh dấu REVOKED
BE-->>App: 204 No Content
else Token đã REVOKED hoặc không tồn tại
BE-->>App: 204 No Content (idempotent — không lỗi)
end
App->>App: Xoá local storage / cookie
App->>User: Chuyển về màn hình đăng nhậpAcceptance Criteria
- AC-1: Endpoint
POST /auth/logoutnhận body{refreshToken: string}. - AC-2: Refresh token trong body không được rỗng (validate
@NotBlank) — rỗng → 400. - AC-3: Token hợp lệ và đang ACTIVE → đánh dấu REVOKED, trả
204 No Content. - AC-4: Token đã REVOKED trước đó (gọi logout lần 2+) → vẫn trả
204 No Content, KHÔNG lỗi (idempotent). - AC-5: Token không tồn tại trong DB (forged, expired đã xoá) → vẫn trả
204 No Content(không tiết lộ token nào có/không). - AC-6: Endpoint là public (không cần auth header) — chỉ cần biết refresh token là logout được.
- AC-7: Logout chỉ ảnh hưởng refresh token cụ thể trong request — không revoke các refresh token khác của cùng user (multi-device support).
Quy tắc nghiệp vụ
- Idempotent là bắt buộc: client có thể retry logout (vd lỗi mạng, FE call nhiều lần do race) — server không được phép trả lỗi cho lần 2+.
- Access token (JWT) không bị invalidate qua endpoint này — nó stateless, chỉ chờ hết 15 phút. Trong thời gian đó nếu attacker có access token vẫn dùng được. Đây là trade-off thiết kế JWT-based.
- Multi-device: user có thể có nhiều refresh token đang active (mỗi thiết bị 1). Logout chỉ vô hiệu token của thiết bị gửi request, các thiết bị khác vẫn đăng nhập.
- Sau logout, để vào lại app user PHẢI đăng nhập (phone+password hoặc Google) — không có cơ chế “đăng nhập tự động” ở repo này.
- Không tiết lộ thông tin về user qua endpoint logout (vd “token này thuộc user nào”) — chỉ 204 generic.
Dữ liệu & Trạng thái
Entity nghiệp vụ:
RefreshToken: token hash, userId, expiresAt, status (ACTIVE / REVOKED / EXPIRED), parentTokenId (cho rotation chain).
Trạng thái refresh token:
ACTIVE— đang dùng được, có thể rotate (xem feature liên quan refresh — chưa map).REVOKED— user đã logout, không rotate được nữa.EXPIRED— quá TTL (7 ngày), tự coi như invalid, dọn dần khỏi DB.
Phân loại response:
204 No Content— luôn luôn (thành công hoặc idempotent no-op)400— body sai format / refresh token rỗng
Câu hỏi mở
- ❓ Có cần endpoint riêng “logout-all-devices” để revoke tất cả refresh token của user (vd khi nghi ngờ bị lộ tài khoản, đổi password)?
- ❓ Có nên log audit event mỗi lần logout (analytics, security investigation)?
- ❓ Sau logout, có cần TTL ngắn (vài giây) cho access token còn dùng để FE wrap-up state, hay accept rằng access vẫn còn 15 phút?
- ❓ Nếu FE quên xoá HttpOnly cookie sau logout, behavior khi user F5 (cookie vẫn gửi)? Có nên BE clear cookie?
Liên quan
- Phụ thuộc: Chưa có
- Ảnh hưởng: Chưa có