Repository navigation
feat(client): 401 auto-refresh hook — drop the mid-session expiry-skew 401s - #90
Merged
Merged
Conversation
…ion wiring (#89) - CampusRequest.set_unauthorized_hook(hook): on a 401 response the hook runs once; a returned bearer token refreshes the Authorization header and the request is retried once. A retry that 401s again, or a hook returning None, surfaces the original 401 — strictly a safety net. Requests made from inside the hook skip the hook (no recursion). The retry is safe for non-idempotent requests: Campus services authenticate in before_request, before any handler runs. - with_user_session(refresh_on_401=True, default) wires the hook on the auth+api clients: mid-session 401s (bearer expired after the skew window) force-refresh the session token — round-trip authenticating as the client (Basic), like session establishment — and restore the new bearer on both clients; failures restore the pre-hook state. refresh_on_401=False keeps the old behaviour. - Verbs refactored through a shared _send(); request wire format unchanged (Session.request with the same kwargs). - 229 tests (was 218).
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.
Closes #89.
What
On a 401 response,
CampusRequestcan now invoke a one-shot refresh hook and retry the request once with a fresh bearer:CampusRequest.set_unauthorized_hook(fn)—fnreturns the new bearer token, orNoneto signal failure. Semantics:Nonereturn (or a hook raisingAPIError) leaves the original 401 response in place — failures surface exactly as before the hook existed.JsonClientABC documents it as an optional capability (feature-detect withhasattr), per the issue's design note.with_user_session(refresh_on_401=True)(default) installs the hook on both service clients: the closure force-refreshes via_get_token_from_session(force_refresh=True)— running the round-trip under client Basic auth (revoke_session()), the same known-good mode session establishment uses, since auth routes accept both but the session's stale bearer must not be presented mid-rotation — then restores the new bearer on both clients viause_token(). Hooks are cleared when the session closes. The proactive refresh stays; the hook only covers the expiry-skew race that used to surface as a mid-request 401 (the exact gap feat(client): optional 401 auto-refresh hook so user-session apps can drop proactive is_expired() checks #89 describes for campus-classroom).Why the retry is safe for POSTs
Campus services authenticate in a
before_requestauthenticator (campus/auth/routes/__init__.py), so a 401 is produced by the auth layer before any handler runs — there is no partial work to replay. This resolves the "POSTs are not idempotent" design question from the issue: retry-after-401 cannot double-execute a handler.Design questions from the issue, resolved
with_user_session; public clients: bring your own hook (campus.auth.refresh(stored, client_id=...)from feat(auth): refresh grant + device-flow parity for public clients #88 returns the rotated pair — README shows the snippet).CampusRequest;JsonClientdocstring documents it as optional.Tests
229 passing (was 218): retry-once semantics (hook called once, second 401 not re-tried,
Nonekeeps the original 401, hook cleared), reentrancy guard, wire-format preservation across verbs, and thewith_user_sessionwiring (force-refresh call args, both clients re-bearered, failure restores pre-hook state,refresh_on_401=Falseopt-out).