From de9d53958807d20fd4a4bed7220f3e66b50cd7be Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Sun, 25 Oct 2026 21:49:14 +0700 Subject: [PATCH] [Doc] Bound the token endpoint error docs to what sets the readers ## Motivation and Context The "Token endpoint errors" section opens with "When a token exchange or refresh fails", but the readers it describes are set only when the token endpoint answers with a non-2xx response within the body cap: a transport failure, a body over the cap, and a 2xx response with a broken body all raise `AuthorizationError` with `nil` readers. The section also leaves unsaid that `InvalidGrantError` is chosen on the raw `error` while the `error` reader holds the sanitized value, so a code the server padded, `"invalid_grant\n"` say, reads back as `error == "invalid_grant"` yet raises `AuthorizationError`; a reader inferring the class from the reader would get it wrong. The section now states the condition and the distinction. The sentence that other authorization failures have `nil` readers predates the authorization callback error of 1.7.0, which sets `error` and `error_description` with `http_status` left `nil`; the section now says so. A blank diagnostic field reads as `nil` as well, since the sanitizer strips it; the section says so too. ## How Has This Been Tested? Docs only. Both statements were checked against `token_endpoint_error` and `bounded_request` in `lib/mcp/client/oauth/flow.rb`. The callback sentence was checked against `authorization_response_error`. ## Breaking Changes None. --- docs/_client/authorization.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/docs/_client/authorization.md b/docs/_client/authorization.md index 3914b3d4..4f0cf0a5 100644 --- a/docs/_client/authorization.md +++ b/docs/_client/authorization.md @@ -268,8 +268,9 @@ so the storage should expire entries older than `pending_authorization_max_age`, ### Token Endpoint Errors -When a token exchange or refresh fails, `MCP::Client::OAuth::Flow::AuthorizationError` includes the HTTP status and -the authorization server's `error` and `error_description` from [RFC 6749 Section 5.2](https://www.rfc-editor.org/rfc/rfc6749#section-5.2). +When the token endpoint answers a token exchange or refresh with a non-2xx response within the body cap, +`MCP::Client::OAuth::Flow::AuthorizationError` includes the HTTP status and the authorization server's `error` +and `error_description` from [RFC 6749 Section 5.2](https://www.rfc-editor.org/rfc/rfc6749#section-5.2). For example: ```text @@ -277,9 +278,12 @@ Token endpoint returned status 400. invalid_request: Client must not use multipl ``` The exception exposes `http_status`, `error`, and `error_description` readers for structured diagnostics. Missing or non-string -diagnostic fields are `nil`; non-JSON responses retain the status-only message. Other authorization failures have `nil` readers. -An `invalid_grant` response still raises `Flow::InvalidGrantError`, a subclass of `Flow::AuthorizationError`, so refresh-token -recovery behavior is unchanged. +diagnostic fields are `nil`, as are blank ones; non-JSON responses retain the status-only message. +When the authorization server returns an error to the authorization callback ([RFC 6749 Section 4.1.2.1](https://www.rfc-editor.org/rfc/rfc6749#section-4.1.2.1)), +`error` and `error_description` are set the same way, with `http_status` left `nil`; other authorization failures have `nil` readers. +A token endpoint response whose raw `error` is exactly `invalid_grant` still raises `Flow::InvalidGrantError`, a subclass of +`Flow::AuthorizationError`, so refresh-token recovery behavior is unchanged. The class follows the raw value +while the `error` reader holds the sanitized one, so `error == "invalid_grant"` alone does not imply that class. Diagnostic fields are limited to 128 characters for `error` and 512 for `error_description`, including a trailing `...` when truncated. Characters outside the RFC's printable ASCII set are replaced with spaces, and surrounding whitespace is removed.