Skip to content

Commit fde7fc4

Browse files
Using lastUpscopingHeader to track last upscoping header to prevent infinite upscoping.
1 parent 38bab6b commit fde7fc4

File tree

2 files changed

+8
-6
lines changed

2 files changed

+8
-6
lines changed

src/client/auth.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ async function authInternal(
348348
): Promise<AuthResult> {
349349
let resourceMetadata: OAuthProtectedResourceMetadata | undefined;
350350
let authorizationServerUrl: string | URL | undefined;
351-
351+
352352
try {
353353
resourceMetadata = await discoverOAuthProtectedResourceMetadata(serverUrl, { resourceMetadataUrl }, fetchFn);
354354
if (resourceMetadata.authorization_servers && resourceMetadata.authorization_servers.length > 0) {

src/client/streamableHttp.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ export class StreamableHTTPClientTransport implements Transport {
133133
private _reconnectionOptions: StreamableHTTPReconnectionOptions;
134134
private _protocolVersion?: string;
135135
private _hasCompletedAuthFlow = false; // Circuit breaker: detect auth success followed by immediate 401
136-
private _hasTriedUpscoping = false; // Circuit breaker: detect upscoping attempt followed by immediate 403
136+
private _lastUpscopingHeader?: string; // Track last upscoping header to prevent infinite upscoping.
137137

138138
onclose?: () => void;
139139
onerror?: (error: Error) => void;
@@ -469,8 +469,10 @@ export class StreamableHTTPClientTransport implements Transport {
469469
const error = extractFieldFromWwwAuth(response, 'error');
470470

471471
if (error === 'insufficient_scope') {
472-
// Prevent infinite recursion when upscoping was already tried.
473-
if (this._hasTriedUpscoping) {
472+
const wwwAuthHeader = response.headers.get('WWW-Authenticate');
473+
474+
// Check if we've already tried upscoping with this header to prevent infinite loops.
475+
if (this._lastUpscopingHeader === wwwAuthHeader) {
474476
throw new StreamableHTTPError(403, 'Server returned 403 after trying upscoping');
475477
}
476478

@@ -485,7 +487,7 @@ export class StreamableHTTPClientTransport implements Transport {
485487
}
486488

487489
// Mark that upscoping was tried.
488-
this._hasTriedUpscoping = true;
490+
this._lastUpscopingHeader = wwwAuthHeader ?? undefined;
489491
const result = await auth(this._authProvider, {
490492
serverUrl: this._url,
491493
resourceMetadataUrl: this._resourceMetadataUrl,
@@ -507,7 +509,7 @@ export class StreamableHTTPClientTransport implements Transport {
507509

508510
// Reset auth loop flag on successful response
509511
this._hasCompletedAuthFlow = false;
510-
this._hasTriedUpscoping = false;
512+
this._lastUpscopingHeader = undefined;
511513

512514
// If the response is 202 Accepted, there's no body to process
513515
if (response.status === 202) {

0 commit comments

Comments
 (0)