docs/clients/auth/client-credentials.mdx
import { VersionBadge } from "/snippets/version-badge.mdx"
<VersionBadge version="4.0.0" /> <Tip> Machine-to-machine authentication is only relevant for HTTP-based transports. </Tip>When a FastMCP client runs without a human present — a backend service, a scheduled job, a CI pipeline, one MCP server calling another — it cannot complete the browser-based OAuth flow. Instead it authenticates as itself using the OAuth 2.0 client credentials grant: the client presents its own credentials directly to the authorization server, receives an access token, and attaches that token to every request. There is no redirect, no consent screen, and no user.
FastMCP provides two providers for this, both implementing the httpx2.Auth interface so they drop into the same auth= parameter as every other client auth option. You pass the MCP server URL, not a token endpoint — the token endpoint is discovered from the server's OAuth metadata, exactly as the interactive OAuth helper does. As with OAuth, you can omit the URL entirely and let the transport supply it.
The common case is a pre-registered client with an ID and a secret. Use ClientCredentialsOAuthProvider and pass it to the auth parameter of your Client or transport:
from fastmcp import Client
from fastmcp.client.auth import ClientCredentialsOAuthProvider
auth = ClientCredentialsOAuthProvider(
client_id="my-client-id",
client_secret="my-client-secret",
scopes=["read", "write"],
)
async with Client("https://example.com/mcp", auth=auth) as client:
await client.list_tools()
The provider discovers the authorization server, exchanges the credentials for an access token, and caches the token in memory for the life of the client. When the token expires it is re-acquired automatically on the next request. Because re-acquiring a token is a single non-interactive request, tokens are held in memory by default with no warning — unlike the interactive OAuth flow, losing the cache on restart costs nothing.
ClientCredentialsOAuthProvider Parametersmcp_url (str, optional): Full URL to the MCP endpoint. Omit it when passing the provider to Client(auth=...) — the transport supplies the URL automatically.client_id (str, required): The pre-registered OAuth client ID.client_secret (str, required): The OAuth client secret.scopes (str | list[str], optional): Scopes to request, as a space-separated string or a list.token_endpoint_auth_method ("client_secret_basic" | "client_secret_post", optional): How the credentials are presented to the token endpoint. Defaults to "client_secret_basic" (an HTTP Basic Authorization header); use "client_secret_post" to send them in the request body instead.token_storage (AsyncKeyValue, optional): A key-value store for the acquired token. Defaults to in-memory storage.Some authorization servers require the client to prove its identity with a signed JWT assertion (RFC 7523 private_key_jwt) instead of a shared secret. This is common with workload identity federation, where the assertion comes from a cloud identity provider. Use PrivateKeyJWTOAuthProvider and supply an assertion_provider — an async callback that receives the authorization server's issuer identifier (the required JWT audience) and returns the assertion.
For a locally signed assertion, build the callback with SignedJWTParameters:
from pathlib import Path
from fastmcp import Client
from fastmcp.client.auth import (
PrivateKeyJWTOAuthProvider,
SignedJWTParameters,
)
private_key_pem = Path("client-signing-key.pem").read_text()
jwt_params = SignedJWTParameters(
issuer="my-client-id",
subject="my-client-id",
signing_key=private_key_pem,
)
auth = PrivateKeyJWTOAuthProvider(
client_id="my-client-id",
assertion_provider=jwt_params.create_assertion_provider(),
)
async with Client("https://example.com/mcp", auth=auth) as client:
await client.list_tools()
If you already have a JWT from an identity provider, wrap it with static_assertion_provider, or pass your own async def provider(audience: str) -> str callback to fetch one on demand.
PrivateKeyJWTOAuthProvider Parametersmcp_url (str, optional): Full URL to the MCP endpoint. Omit it when passing the provider to Client(auth=...).client_id (str, required): The OAuth client ID.assertion_provider (Callable[[str], Awaitable[str]], required): Async callback that receives the authorization server's issuer identifier and returns a signed JWT assertion.scopes (str | list[str], optional): Scopes to request, as a space-separated string or a list.token_storage (AsyncKeyValue, optional): A key-value store for the acquired token. Defaults to in-memory storage.