MCP.OAuth2.Client (fnord v0.9.38)
View SourcePure OAuth2 + PKCE client implementation for MCP servers.
Unlike OIDC libraries (like oidcc), this works with OAuth2 Authorization Server
discovery (RFC 8414) at /.well-known/oauth-authorization-server, not just
OpenID Connect discovery at /.well-known/openid-configuration.
Implements:
- Authorization Code flow with PKCE (RFC 7636)
- Token refresh (RFC 6749)
- OAuth2 server metadata discovery (RFC 8414)
- Resource Indicators (RFC 8707) via the optional
:resourceconfig key
The MCP authorization spec requires clients to send the canonical MCP
server URI as the resource parameter on both the authorization and
token requests so the server can bind the grant to that resource.
Servers that advertise a resource in their metadata (e.g. Linear)
hard-fail flows that omit it. Callers pass the server's base_url as
:resource; when absent the parameter is omitted for compatibility
with servers that predate RFC 8707.
Security:
- PKCE is always required (S256 challenge method)
- Tokens are never logged
- Uses secure random generation for state and verifier
Summary
Functions
Handle OAuth2 callback and exchange authorization code for tokens.
Refresh an expired access token using the refresh token.
Start OAuth2 authorization flow with PKCE.
Types
@type tokens() :: %{ access_token: String.t(), token_type: String.t(), expires_at: non_neg_integer(), refresh_token: String.t() | nil, scope: String.t() | nil }
Functions
@spec handle_callback(config(), map(), String.t(), String.t()) :: {:ok, tokens()} | {:error, term()}
Handle OAuth2 callback and exchange authorization code for tokens.
Validates state, extracts code, exchanges for tokens with PKCE verifier.
Returns: {:ok, tokens} with normalized token map
Refresh an expired access token using the refresh token.
Returns: {:ok, tokens} with new access token and possibly new refresh token
@spec start_flow(config()) :: {:ok, %{auth_url: String.t(), state: String.t(), code_verifier: String.t()}} | {:error, term()}
Start OAuth2 authorization flow with PKCE.
Fetches server metadata, generates PKCE parameters, and builds authorization URL.
Returns: {:ok, %{auth_url: String.t(), state: String.t(), code_verifier: String.t()}}