# `ConduitMcp.Client.OAuth.ClientCredentials`
[🔗](https://github.com/nyo16/conduit_mcp/blob/v0.11.0/lib/conduit_mcp/client/oauth/client_credentials.ex#L2)

Machine-to-machine authorization: the OAuth 2.1 `client_credentials`
grant (the MCP `io.modelcontextprotocol/oauth-client-credentials`
extension). No user and no browser: the client authenticates as itself
and gets a token for the MCP server. Compiled only with `:finch`.

    {ConduitMcp.Client,
     name: :reports,
     transport:
       {ConduitMcp.Client.Transport.StreamableHTTP,
        url: "https://mcp.example.com/mcp",
        auth:
          {:client_credentials,
           client_id: "reporting-service",
           client_secret: {:system, "MCP_CLIENT_SECRET"},
           scopes: ["reports:read"]}}}

Discovery is the same as for the authorization-code flow (Protected
Resource Metadata, then the authorization server's metadata; `S256` and
an `authorization_endpoint` are not required). The token request
carries `resource` (RFC 8707) and `scope` (the configured `:scopes`,
else the server's `scopes_supported`), and authenticates the client
with:

  * `client_secret` - a string, a `ConduitMcp.Client.Secret` or
    `{:system, "VAR"}` (read from the environment on every token
    request, never kept), sent as `client_secret_basic` (default) or
    `client_secret_post` (`token_endpoint_auth_method:`);
  * `private_key` - a private JWK map or PEM for `private_key_jwt`
    (RFC 7523): a signed assertion with `aud` = the token endpoint.
    Needs the optional `:jose` dependency, checked when the options
    are validated.

Tokens are cached in the token store under `{principal, issuer,
resource}` like any other, and renewed by requesting a new one when
they expire (within `refresh_skew`), single-flight. A step-up (403
`insufficient_scope`) requests a new token for the union of the held and
challenged scopes, within `max_step_up_attempts`.

`ConduitMcp.Client.OAuth.token_for/2` returns the current token; this
module holds the token request itself.

---

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