Skip to content

fix(backend): revoke refresh tokens on logout and admin deactivation - #564

Merged
algirdasc merged 2 commits into
mainfrom
fix/logout-refresh-token-revocation
Aug 10, 2026
Merged

fix(backend): revoke refresh tokens on logout and admin deactivation#564
algirdasc merged 2 commits into
mainfrom
fix/logout-refresh-token-revocation

Conversation

@algirdasc

Copy link
Copy Markdown
Owner

Problem

Security audit finding: DELETE /api/auth/logout was a no-op — refresh tokens stayed valid for their full gesdinet default lifetime (30 days), so a stolen refresh token survived logout. Same gap in admin deactivation: it cleared the password reset token but left live refresh tokens, and no user_checker blocks deactivated accounts.

Fix

  • New RefreshTokenRepository::revokeAllForUser() (DQL delete by username = user identifier/email).
  • LogoutController now requires the authenticated user and revokes all their refresh tokens (revokes every session — per-device revoke can come later if clients start sending the token).
  • AdminUserService::deactivate() revokes the user's refresh tokens too.
  • Explicit ttl: 2592000 in gesdinet_jwt_refresh_token.yaml.

No frontend change needed: Nebular already calls DELETE /auth/logout and only clears the local token on a successful response, which this keeps (200).

Tests

  • New LogoutControllerTest: seeds refresh tokens for two users, rotates one via POST /api/auth/refresh-token, logs out, then asserts the rotated token is rejected with 401, the user's rows are gone, and the other user's token is untouched.
  • Added logout to AuthenticationRequiredTest (no JWT → 401).
  • Full suite: 131 tests / 554 assertions OK; PHPStan clean.

Logout was a no-op: refresh tokens stayed valid for their full lifetime
(30-day gesdinet default), so a stolen token survived 'logout'. Likewise,
admin deactivation cleared the password reset token but left refresh
tokens usable.

- DELETE /api/auth/logout now deletes the user's refresh token rows
- AdminUserService::deactivate revokes the user's refresh tokens too
- Make gesdinet refresh token ttl explicit (2592000 = 30 days)

Test: e2e flow proves a rotated refresh token is rejected with 401 after
logout while another user's token is untouched; logout without a JWT
returns 401.
@algirdasc
algirdasc merged commit 3ac6476 into main Aug 10, 2026
4 checks passed
@algirdasc
algirdasc deleted the fix/logout-refresh-token-revocation branch August 10, 2026 19:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant