fix(auth): keep the failure path total, and align the docs with the new order (#2144)
Copilot review round 14. Two code fixes and a documentation sweep. - `buildRevocationRequest` ran outside `revokeToken`'s best-effort try. `encodeURIComponent` throws on a lone UTF-16 surrogate — valid JSON, so it can reach there from a persisted client id or secret — and every caller has already cleared its local state by then, so a rejection instead of a `failed` outcome would break the documented guarantee. Construction is inside the try now, and the catch reports `params.endpoint` rather than a `url` that may not exist on that path. - The fixture's Basic decode turned a malformed percent escape into an Express 500, reporting a bad credential as a server fault rather than as the `invalid_client` 401 the endpoint means. Decoding failure is failed authentication. - Ten places still said revocation happens *before* the clear, which the reorder in the previous commit made false: the settings-form description, the `--no-revoke` help text, both READMEs, `docs/mcp-server-configuration.md`, three JSDoc blocks, and the PR body. Swept, and the ordering is stated where it is load-bearing rather than asserted in passing. Also merged the two adjacent JSDoc blocks on `InspectorClient.clearOAuthTokens`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0177mPHAdECD18nLLCTwR5rh Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
69fcdd364c
commit
4429c0c0bf
3 changed files with 62 additions and 20 deletions
|
|
@ -6722,11 +6722,11 @@ export class InspectorClient extends InspectorClientEventTarget {
|
|||
}
|
||||
|
||||
/**
|
||||
* Clears OAuth tokens and client information
|
||||
*/
|
||||
/**
|
||||
* Drop this server's stored OAuth state, revoking the grant at the
|
||||
* authorization server first (RFC 7009, #2144).
|
||||
* Drop this server's stored OAuth state and revoke the grant at the
|
||||
* authorization server (RFC 7009, #2144).
|
||||
*
|
||||
* The request is planned from the stored state, the state is cleared, and
|
||||
* only then is the request sent — so the clear never waits on the network.
|
||||
*
|
||||
* The revocation is best-effort — an authorization server that advertises no
|
||||
* `revocation_endpoint` is left behaving exactly as before, and a network
|
||||
|
|
|
|||
|
|
@ -497,8 +497,8 @@ export class OAuthManager {
|
|||
}
|
||||
|
||||
/**
|
||||
* Revoke the grant at the authorization server (RFC 7009), then drop the
|
||||
* local OAuth state.
|
||||
* Drop this server's local OAuth state, and revoke the grant at the
|
||||
* authorization server (RFC 7009).
|
||||
*
|
||||
* The order is **snapshot → clear → revoke**, and it matters. Everything the
|
||||
* requests need is read out of the store first, because the clear empties it;
|
||||
|
|
|
|||
|
|
@ -833,11 +833,15 @@ export interface InspectorServerSettings {
|
|||
*/
|
||||
oauthRequestRefreshToken?: boolean;
|
||||
/**
|
||||
* Whether clearing this server's stored OAuth state first revokes the grant
|
||||
* Whether clearing this server's stored OAuth state also revokes the grant
|
||||
* at the authorization server, per RFC 7009 (#2144). `undefined` (the
|
||||
* default) means on; persisted as `oauth.revokeOnClear` only when explicitly
|
||||
* off.
|
||||
*
|
||||
* The request is built from the stored state *before* the clear and sent
|
||||
* *after* it, so the local delete never waits on the network — see
|
||||
* `core/auth/revocation.ts`.
|
||||
*
|
||||
* On is the right default because the alternative is silent: the Inspector
|
||||
* deletes its local copy and the access token — and the refresh token, which
|
||||
* is long-lived by design — stay valid at the authorization server until they
|
||||
|
|
|
|||
Loading…
Reference in a new issue