Oauth
Category: Mcp_client
Source: oauth.dart
OAuth 2.1 Authorization Code Flow + PKCE + Dynamic Client Registration for MCP servers.
Used by glue mcp auth login <server> (and /mcp auth login).
Flow:
- Discover the authorization-server metadata at
<base>/.well-known/oauth-authorization-server(RFC 8414). - (Optional) Dynamically register a client (RFC 7591) and persist the issued
client_idso we don't re-register on subsequent logins for the same server. - Open the user's browser to
authorization_endpoint?...with a PKCE challenge + a freshstateparameter. - Bind a one-shot loopback HTTP server on
127.0.0.1:0that the browser will redirect to. Capturecode+ verifystate. - Exchange the code at
token_endpointfor an access token (+ optional refresh token). - Persist the tokens to [CredentialStore] under
mcp:<server-id>with the field names declared in [McpOAuthFields].
No secrets are logged. The browser URL itself is shown to the user (it contains the state + challenge but no token).
Enums
McpAuthInvalidation
Scope of an MCP auth invalidation. Mirrors the TS SDK's OAuthClientProvider.invalidateCredentials(scope) granularity so we can drop just the bit that failed without round-tripping DCR or rediscovery.
| Value | Description |
|---|---|
client | |
scope | |
all | |
refresh_token | |
expires_at |
Classes
McpAuthDiscovery
Result of [discoverMcpAuth] — everything needed to run the auth flow and cache the outcome in config.
Constructor
const McpAuthDiscovery({
required this.endpoints,
required this.scopes,
this.resourceMetadataUrl,
this.authorizationServer,
})Properties
| Property | Type | Description |
|---|---|---|
endpoints | OAuthEndpoints | |
scopes | List<String> | |
resourceMetadataUrl | Uri? | null when discovery fell back to the legacy direct path. |
authorizationServer | Uri? | null when discovery fell back to the legacy direct path. |
OAuthEndpoints
Constructor
const OAuthEndpoints({
required this.authorizationEndpoint,
required this.tokenEndpoint,
this.registrationEndpoint,
this.scopesSupported = const [],
})factory OAuthEndpoints.fromMetadata(Map<String, dynamic> json)Properties
| Property | Type | Description |
|---|---|---|
authorizationEndpoint | Uri | |
tokenEndpoint | Uri | |
registrationEndpoint | Uri? | |
scopesSupported | List<String> |
OAuthDiscoveryException
Constructor
const OAuthDiscoveryException(this.message)Properties
| Property | Type | Description |
|---|---|---|
message | String |
Methods
String toString()
ProtectedResourceMetadata
Parsed RFC 9728 protected resource metadata document.
Constructor
const ProtectedResourceMetadata({
required this.resource,
required this.authorizationServers,
this.scopesSupported = const [],
required this.metadataUrl,
})Properties
| Property | Type | Description |
|---|---|---|
resource | Uri | resource field — should equal the MCP server's origin. |
authorizationServers | List<Uri> | authorization_servers — MCP requires at least one. |
scopesSupported | List<String> | scopes_supported — passed through to authorize URL when no WWW-Authenticate scope is available. |
metadataUrl | Uri | URL the metadata was fetched from — cached in config to skip rediscovery next session. |
client | final | |
ownsClient | final | |
path | final | |
res | final | |
json | final | |
resourceRaw | final | |
authServersRaw | final | |
authServers | final | |
scheme | String | |
parameters | Map<String, String> | |
trimmed | final | |
spaceIdx | final | |
scheme | final | |
rest | final | |
params | final | |
out | final | |
i | var | |
resourceMetadata | Uri? get | resource_metadata parameter from RFC 9728 §5.1. The MCP spec requires servers to advertise this URL on 401. |
scope | List<String> get | Space-delimited scopes from RFC 6750 §3. Empty list when absent. |
Methods
`const WwwAuthenticateChallenge({
required this.scheme,
required this.parameters,
})`
return WwwAuthenticateChallenge(scheme: 'Bearer', parameters: params)
WwwAuthenticateChallenge
Parsed WWW-Authenticate: Bearer … challenge. Only Bearer is relevant for MCP — other schemes return null from [parseWwwAuthenticate].
Constructor
const WwwAuthenticateChallenge({
required this.scheme,
required this.parameters,
})Properties
| Property | Type | Description |
|---|---|---|
scheme | String | |
parameters | Map<String, String> | |
resourceMetadata | Uri? get | resource_metadata parameter from RFC 9728 §5.1. The MCP spec requires servers to advertise this URL on 401. |
scope | List<String> get | Space-delimited scopes from RFC 6750 §3. Empty list when absent. |
OAuthClient
Constructor
const OAuthClient({required this.clientId, this.clientSecret})Properties
| Property | Type | Description |
|---|---|---|
clientId | String | |
clientSecret | String? |
OAuthRegistrationException
Constructor
const OAuthRegistrationException(this.message)Properties
| Property | Type | Description |
|---|---|---|
message | String |
Methods
String toString()
OAuthTokens
Constructor
const OAuthTokens({
required this.accessToken,
this.refreshToken,
this.expiresAt,
this.scope,
})Properties
| Property | Type | Description |
|---|---|---|
accessToken | String | |
refreshToken | String? | |
expiresAt | DateTime? | |
scope | String? |
OAuthFlowException
Constructor
const OAuthFlowException(this.message)Properties
| Property | Type | Description |
|---|---|---|
message | String |
Methods
String toString()
abstract McpOAuthFields
Field names used under CredentialStore's mcp:<server-id> namespace for OAuth-style auth. Bearer-token-only servers use the parallel bearer field; the two flows are orthogonal.
Properties
| Property | Type | Description |
|---|---|---|
accessToken | const String | |
refreshToken | const String | |
expiresAtIso | const String | |
clientId | const String | |
clientSecret | const String | |
scope | const String |
Functions
`Future<OAuthEndpoints> discoverOAuthEndpoints(
Uri serverBaseUrl, { http.Client? httpClient, })`
Discovers the OAuth metadata for an MCP server. Tries the canonical RFC 8414 path (/.well-known/oauth-authorization-server); falls back to the OIDC discovery path (/.well-known/openid-configuration).
`Future<McpAuthDiscovery> discoverMcpAuth({
required Uri serverUrl, String? wwwAuthenticate, Uri? cachedResourceMetadataUrl, http.Client? httpClient, })`
MCP-spec discovery: RFC 9728 protected resource metadata → RFC 8414 authorization server metadata. Falls back to the legacy direct probe against the server URL when no RFC 9728 metadata is found.
Scopes from WWW-Authenticate win over scopes_supported in protected-resource metadata (RFC 6750 + MCP spec).
`Future<OAuthEndpoints> discoverAuthorizationServerMetadata({
required Uri authServer, http.Client? httpClient, })`
Discovers RFC 8414 authorization server metadata for [authServer]. Falls back to OIDC discovery (/.well-known/openid-configuration).
Validates the issuer field equals the URL the metadata was fetched from — required by RFC 8414 §3.3 and MCP §"After retrieving a metadata document".
Throws [OAuthDiscoveryException] when no compliant metadata is found.
`Future<ProtectedResourceMetadata> discoverProtectedResourceMetadata({
required Uri serverUrl, Uri? resourceMetadataUrl, http.Client? httpClient, })`
Discovers RFC 9728 protected resource metadata for an MCP server.
Tries, in order:
- [resourceMetadataUrl] when supplied (from
WWW-Authenticateor cached config). <server>/.well-known/oauth-protected-resource{path}— RFC 9728 path-suffix form.<server>/.well-known/oauth-protected-resource— root form.
Throws [OAuthDiscoveryException] when nothing returns valid metadata.
WwwAuthenticateChallenge? parseWwwAuthenticate(String? header)
Parses a WWW-Authenticate header. Returns null when the header is missing, empty, or carries a non-Bearer scheme.
Handles RFC 7235 quoted-string values (which may contain commas).
`Future<OAuthClient> registerOAuthClient({
required Uri registrationEndpoint, required Uri redirectUri, required String clientName, http.Client? httpClient, })`
`Future<OAuthTokens> refreshOAuthTokens({
required OAuthEndpoints endpoints, required OAuthClient client, required String refreshToken, http.Client? httpClient, })`
Refresh-token grant. Returns new tokens; the refresh token may rotate.
`void storeMcpOAuthTokens({
required String serverId, required OAuthClient client, required OAuthTokens tokens, required CredentialStore credentials, })`
Persists [tokens] + [client] into the credential store under mcp:<serverId>. Idempotent — re-running the login flow overwrites.
`void clearMcpOAuthTokens({
required String serverId, required CredentialStore credentials, })`
Clears all OAuth fields for [serverId] from the credential store. Leaves the bearer field (if any) intact.
`void invalidateMcpAuth({
required String serverId, required McpAuthInvalidation scope, required CredentialStore credentials, })`
Drops [scope]'s portion of MCP OAuth credentials for [serverId]. No-op for [McpAuthInvalidation.discovery] (handled in the config writer).
`String? readMcpOAuthAccessToken({
required String serverId, required CredentialStore credentials, })`
Reads the current OAuth access token for [serverId]. Returns null when nothing is stored. Does not refresh — callers handle expiry elsewhere.