Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/client/src/client/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -866,7 +866,8 @@ function isLoopbackHost(hostname: string): boolean {
}

/**
* SEP-2207: refuse to send credentials to a non-TLS, non-loopback token endpoint.
* Refuses to send credentials to a non-TLS, non-loopback token endpoint
* (MCP authorization spec, OAuth 2.1 §1.5).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Do not cite §1.5 for loopback token endpoints

For a token endpoint such as http://127.0.0.1/token, this function permits the request, but OAuth 2.1 §1.5 limits its HTTP exception specifically to loopback-interface redirect URIs, not token endpoints. The new attribution therefore still presents the implemented loopback-token-endpoint exception as an OAuth 2.1 requirement; cite a normative source that actually permits this exception, or describe it as an SDK-specific policy.

Useful? React with 👍 / 👎.

* Throws {@linkcode InsecureTokenEndpointError}. Loopback hosts are exempt.
*/
export function assertSecureTokenEndpoint(tokenEndpoint: string | URL): URL {
Expand Down
3 changes: 2 additions & 1 deletion packages/client/src/client/authErrors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,8 @@ export class RegistrationRejectedError extends OAuthClientFlowError {

/**
* Thrown by the token-exchange and refresh paths when the resolved token
* endpoint is not `https:` and is not a loopback host (SEP-2207). This is a
* endpoint is not `https:` and is not a loopback host (MCP authorization spec,
* OAuth 2.1 §1.5). This is a
* configuration error — re-authorizing cannot fix it — so it intentionally does
* **not** extend `OAuthError` and `auth()`'s refresh branch rethrows it instead
* of falling through to a fresh `/authorize` redirect.
Expand Down
Loading