Skip to content

Commit acf1ba4

Browse files
dsp-antclaude
andcommitted
test: Add tests for RequestInit passthrough to auth requests
Added comprehensive tests to verify that: - Custom headers (like user-agent) from RequestInit are passed to auth requests - Auth-specific headers override base headers when needed - All RequestInit options (credentials, mode, cache, etc.) are preserved All 553 tests pass. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 7d907b1 commit acf1ba4

File tree

1 file changed

+109
-0
lines changed

1 file changed

+109
-0
lines changed

src/client/auth.test.ts

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2558,4 +2558,113 @@ describe('OAuth Authorization', () => {
25582558
expect(body.get('refresh_token')).toBe('refresh123');
25592559
});
25602560
});
2561+
2562+
describe('RequestInit headers passthrough', () => {
2563+
it('custom headers from RequestInit are passed to auth discovery requests', async () => {
2564+
const { createFetchWithInit } = await import('../shared/transport.js');
2565+
2566+
const customFetch = jest.fn().mockResolvedValue({
2567+
ok: true,
2568+
status: 200,
2569+
json: async () => ({
2570+
resource: 'https://resource.example.com',
2571+
authorization_servers: ['https://auth.example.com']
2572+
})
2573+
});
2574+
2575+
// Create a wrapped fetch with custom headers
2576+
const wrappedFetch = createFetchWithInit(customFetch, {
2577+
headers: {
2578+
'user-agent': 'MyApp/1.0',
2579+
'x-custom-header': 'test-value'
2580+
}
2581+
});
2582+
2583+
await discoverOAuthProtectedResourceMetadata('https://resource.example.com', undefined, wrappedFetch);
2584+
2585+
expect(customFetch).toHaveBeenCalledTimes(1);
2586+
const [url, options] = customFetch.mock.calls[0];
2587+
2588+
expect(url.toString()).toBe('https://resource.example.com/.well-known/oauth-protected-resource');
2589+
expect(options.headers).toMatchObject({
2590+
'user-agent': 'MyApp/1.0',
2591+
'x-custom-header': 'test-value',
2592+
'MCP-Protocol-Version': LATEST_PROTOCOL_VERSION
2593+
});
2594+
});
2595+
2596+
it('auth-specific headers override base headers from RequestInit', async () => {
2597+
const { createFetchWithInit } = await import('../shared/transport.js');
2598+
2599+
const customFetch = jest.fn().mockResolvedValue({
2600+
ok: true,
2601+
status: 200,
2602+
json: async () => ({
2603+
issuer: 'https://auth.example.com',
2604+
authorization_endpoint: 'https://auth.example.com/authorize',
2605+
token_endpoint: 'https://auth.example.com/token',
2606+
response_types_supported: ['code'],
2607+
code_challenge_methods_supported: ['S256']
2608+
})
2609+
});
2610+
2611+
// Create a wrapped fetch with a custom Accept header
2612+
const wrappedFetch = createFetchWithInit(customFetch, {
2613+
headers: {
2614+
'Accept': 'text/plain',
2615+
'user-agent': 'MyApp/1.0'
2616+
}
2617+
});
2618+
2619+
await discoverAuthorizationServerMetadata('https://auth.example.com', {
2620+
fetchFn: wrappedFetch
2621+
});
2622+
2623+
expect(customFetch).toHaveBeenCalled();
2624+
const [url, options] = customFetch.mock.calls[0];
2625+
2626+
// Auth-specific Accept header should override base Accept header
2627+
expect(options.headers).toMatchObject({
2628+
'Accept': 'application/json', // Auth-specific value wins
2629+
'user-agent': 'MyApp/1.0', // Base value preserved
2630+
'MCP-Protocol-Version': LATEST_PROTOCOL_VERSION
2631+
});
2632+
});
2633+
2634+
it('other RequestInit options are passed through', async () => {
2635+
const { createFetchWithInit } = await import('../shared/transport.js');
2636+
2637+
const customFetch = jest.fn().mockResolvedValue({
2638+
ok: true,
2639+
status: 200,
2640+
json: async () => ({
2641+
resource: 'https://resource.example.com',
2642+
authorization_servers: ['https://auth.example.com']
2643+
})
2644+
});
2645+
2646+
// Create a wrapped fetch with various RequestInit options
2647+
const wrappedFetch = createFetchWithInit(customFetch, {
2648+
credentials: 'include',
2649+
mode: 'cors',
2650+
cache: 'no-cache',
2651+
headers: {
2652+
'user-agent': 'MyApp/1.0'
2653+
}
2654+
});
2655+
2656+
await discoverOAuthProtectedResourceMetadata('https://resource.example.com', undefined, wrappedFetch);
2657+
2658+
expect(customFetch).toHaveBeenCalledTimes(1);
2659+
const [url, options] = customFetch.mock.calls[0];
2660+
2661+
// All RequestInit options should be preserved
2662+
expect(options.credentials).toBe('include');
2663+
expect(options.mode).toBe('cors');
2664+
expect(options.cache).toBe('no-cache');
2665+
expect(options.headers).toMatchObject({
2666+
'user-agent': 'MyApp/1.0'
2667+
});
2668+
});
2669+
});
25612670
});

0 commit comments

Comments
 (0)