# `GcpCompute.TokenProvider`
[🔗](https://github.com/nyo16/gcp_compute/blob/v0.3.0/lib/gcp_compute/token_provider.ex#L1)

Behaviour for minting the OAuth2 access tokens used to authenticate Compute
API requests.

The library never hard-depends on a particular auth mechanism. A
`GcpCompute.Config` holds a `{module, arg}` pair; before each request the
configured `module.fetch_token(arg)` is invoked.

Built-in implementations:

  * `GcpCompute.TokenProvider.Goth` — mints tokens via [Goth](https://hexdocs.pm/goth)
    (the `arg` is the registered Goth name). This is the production default.
  * `GcpCompute.TokenProvider.Static` — returns a fixed token, a `%{token: ...}`
    map, or the result of a zero-arity function. Handy for tests and the
    Compute emulator.

## Writing your own

    defmodule MyApp.WorkloadIdentity do
      @behaviour GcpCompute.TokenProvider

      @impl true
      def fetch_token(_arg) do
        # ... fetch from the metadata server, Vault, etc.
        {:ok, %{token: token, expires: unix_seconds}}
      end
    end

then `GcpCompute.Config.new(token_provider: {MyApp.WorkloadIdentity, []}, ...)`.

# `token`

```elixir
@type token() :: %{
  :token =&gt; String.t(),
  optional(:type) =&gt; String.t(),
  optional(:expires) =&gt; non_neg_integer()
}
```

A minted token.

Only `:token` is required. `:type` and `:expires` are **advisory metadata that
this library deliberately does not read**: `GcpCompute` holds no token cache,
so there is nothing for an expiry to invalidate. Caching and refresh are the
provider's job (as in Goth), which is the only place that can renew a
credential. The fields are part of the type so a provider can surface them to
its own callers and so `%{token: _}` maps from Goth pass through unchanged.

# `fetch_token`

```elixir
@callback fetch_token(arg :: term()) :: {:ok, token()} | {:error, term()}
```

Return a valid access token, or an error.

Implementations are expected to cache/refresh internally (as Goth does) —
`fetch_token/1` is called on every request and must be cheap on the hot path.

Return `{:ok, %{token: binary}}` or `{:error, reason}`. Anything else — an
unwrapped token, `nil`, a 3-tuple — is rejected with
`%GcpCompute.Error{reason: :invalid_token_provider_return}` before any request
is sent, and the returned value is kept only in the error's redacted `:body`.
Put no credential in an error `reason`: it can reach logs.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
