Skip to content

Add TokenProvider.auto for ADC-style provider selection - #24

Merged
alejandrohdezma merged 5 commits into
mainfrom
feat/auto
Jun 1, 2026
Merged

Add TokenProvider.auto for ADC-style provider selection#24
alejandrohdezma merged 5 commits into
mainfrom
feat/auto

Conversation

@alejandrohdezma

Copy link
Copy Markdown
Collaborator

💻 How to review this PR?

This PR was created with the idea of being reviewed commit by commit. Each commit contains an incremental change that makes it easier to review. Also some of the commits contain additional information in their description to help understand why the change was made.

I also recommend checking "Hide whitespace" when reviewing this PR!

🚀 What's included in this PR?

Adds TokenProvider.auto — picks the right token provider using Google's standard ADC precedence, dispatching on the credentials file's "type" field:

  1. service_account JSON → serviceAccount(email, key, scopes, httpClient)
  2. authorized_user JSON → userAccount(clientId, clientSecret, refreshToken, httpClient)
  3. No file → metadata-server fallback (serviceAccount(httpClient) for access tokens, identity(httpClient, audience) for identity tokens)
  4. Any other "type" → raises UnsupportedCredentialsType (e.g. external_account, impersonated_service_account, gdch_service_account).

Useful when the same binary runs locally (user account), in CI (service-account JSON via GOOGLE_APPLICATION_CREDENTIALS), and in production (workload identity on GCE/GKE).

Also includes:

  • A new userIdentity(clientId, clientSecret, refreshToken, httpClient) overload mirroring the existing userAccount triple-overload — extracted so the principal-resolution / token-fetch logic lives in one place.
  • Three argless TokenProvider.auto overloads that allocate a default JdkHttpClient internally and return a Resource[F, TokenProvider[F]].

Pull the refresh-token exchange + JWT-decode principal lookup out of
`userIdentity(httpClient)` into a new public
`userIdentity(clientId, clientSecret, refreshToken, httpClient)` overload,
mirroring the existing `userAccount` shape. The single-arg variant now
just dispatches via the ADC `CredentialsFile` AST and delegates to the
triple-overload, keeping the parsing path in one place.
Three overloads picking the right factory using Google's standard
"Application Default Credentials" precedence:

- `auto(client)` and `auto(scopes, client)` resolve access-token
  providers — service-account JSON or authorized-user JSON when an
  ADC file is present (auto-detected from contents), or the GCE
  metadata server's workload identity when no file is configured.
- `auto(client, audience)` resolves identity-token providers,
  dispatching `userIdentity` vs `identity(client, audience)` by ADC
  file presence.

Uses `Parser.onDefaultCredentialsFile` for the dispatch and reuses
the `UnableToGetClientData` failure mode to distinguish SA from
authorized-user JSON without a separate parse pass.
@alejandrohdezma
alejandrohdezma requested a review from a team as a code owner May 25, 2026 18:26
@github-actions github-actions Bot added 🚀 feature New feature or improvement ⚖️ M Size of PR between 100 and 500 lines labels May 25, 2026
When `GCP_AUTH_DISABLE=true` (env var) or `gcp.auth.disable=true` (JVM
system property) is set, every `TokenProvider.auto` overload
short-circuits to `TokenProvider.const(AccessToken.noop)` — no
filesystem reads, no metadata-server probes. Intended for acceptance
tests that need to silence credential resolution without plumbing a
separate `TokenType` through the application config.

A stray production setting will silently produce a no-op provider
instead of a loud "credentials not found" error. The Scaladoc and
README call out this trade-off and recommend `gcp-auth-pureconfig`'s
`TokenType.NoOp` as the safer alternative when the configuration
channel can be controlled per environment.

@Oliver-Taylor Oliver-Taylor left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Nice! This should make configuration most simpler

Base automatically changed from feat/principal to main June 1, 2026 17:01
@alejandrohdezma
alejandrohdezma merged commit 698a01e into main Jun 1, 2026
6 checks passed
@alejandrohdezma
alejandrohdezma deleted the feat/auto branch June 1, 2026 20:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

⚖️ M Size of PR between 100 and 500 lines 🚀 feature New feature or improvement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants