Skip to content

feat(auth): add CredentialStore and cache GCP credentials#1174

Open
wolo-lab wants to merge 2 commits into
wolo/auth-gcp-providerfrom
wolo/auth-store-cache
Open

feat(auth): add CredentialStore and cache GCP credentials#1174
wolo-lab wants to merge 2 commits into
wolo/auth-gcp-providerfrom
wolo/auth-store-cache

Conversation

@wolo-lab

@wolo-lab wolo-lab commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Problem

The GCP provider does a credential-service round-trip (plus up to a ~10s pending
poll) on every request; there is no caching. adk-python has an
InMemoryCredentialService.

Summary

  • Add `auth.CredentialStore` + `InMemoryCredentialStore`: concurrency-safe,
    with per-entry expiry and a small clock-skew margin. TokenSource-backed
    providers are self-caching and do not need it.
  • The GCP provider caches via the store (default in-memory, override with
    `ProviderConfig.Store`), keyed by (app, user, resource); the client surfaces
    the service's `expireTime` so entries expire correctly.

@wolo-lab
wolo-lab force-pushed the wolo/auth-store-cache branch from 995f518 to 32dc472 Compare July 18, 2026 20:44
@wolo-lab
wolo-lab force-pushed the wolo/auth-gcp-provider branch from a46455a to 421a856 Compare July 18, 2026 20:44
Add auth.CredentialStore (keyed by app+user+slot) with an in-memory
implementation, and use it in the GCP provider so a resolved credential is
reused across requests instead of hitting the credential service on every tool
call (each miss is a round-trip plus up to a ~10s pending poll).

- auth.CredentialStore / InMemoryCredentialStore: concurrency-safe, agent-free
  (keyed by explicit strings), with per-entry expiry and a small clock-skew
  margin. TokenSource-backed providers are self-caching and do not need it.
- gcp.Provider caches via the store (default in-memory, override with WithStore),
  keyed by (appName, userID, resource); the GCP client now surfaces the
  service's expireTime so entries expire correctly.

Deferred (documented): SessionStateCredentialStore lands with the interactive
consent flow (A3) — it persists across the consent round-trip and needs write
access to session state, which the read-only RoundTripper/provider path does not
have. Downstream-401 invalidation (force_refresh) is a follow-up.
@wolo-lab
wolo-lab force-pushed the wolo/auth-store-cache branch from 32dc472 to d392cd9 Compare July 18, 2026 23:33
@wolo-lab
wolo-lab force-pushed the wolo/auth-gcp-provider branch from 421a856 to eadd5a6 Compare July 18, 2026 23:33
…thod

RetrieveCredential was a thin public wrapper that dropped the expiry from an
unexported retrieve() the provider called directly, so the real prod path used
the unexported variant while the public one was test-only. Collapse both into a
single RetrieveCredential returning *Retrieval{Credential, ExpiresAt}, making
the expiry a documented public field (zero => "do not cache").
@wolo-lab
wolo-lab force-pushed the wolo/auth-store-cache branch from eb90b2c to b8ec0e5 Compare July 19, 2026 14:48
@wolo-lab
wolo-lab marked this pull request as ready for review July 19, 2026 14:58
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