feat: add token refresh and rotation conformance scenarios #139
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Summary
Adds two new client auth conformance scenarios that test OAuth 2.1 refresh token behavior:
auth/token-refresh-basic— Tests that clients use therefresh_tokengrant to obtain a new access token when the current one expires (OAuth 2.1 §6). Server issues 2-second TTL access tokens + refresh token; client must detect 401, sendgrant_type=refresh_token, and use the new access token successfully.auth/token-refresh-rotation— Same flow but the server rotates the refresh token on each use (OAuth 2.1 §6.1). Client must store the new refresh token and not reuse the old one.Motivation
Multiple MCP client implementations have been reported as not handling token refresh reliably — leading to auth loops, death spirals, and excessive retry RPM when access tokens expire. These scenarios provide a concrete conformance check against the OAuth 2.1 refresh token spec.
Changes
token-refresh.tsTokenRefreshBasicScenarioandTokenRefreshRotationScenariocreateAuthServer.tsissueRefreshToken,rotateRefreshTokens,accessTokenExpiresIn,onRefreshTokenRequestoptions; fullgrant_type=refresh_tokenhandlercreateServer.tsperRequestServeroption (fresh MCP Server per request, needed becauseserver.close()on response end breaks subsequent requests across token boundaries)mockTokenVerifier.tsissuedAt,expiresInper token); expired tokens throwInvalidTokenErrorwith INFO conformance checkspec-references.tsOAUTH_2_1_REFRESH_TOKEN(§6) andOAUTH_2_1_TOKEN_ROTATION(§6.1)index.tseverything-client.tsrunTokenRefreshClientexercising the full refresh flowTest plan
auth/token-refresh-basicpasses in ~3s (2s token TTL + 1s buffer)auth/token-refresh-rotationpasses in ~3stsc --noEmitcleanDependencies
Depends on #138 (
InvalidTokenErrorfix) — without it, expired tokens return 500 instead of 401 and the refresh flow never triggers.Made with Cursor