fix: session not being marked as logged out when logging out via REST /v1/logout
Proposed changes
When a user logs out via POST /v1/logout, the login token is removed from the user document but the session in the Sessions collection is never marked as logged out. The cleanup relies on an indirect chain (watch.users → in-memory callbacks → Accounts.onLogout → SAUMonitor → Sessions.logoutBySessionIdAndUserId) that breaks when the client closes its WebSocket upon receiving the logout response, the callbacks are destroyed before the broadcast arrives.
This adds a direct Sessions.logoutBySessionIdAndUserId() call in the logout handler, awaited before the response, so the session is always marked with logoutAt regardless of the WebSocket race.
Issue(s)
https://rocketchat.atlassian.net/browse/NATIVE-978
Steps to test or reproduce
- Log in on an Android/iOS client
- Verify the device appears in Device Manager
- Log out from the client
- Log back in
- Check Device Manager, should show only one active session not two
Further comments
The root cause is a race condition: POST /v1/logout broadcasts watch.users as fire-and-forget (void), but the mobile client closes its WebSocket on receiving the 200 response, removing the in-memory observer callbacks before the broadcast arrives. The SAUMonitor never receives the logout event, so logoutAt is never set on the session document. The direct Sessions.logoutBySessionIdAndUserId() call eliminates the dependency on this chain entirely.
Summary by CodeRabbit
- Bug Fixes
- Improved logout handling so
POST /v1/logoutexplicitly marks the user’s session as logged out, preventing stale/orphaned sessions from persisting in Device Manager. - Reduced inconsistent session state by avoiding indirect, timing-sensitive cleanup during logout.
- Improved logout handling so
- Tests
- Added end-to-end coverage for
POST /api/v1/logoutto confirm session invalidation,logoutAt/logoutByupdates on the session record, and correct401responses for unauthenticated requests.
- Added end-to-end coverage for