Skip to content

Per-Request Auth Token Refresh#103

Merged
anna-singleton-resolver merged 13 commits intomainfrom
feature/dynamic-refresh
Feb 23, 2026
Merged

Per-Request Auth Token Refresh#103
anna-singleton-resolver merged 13 commits intomainfrom
feature/dynamic-refresh

Conversation

@carlpatchett
Copy link
Collaborator

@carlpatchett carlpatchett commented Feb 16, 2026

Token is now not eagerly pulled and baked into requests, its dynamically aquired per rpc

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements dynamic token refresh for OAuth authentication by deferring token acquisition from channel creation time to per-RPC invocation. The implementation changes from async to sync I/O to accommodate gRPC's threading model and switches the authorization header format from "Token" to the standard "Bearer" prefix.

Changes:

  • Token acquisition now occurs dynamically per RPC instead of eagerly at channel creation time
  • Converted CredentialHelper from async/await to synchronous with threading.Lock for gRPC callback compatibility
  • Changed authorization header format from "Token {token}" to standard "Bearer {token}"

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/resolver_athena_client/client/channel.py Removed TokenMetadataPlugin, added _AutoRefreshTokenAuthMetadataPlugin for dynamic token refresh; converted CredentialHelper from async to sync; changed authorization scheme to Bearer
tests/client/test_channel.py Updated tests to verify non-eager token fetching; converted async tests to sync; added tests for new _AutoRefreshTokenAuthMetadataPlugin class
tests/functional/conftest.py Removed eager token acquisition test from credential_helper fixture
examples/example.py Removed eager token acquisition and validation before channel creation
examples/classify_single_example.py Removed eager token acquisition and validation before channel creation
docs/authentication.rst Updated code examples to reflect that get_token() is now synchronous
docs/api/exceptions.rst Updated code examples to reflect that get_token() is now synchronous

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@iwillspeak iwillspeak changed the title Dynamic Refresh Dynamic Auth Token Refresh Feb 17, 2026
@iwillspeak iwillspeak changed the title Dynamic Auth Token Refresh Per-Request Auth Token Refresh Feb 17, 2026
iwillspeak
iwillspeak previously approved these changes Feb 17, 2026
Copy link
Contributor

@iwillspeak iwillspeak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

snus-kin
snus-kin previously approved these changes Feb 17, 2026
JohnnyWombwell
JohnnyWombwell previously approved these changes Feb 18, 2026
iwillspeak
iwillspeak previously approved these changes Feb 18, 2026
iwillspeak
iwillspeak previously approved these changes Feb 19, 2026
Copy link
Contributor

Copilot AI commented Feb 20, 2026

@iwillspeak I've opened a new pull request, #107, to work on those changes. Once the pull request is ready, I'll request review from you.

@iwillspeak
Copy link
Contributor

@copilot looks like the changes in #106 have broken some of the tests. Update the tests to match the expected behaviour with schemes (we always respect the capitalisation from the server)

Copy link
Contributor

Copilot AI commented Feb 20, 2026

@iwillspeak I've opened a new pull request, #108, to work on those changes. Once the pull request is ready, I'll request review from you.

…stampede (#107)

* Initial plan

* Implement background token refresh for old tokens

- Add issued_at field to TokenData to track token creation time
- Add is_old() method to check if token should be refreshed (< 50% lifetime)
- Trigger non-blocking background refresh when token is old but valid
- Keep blocking refresh for expired tokens
- Add comprehensive tests for background refresh behavior

Co-authored-by: iwillspeak <1004401+iwillspeak@users.noreply.github.com>

* fix: update tests to match preserved token scheme casing

Tests were expecting capitalized schemes but implementation was
changed in 4b7e73a to preserve server-provided casing.

Co-authored-by: iwillspeak <1004401+iwillspeak@users.noreply.github.com>

* Address code review feedback

- Add logging for background refresh failures
- Improve comments explaining magic numbers
- Add test for server casing preservation
- Add comment explaining test tolerance

Co-authored-by: iwillspeak <1004401+iwillspeak@users.noreply.github.com>

* Address PR review comments

- Make issued_at a required field (remove default value)
- Remove fallback logic for legacy tokens in is_old()
- Add stampede prevention in _background_refresh
- Remove obsolete tests for fallback logic
- Add test for stampede prevention

Co-authored-by: iwillspeak <1004401+iwillspeak@users.noreply.github.com>

* Revert Bearer/DPoP test assertion changes from c50327d

The target branch now properly fixes the test by providing "Bearer"
in the mock data. Reverting my previous fix that changed the assertion
to match the old mock data.

Co-authored-by: anna-singleton-resolver <199753965+anna-singleton-resolver@users.noreply.github.com>

* fix: start refresh thread checks for already refreshed token

* chore: remove extraneous comment

* feat: reduce eagerness of background refresh from at 50% remaining to 25% remaining

* doc: update is_old docstring

* fix: correct boolean logic in _start_background_refresh

Changed from OR to AND logic: refresh should start if
(refresh_not_active AND token_needs_refresh), not if any
condition is true. This prevents unnecessary refresh attempts.

Co-authored-by: iwillspeak <1004401+iwillspeak@users.noreply.github.com>

* test: fix test assertions to be on 25% instead of 50%

* feat: allow configurable proactive_refresh_threshold

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: iwillspeak <1004401+iwillspeak@users.noreply.github.com>
Co-authored-by: anna-singleton-resolver <199753965+anna-singleton-resolver@users.noreply.github.com>
Co-authored-by: anna-singleton-resolver <anna.singleton@resolver.com>
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

iwillspeak
iwillspeak previously approved these changes Feb 23, 2026
@anna-singleton-resolver anna-singleton-resolver enabled auto-merge (squash) February 23, 2026 11:51
@anna-singleton-resolver anna-singleton-resolver merged commit 3d9e87f into main Feb 23, 2026
17 checks passed
@anna-singleton-resolver anna-singleton-resolver deleted the feature/dynamic-refresh branch February 23, 2026 11:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants