ExMCP.Authorization.OAuthFlow (ex_mcp v0.10.0)
View SourceOAuth 2.1 flow implementations for MCP authorization.
This module handles the core OAuth flows:
- Authorization Code Flow with PKCE
- Client Credentials Flow
- Token refresh flow
Summary
Functions
Performs OAuth 2.1 client credentials flow.
Performs OAuth 2.1 client credentials flow with JWT client authentication (private_key_jwt).
Exchanges an authorization code for tokens.
Initiates a full re-authorization flow with an expanded scope set.
Refreshes an access token using a refresh token.
Starts the OAuth 2.1 authorization code flow with PKCE.
Types
@type token_response() :: %{ access_token: String.t(), token_type: String.t(), expires_in: non_neg_integer() | nil, refresh_token: String.t() | nil, scope: String.t() | nil }
Functions
@spec client_credentials_flow(client_credentials_params()) :: {:ok, token_response()} | {:error, term()}
Performs OAuth 2.1 client credentials flow.
@spec client_credentials_jwt_flow(jwt_credentials_params()) :: {:ok, token_response()} | {:error, term()}
Performs OAuth 2.1 client credentials flow with JWT client authentication (private_key_jwt).
Uses RFC 7523 Section 2.2 client assertions instead of a client secret.
@spec exchange_code_for_token(token_params()) :: {:ok, token_response()} | {:error, term()}
Exchanges an authorization code for tokens.
@spec reauthorize_with_scopes(auth_params(), [String.t()]) :: {:ok, String.t(), map()} | {:error, term()}
Initiates a full re-authorization flow with an expanded scope set.
Used when a refresh token is not available or the server does not support scope upgrades via refresh. This starts a new authorization code flow with the combined current + additional scopes.
@spec refresh_token(String.t(), String.t(), String.t(), keyword() | String.t() | nil) :: {:ok, token_response()} | {:error, term()}
Refreshes an access token using a refresh token.
Options
client_secret- Client secret for confidential clients (default: nil)scope- Space-separated scope string to request expanded scopes during refresh. Used for incremental scope upgrades (2025-11-25). If the authorization server supports it, the new token will have the expanded scope set.
@spec start_authorization_flow(auth_params()) :: {:ok, String.t(), map()} | {:error, term()}
Starts the OAuth 2.1 authorization code flow with PKCE.
Example
{:ok, auth_url, state} = OAuthFlow.start_authorization_flow(%{
client_id: "my-client",
redirect_uri: "http://localhost:8080/callback",
authorization_endpoint: "https://auth.example.com/oauth/authorize",
scopes: ["mcp:read", "mcp:write"]
})