Treat a refreshable codex credential as authenticated
get_provider_handler() gates every provider on the synchronous
validate_credentials(), which for codex OAuth2 asks is_authenticated() ->
get_valid_token(). That returns None as soon as the cached access token is
within five minutes of expiry, and deliberately does not refresh. The request
paths do refresh - get_valid_token_with_refresh() at codex.py:311 and :1188,
writing the new tokens back - but they are never reached, because handler
construction has already raised "credentials not valid or not configured".
So an access token going stale takes the provider out of every rotation, and
nothing puts it back: a provider that cannot be built cannot refresh the token
that would let it be built. Only a human re-login clears it. On aisbf.cloud
all six codex providers were in that state - the main one since its token
expired on 2026-09-10 - with working refresh tokens sitting in the credential
files beside them, so rotation/lisa quietly served every request from its
kilo fallback instead of codex.
is_authenticated() now answers the question validate_credentials() is really
asking - can these credentials still produce a token - by accepting a stale
access token when a refresh token is present. If that refresh later fails the
request fails and the rotation fails over, which is the behaviour it already
has for any other provider error.
kilo is left alone: its get_valid_token_with_refresh() only reloads the file
and cannot refresh, so for kilo an expired token really is terminal. Qwen has
the same shape as codex, but its OAuth2 path is documented as discontinued.
Co-Authored-By:
Claude Opus 5 <noreply@anthropic.com>
Showing
Please
register
or
sign in
to comment