test(auth): pin the over-age token asymmetry the interceptor reacts to - #2991
Merged
bwp91 merged 1 commit intoAug 22, 2026
Merged
Conversation
refreshToken() is the only reader of sessionStartedAt, so a token past the cap is refused a renewal while every guarded route still accepts it. That is what let the browser turn a refused refresh into an account-wide logout the server then honoured (homebridge#2981). The fix is in the interceptor and refreshSession(), covered by the ui specs; this pins the server side they react to.
bwp91
approved these changes
Aug 22, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The reproduction from #2981, as a test.
refreshToken()is the only reader ofsessionStartedAt, so a token past the 30 day cap is refused a renewal while/auth/checkstill accepts it. That asymmetry is what let the interceptor turn a refused refresh into an account-wide logout the server then honoured. The fix for that is in the interceptor andrefreshSession(); this pins the server side they react to.The 31 days are a backdated
sessionStartedAtrather than elapsed time, so it tests the comparison and nothing about clocks.I also wrote a second test around the logout itself, over-age token revoking the account and
scope: 'local'sparing the other device, and dropped it./auth/logoutnever readssessionStartedAt, so nothing in it depended on the token being over-age; it passed just as happily with a fresh one, and its account-wide half duplicatedkeeps other sessions alive when the logout is scoped to this browser.Ran the original chain against a beta.3 instance as well, driving the real interceptor rather than a mock:
{"scope":"local"}on the wire, second device still 200. Reverting both halves of c903c0a in a scratch copy puts{}back and takes it to 401.62 passing in the auth e2e file, lint clean. Adding the cap to
validateUser()fails this test and nothing else in the suite; disabling it inrefreshToken()fails this plusrefuses to renew a session past its maximum ageandwarns when it refuses a refresh, and stays quiet when it allows one. Themaximum ageassertion is there because a 401 from an expired or malformed token would otherwise satisfy the same expectation.