fix: keep the web session when a resume fails without refusing the token
Merged
GG
13h ago+142+142+012345678901234567890123456789-0-0-0123456789
Proposed changes
Users are logged out of the web client when the server restarts or is redeployed.
Meteor's accounts client logs out after any error from the resume login it sends in three cases: on page load, after every reconnect, and when the stored token changes in another tab. During a restart the server can answer with errors that say nothing about the token:
- internal errors (a Mongo disruption, a login validation hook throwing);
too-many-requests;error-login-blocked-for-ip.
Any of these was enough to discard a valid session.
The session now only ends when the server refuses the token:
client/lib/isLoginTokenRefused.tsdecides what counts as a refusal. That is an unknown token ("You've been logged out by the server"), an expired token ("Your session has expired", including the form the service broker rebuilds), or an account that may not log in (error-user-is-not-activated,error-user-has-no-roles,error-app-user-is-not-allowed-to-login).client/meteor/overrides/keepSessionOnTransientResumeErrors.tskeeps the stored token after any other resume failure and retries the resume with a backoff (1s, doubling up to 60s). It covers the page-load resume too, which accounts-base starts before the app's overrides load. A logout the user asks for (Meteor.logout/Accounts.logout) always goes through.
Issue(s)
https://rocketchat.atlassian.net/browse/ARCH-2581
Steps to test or reproduce
- Log in to a monolith instance and keep the tab open.
- Make the resume login fail with a non-auth error, then reconnect. For example, restart the server while MongoDB is briefly unavailable, or enable
Block_Multiple_Failed_Logins_By_Ipwith a low threshold. - Before: the tab lands on the login page and
Meteor.loginTokenis gone from localStorage. After: the token stays, the console shows[accounts] kept the session after a login failure that does not refuse the token, and the session comes back once the server answers. - Revoke the token instead (e.g. log out the session from another device, or wait for it to expire). The tab is logged out as before.
client/lib/isLoginTokenRefused.spec.ts covers the refused and the transient errors.
Further comments
Found during the same investigation and left for separate PRs:
- The REST client clears credentials on any 401 from a mutating endpoint (e.g.
rooms.hideanswers 401 for a room the user can't access). force_logoutignores the session id, so logging out another device logs out this tab.- In microservices, the DDP streamer can answer a login with an empty successful result while the account service isn't registered.
Summary by CodeRabbit
- Bug Fixes
- Users remain signed in when session-resume attempts encounter temporary errors.
- Session resumption now retries automatically with increasing delays.
- Users are logged out only when the server rejects the session token.
- Successful reconnection restores normal session handling, while explicit logout continues to work as expected.