Skip to content

SMOODEV-948: Async auth-token provider across TS, Python, Rust, Go#72

Merged
brentrager merged 1 commit into
mainfrom
SMOODEV-948-async-auth-provider
May 12, 2026
Merged

SMOODEV-948: Async auth-token provider across TS, Python, Rust, Go#72
brentrager merged 1 commit into
mainfrom
SMOODEV-948-async-auth-provider

Conversation

@brentrager
Copy link
Copy Markdown
Contributor

Summary

Adds a first-class async auth-token provider to TS, Python, Rust, and Go (.NET already has one). The provider is invoked before every request to mint/refresh a token, with the result injected as the Authorization header using a configurable scheme (default Bearer).

  • TS: FetchBuilder.withAuthTokenProvider(provider, scheme?). PreRequestHook widened to allow async returns so the pipeline can await hooks.
  • Python: FetchBuilder.with_auth_provider(provider, scheme='Bearer'). Provider may be sync or async.
  • Rust: FetchBuilder::with_auth_provider(provider, scheme) with Arc<dyn Fn() -> Pin<Box<dyn Future<Output=String>>>>.
  • Go: ClientBuilder.WithAuthTokenProvider(provider, scheme) with func(ctx context.Context) (string, error) — propagates context + errors.

Test plan

  • TS — pnpm exec vitest run (48 passed; 4 new)
  • Python — uv run pytest (118 passed; 5 new)
  • Rust — cargo test (107 passed; 3 new)
  • Go — go test ./... (94 passed; 4 new)

Only .NET shipped a first-class `AuthTokenProvider` delegate. The other four
ports forced callers to wire auth either statically (`with_auth(string)`) or
manually via a pre-request hook. Add a real async provider hook to each.

TypeScript
----------
- `FetchBuilder.withAuthTokenProvider(provider, scheme = 'Bearer')`.
- `PreRequestHook` return type widened to allow `Promise<...>` so the
  pipeline can `await` async hooks. The new builder method composes with any
  existing pre-request hook (hook runs first, Authorization injected after).
- Export new `AuthTokenProvider` type.

Python
------
- `FetchBuilder.with_auth_provider(provider, scheme='Bearer')`.
- New `auth_token_provider` + `auth_scheme` fields on `FetchOptions`.
- Provider may return `str` or an awaitable; the client awaits inline.

Rust
----
- New `AuthTokenProvider` type alias
  (`Arc<dyn Fn() -> Pin<Box<dyn Future<Output=String>>>>`).
- `FetchBuilder::with_auth_provider(provider, scheme)`.
- `FetchClient` calls the provider before each `fetch()` / `fetch_with_options()`
  and injects the Authorization header into the merged init.

Go
--
- `AuthTokenProvider` type:
  `func(ctx context.Context) (string, error)`.
- `ClientBuilder.WithAuthTokenProvider(provider, scheme)`.
- Provider is invoked inside `executeHTTPRequest` after pre-request hook so
  cancellation/timeouts flow through; provider errors propagate via the
  PostResponseError hook chain.

Tests
-----
- TS: 4 new cases in `fetch.spec.ts` (sync, async, custom scheme, hook composition).
- Python: new `test_auth_provider.py` with 5 cases.
- Rust: new `auth_provider_tests.rs` with 3 cases.
- Go: new `auth_provider_test.go` with 4 cases.
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 12, 2026

🦋 Changeset detected

Latest commit: 498c982

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@smooai/fetch Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@brentrager brentrager merged commit 148364b into main May 12, 2026
1 check failed
@brentrager brentrager deleted the SMOODEV-948-async-auth-provider branch May 12, 2026 17:19
brentrager added a commit that referenced this pull request May 12, 2026
…ejection, FastFirst (#75)

Brings the .NET port closer to feature parity with the TS / Python / Rust /
Go ports. Existing `SmooFetchOptions` + `SmooFetch.Create` factory remain
for backwards compatibility — everything new is additive.

New surface
-----------
- `SmooFetchBuilder` (`SmooFetchBuilder.Create().With...().Build()`).
- `LifecycleHooks` with `PreRequest`, `PostRequestOk`, `PostRequestErr`.
- `CircuitBreakerOptions` + Polly v8 circuit breaker composed inside the
  resilience pipeline. Trips on the same predicates as the retry policy.
- `OnRejectionCallback` / `OnRejectionDecision` (`Retry` / `RetryWithDelay` /
  `Abort` / `Skip` / `Default`) honored by the Polly `DelayGenerator`.
- `RetryPolicy.FastFirst` — first retry fires with zero delay.
- `RetryPolicy` converted to `record` so builder methods can use `with` to
  compose policies on the fly.

Tests
-----
New `SmooFetchBuilderTests` (7 cases) cover the builder happy path,
PreRequest / PostRequestOk hook firing, the PostRequestErr documented
behavior (only fires on transport-level throws, not HttpResponseError from
the JSON reader), FastFirst skipping the initial backoff, OnRejection
RetryWithDelay overriding the default delay, and the circuit breaker
tripping after the failure threshold.

Also included
-------------
- `#[allow(dead_code)]` on `TestReply` in the Rust `auth_provider_tests.rs`
  added in PR #72 — the struct is only used as a `serde` deserialization
  target so cargo errors under `-D warnings` without the annotation.

Out of scope (parked as follow-up)
----------------------------------
- Sliding-window rate limiter for .NET (callout from SMOODEV-946: "Rate
  limiter and FastFirst can ship as a follow-up if context is tight" —
  FastFirst is included; rate limiter is the only remaining gap).

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

1 participant