Add getBearerToken callback for BYOK providers (Managed Identity)#1748
Add getBearerToken callback for BYOK providers (Managed Identity)#1748SteveSandersonMS wants to merge 2 commits into
Conversation
This comment has been minimized.
This comment has been minimized.
Lets BYOK provider configs supply a `getBearerToken` callback so the SDK consumer resolves bearer tokens (e.g. Azure Managed Identity via @azure/identity) on demand. The callback never crosses the wire: the SDK strips it from the provider config, sends a `hasBearerTokenProvider: true` flag, and answers the runtime's session-scoped `providerToken.acquire` RPC by routing to the matching per-provider callback. The returned token is applied as the Authorization header for outbound model requests; the consumer owns caching/refresh. - client.ts: strip the callback, emit the `hasBearerTokenProvider` wire flag, register per-provider callbacks on the session. - session.ts: handle `providerToken.acquire` by dispatching on provider name. - types.ts: public `getBearerToken` / `ProviderTokenArgs` / `ProviderBearerToken`. - generated/rpc.ts: regenerated contract (providerToken.acquire + hasBearerTokenProvider/bearerTokenScope fields). - e2e: callback token reaches model, refresh-on-expiry, per-provider dispatch. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
0ba9325 to
d321d4a
Compare
Cross-SDK Consistency ReviewThis PR adds the experimental What this PR adds (Node.js)
Cross-SDK gaps foundAll five other SDKs (Python, Go, .NET, Java, Rust) currently have 1. This is a new wire-protocol field added to the Affected files:
2. The callback-based bearer token provider (
3. This is the most critical gap. When the runtime needs a token, it issues a Affected files: each SDK's session/client RPC registration layer. RecommendationSince this feature is marked
Would it make sense to open tracking issues for each SDK, or is this already planned as follow-up work?
|
Mirror the runtime contract simplification: the runtime no longer caches provider tokens, it calls getBearerToken once per outbound request. Drop the vestigial `scope`/`bearerTokenScope` (the callback closes over its own scope/ audience) and stop forwarding `expiresOnTimestamp` over the wire. The field is retained on `ProviderBearerToken` so an Azure Identity `AccessToken` can be returned verbatim, but it is now documented as ignored — caching and refresh are the callback's responsibility (e.g. `@azure/identity` caches internally). Rewrite the e2e suite to drive a local capturing HTTP server as the BYOK endpoint instead of CAPI record/replay snapshots, so the tests assert on the outbound Authorization header directly and pass identically in record and replay mode. Delete the obsolete snapshots. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Thanks — a couple of these points are now moot after a contract simplification pushed since this review ran:
So the remaining cross-SDK surface is just (2) the |
Summary
Adds an experimental
getBearerTokencallback to BYOK provider configs so the SDK consumer can resolve bearer tokens (e.g. Azure Managed Identity via@azure/identity) on demand. The Copilot SDK takes zero Azure dependency — the consumer fills in the callback with their own identity library.The callback never crosses the wire. The SDK strips it from the provider config and sends a
hasBearerTokenProvider: trueflag. When the runtime needs a token it issues a session-scopedproviderToken.acquireRPC, which the SDK routes to the matching per-provider callback; the returned token is applied as theAuthorizationheader for the outbound model request. The runtime does no caching — it invokes the callback once per request, so the consumer (or the identity library it wraps) owns caching/refresh. Scope/audience is closed over by the callback and never crosses the wire.Public surface
Consumer example (the callback binds its own scope):
Returning a bare
stringis equivalent to{ token }. An@azure/identityAccessTokencan be returned verbatim — itsexpiresOnTimestampis accepted for ergonomics but ignored (the library already caches internally).Changes
client.ts— strip the callback, emit thehasBearerTokenProviderwire flag, register per-provider callbacks on the session.session.ts— handleproviderToken.acquire, dispatching on provider name.types.ts— publicgetBearerToken/ProviderTokenArgs/ProviderBearerToken.generated/rpc.ts— regenerated contract (providerToken.acquire+hasBearerTokenProvider).Authorizationheader directly; no CAPI snapshots, passes in record and replay).Notes
hasBearerTokenProvider).main; the prior draft PR Add getBearerToken callback for BYOK providers (Managed Identity v1) #1746 is left intact for reference.Test plan
npm run typecheck