Clearing the Inspector's OAuth state deleted the local copy of the tokens and stopped there. The access token — and the refresh token, which is long-lived by design — stayed valid at the authorization server until they expired on their own, so a day of connect/disconnect iteration left it holding grants for sessions that ended hours ago. RFC 7009 §1 describes exactly that case, and nothing in the repo constructed a revocation request, so a server author implementing `revocation_endpoint` had no way to exercise it with the tool that exists to exercise this. core/auth/revocation.ts builds and sends the request; the three clear paths call it, so the behavior is written once — web's "Clear OAuth state and disconnect" (both the active and stored-only paths), the TUI's Auth tab, and the CLI's --relogin. It runs BEFORE the local clear, because the token, the client credentials and the discovered `revocation_endpoint` all live in the store the clear is about to empty. The request names the refresh token when there is one: §2.1 asks the AS to also invalidate the access tokens issued under the same grant, so one request covers both halves. Best-effort by construction. Every path returns a TokenRevocationOutcome rather than throwing: no advertised endpoint means nothing is sent and that authorization server behaves exactly as before, and a network error, a non-2xx, a 5s timeout or an unreadable store is reported and nothing more. Forgetting the tokens is what the user asked for. `lost_authorization_state` recovery deliberately skips it — it clears a half-finished flow to retry it, and an authorization that never completed has no grant to revoke. Client authentication resolves the preregistered slot first, mirroring BaseOAuthClientProvider.clientInformation; reading only the dynamic slot would send no authentication for a server configured with `oauth.clientId`. The Basic credential is byte-identical to the SDK's applyBasicAuth so this request and the token request cannot present the same secret differently. Opt out per server with `oauth.revokeOnClear` (default on, only `false` written to disk) or per CLI run with --no-revoke. Read at clear time rather than connect time, so toggling needs no reconnect. Turning it off is a testing affordance: a client that walks away still holding live tokens is a case a server author may want to reproduce. test-servers now advertises `revocation_endpoint` and serves POST /oauth/revoke, faithful on §2.2 (an unknown token is a success) and §2.1 (revoking a refresh token invalidates the access tokens under the same grant), with oauth-revocation-http.json / oauth-no-revocation-http.json as showcase configs. 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>
155 lines
3.7 KiB
TypeScript
155 lines
3.7 KiB
TypeScript
// Types
|
|
export type {
|
|
OAuthStep,
|
|
AuthProtocol,
|
|
OAuthClientRegistrationKind,
|
|
MessageType,
|
|
StatusMessage,
|
|
OAuthFlowState,
|
|
OAuthConnectionState,
|
|
CallbackParams,
|
|
} from "./types.js";
|
|
export {
|
|
EMPTY_OAUTH_FLOW_STATE,
|
|
authProtocolFromEnterpriseManaged,
|
|
} from "./types.js";
|
|
|
|
export {
|
|
buildOAuthConnectionState,
|
|
hasPersistedOAuthServerState,
|
|
isServerOAuthConfigured,
|
|
protocolFromOAuthConfig,
|
|
} from "./connection-state.js";
|
|
export type { BuildOAuthConnectionStateParams } from "./connection-state.js";
|
|
|
|
export { ensureCimdClientRegistration } from "./cimd.js";
|
|
|
|
export { mcpAuth, type McpAuthOptions, type McpAuthResult } from "./mcpAuth.js";
|
|
export { computeScopeUnion, isStrictScopeSuperset } from "./scopes.js";
|
|
|
|
// Custom authorization-request parameters (#2018)
|
|
export {
|
|
RESERVED_AUTHORIZATION_PARAMS,
|
|
isReservedAuthorizationParam,
|
|
authorizationParamKeyError,
|
|
applyAuthorizationParams,
|
|
} from "./authorizationParams.js";
|
|
export type { ReservedAuthorizationParam } from "./authorizationParams.js";
|
|
|
|
// Authorization/token endpoint overrides (#1906)
|
|
export {
|
|
oauthEndpointUrlError,
|
|
normalizeOAuthEndpointOverrides,
|
|
isAuthorizationServerMetadata,
|
|
applyOAuthEndpointOverrides,
|
|
withOAuthEndpointOverrides,
|
|
} from "./endpointOverrides.js";
|
|
export type { OAuthEndpointOverrides } from "./endpointOverrides.js";
|
|
|
|
// Storage
|
|
export type {
|
|
OAuthStorage,
|
|
IdpSessionState,
|
|
SaveClientInformationOptions,
|
|
} from "./storage.js";
|
|
export { getServerSpecificKey, OAUTH_STORAGE_KEYS } from "./storage.js";
|
|
|
|
// Providers
|
|
export type {
|
|
OAuthProviderConfig,
|
|
RedirectUrlProvider,
|
|
OAuthNavigation,
|
|
OAuthNavigationCallback,
|
|
} from "./providers.js";
|
|
export {
|
|
MutableRedirectUrlProvider,
|
|
ConsoleNavigation,
|
|
CallbackNavigation,
|
|
BaseOAuthClientProvider,
|
|
} from "./providers.js";
|
|
|
|
// Utilities
|
|
export {
|
|
parseHttpUrl,
|
|
parseOAuthCallbackParams,
|
|
generateOAuthState,
|
|
parseOAuthState,
|
|
generateOAuthErrorDescription,
|
|
formatOAuthFailureDetail,
|
|
isUnauthorizedError,
|
|
} from "./utils.js";
|
|
|
|
export type {
|
|
AuthChallenge,
|
|
AuthChallengeReason,
|
|
AuthChallengeOutcome,
|
|
HandleAuthChallengeOptions,
|
|
ParseAuthChallengeContext,
|
|
WwwAuthenticateBearerParams,
|
|
} from "./challenge.js";
|
|
export {
|
|
AuthChallengeError,
|
|
AuthRecoveryRequiredError,
|
|
parseAuthChallengeFromError,
|
|
parseAuthChallengeFromResponse,
|
|
parseScopeString,
|
|
parseWwwAuthenticateBearer,
|
|
unionAuthorizationScopes,
|
|
isAuthChallengeError,
|
|
isConnectAuthRecoveryError,
|
|
findNestedAuthError,
|
|
EMA_STEP_UP_PENDING_URL,
|
|
} from "./challenge.js";
|
|
|
|
export {
|
|
isStandardOAuthStepUp,
|
|
isEmaStepUp,
|
|
isStepUpConfirmation,
|
|
stepUpConfirmMessage,
|
|
stepUpFollowUpMessage,
|
|
stepUpModalTitle,
|
|
stepUpAuthorizeActionLabel,
|
|
emaStepUpInProgressMessage,
|
|
emaStepUpSuccessMessage,
|
|
emaStepUpFailureMessage,
|
|
stepUpAdditionalScopes,
|
|
stepUpInsufficientScopeMessage,
|
|
oauthPreRedirectToastCopy,
|
|
isReAuthBannerReason,
|
|
reAuthBannerMessage,
|
|
lostAuthorizationStateTitle,
|
|
lostAuthorizationStateMessage,
|
|
lostAuthorizationStateActionLabel,
|
|
issuerMismatchTitle,
|
|
issuerMismatchMessage,
|
|
issuerBindingFailureCopy,
|
|
type OAuthInteractiveAuthKind,
|
|
} from "./oauthUx.js";
|
|
|
|
export {
|
|
findIssuerBindingFailure,
|
|
type IssuerBindingFailure,
|
|
} from "./issuerBinding.js";
|
|
|
|
// Discovery
|
|
export { discoverScopes } from "./discovery.js";
|
|
|
|
// RFC 7009 token revocation (#2144)
|
|
export {
|
|
DEFAULT_REVOCATION_TIMEOUT_MS,
|
|
buildRevocationRequest,
|
|
revocationAuthMethods,
|
|
revokeStoredOAuthTokens,
|
|
revokeToken,
|
|
selectRevocableToken,
|
|
} from "./revocation.js";
|
|
export type {
|
|
RevocationRequestParams,
|
|
RevokeStoredOAuthTokensParams,
|
|
RevokeTokenParams,
|
|
TokenRevocationOutcome,
|
|
TokenRevocationSkipReason,
|
|
} from "./revocation.js";
|
|
|
|
// Logging (re-exported from core/logging)
|
|
export { silentLogger } from "../logging/index.js";
|