Azure-Samples / Azure-Samples/claude
Use anthropic SDK 0.109+ credentials= for long-running token refresh (drop AnthropicIdentity subclass)
- Dominant language
- PowerShell
- Stars
- 37
- Forks
- 15
- Avg merge
- 3d 14h
- Merged PRs (30d)
- 1
Description
### Background
The long-running sample [src/hello_claude_token_refresh.py](src/hello_claude_token_refresh.py) defines an AnthropicIdentity(Anthropic) subclass that overrides the uth_token property as a workaround for the SDK only accepting a static uth_token: str. The plain Anthropic client's captured Entra ID token would otherwise start failing with 401 after ~1 hour, which is why the shim exists.
### What changed upstream
Anthropic Python SDK v0.98.0 (May 2026) added a public `credentials=` constructor parameter on `Anthropic` / `AsyncAnthropic` that takes an `AccessTokenProvider` (a callable returning an `AccessToken(token, expires_at)`). The SDK wraps it in an internal `TokenCache` that:
- Calls the provider lazily (no token fetched at client construction).
- Caches the token and reuses it across requests.
- On a `401` response, invalidates the cache and retries the request once with a freshly minted token (`_should_retry` override in `_client.py`).
This is exactly the capability the `AnthropicIdentity` shim was emulating. `auth_token` itself is still a static `str` (so https://github.com/anthropics/anthropic-sdk-python/issues/1496 remains open for the narrower "make `auth_token` accept a Callable" ask), but the more general `credentials=` path solves the long-running use case cleanly.
Verified against `src/anthropic/lib/credentials/_types.py` and `src/anthropic/_client.py` at tag `v0.109.1`.
### Proposed change
- Bump `anthropic>=0.109.1` in [requirements.txt](requirements.txt).
- Rewrite [src/hello_claude_token_refresh.py](src/hello_claude_token_refresh.py) to:
- Delete the `AnthropicIdentity(Anthropic)` subclass.
- Build a tiny `AccessTokenProvider` from `DefaultAzureCredential` that returns `AccessToken(token=t.token, expires_at=t.expires_on)` (`expires_on` is unix seconds, same format the SDK expects).
- Pass it to `Anthropic(credentials=provider, base_url=...)`.
- Update the **long-running** code snippet in the README's collapsed *SDK call shape* section to match. The one-shot `hello_claude.py` and its snippet are unchanged.
### Out of scope
- No change to `src/hello_claude.py` (the short-lived script path keeps using `auth_token=token` — still the simplest pattern for one-shot runs).
- No change to `src/check_claude_quota.py`, `src/hello_claude_apikey.py`, or the verifier scripts.
- No change to RBAC, infra, or hooks.
Contributor guide
Assessment
This issue has not been assessed yet.