Repository navigation
fix: log in again when the auth server rejects an expired refresh token - #165
Merged
Merged
Conversation
The ApptiveGrid auth server answers an expired refresh token with a
plain-text 401 ("the token is not valid: 'token expired'"), which
openid_client throws as an HttpRequestException rather than an
OpenIdException. Since 2.3.1 only OpenIdException counted as a rejected
credential, so the dead credential was kept and every login attempt
refreshed it again and failed the same way.
Client errors from the token endpoint (except 408 and 429) now count as
a rejection too, both when restoring the saved credential and when
refreshing an expired token in memory: the token and credential are
cleared and, with autoAuthenticate, the login page opens.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Problem
A user who had been signed in for months got
HttpRequestException(401): the token is not valid: 'token expired' [401 Unauthorized]on every screen, and logging in again failed with the same error.The ApptiveGrid auth server answers an expired refresh token with a plain-text 401, not an OAuth error JSON.
openid_clienttherefore throws anHttpRequestException(401)instead of anOpenIdException. Since 2.3.1 (#162) onlyOpenIdExceptioncounted as a rejected credential; everything else is treated like a lost connection: the credential stays stored and the error propagates. So every request, and every login attempt (which goes throughcheckAuthenticationfirst), refreshed the same dead credential again and failed. Because the credential lives in the keychain, not even a reinstall helps on iOS.The in-memory branch (token present but about to expire) had the same gap: a rejected refresh kept the expired token, so all requests kept failing with 401.
Fix
ApptiveGridAuthenticator.isCredentialRejected(error):OpenIdException, or anHttpRequestExceptionwith a 4xx status except 408 (timeout) and 429 (rate limit). Connection errors and 5xx stay "not a rejection", so the offline behaviour from fix: keep the credential when a token refresh fails for want of a connection #162 is unchanged.authenticate()as before; anything else rethrows.autoAuthenticateandrequestNewToken, opens the login; anything else rethrows and keeps the token.Tests
In
test/authenticator_test.dart:requestNewToken: falseit only clears the token; a connection error keeps the token and throwsisCredentialRejectedforOpenIdException, 400/401/403, 408/429/5xx and other errorsThe three behaviour tests fail without the fix. All 685 tests pass,
dart analyze --fatal-infosis clean,dart formatunchanged, and the authenticator has no uncovered line.🤖 Generated with Claude Code