fix: Support WWW-Authenticate scope param for SEP-835 (#983)
Co-authored-by: OtotheA <oscar@otothea.com>
This commit is contained in:
parent
216604720b
commit
ee9fed28cc
1 changed files with 118 additions and 74 deletions
|
|
@ -7,14 +7,14 @@ jest.mock('../client/auth.js', () => {
|
|||
return {
|
||||
...actual,
|
||||
auth: jest.fn(),
|
||||
extractResourceMetadataUrl: jest.fn()
|
||||
extractWWWAuthenticateParams: jest.fn()
|
||||
};
|
||||
});
|
||||
|
||||
import { auth, extractResourceMetadataUrl } from './auth.js';
|
||||
import { auth, extractWWWAuthenticateParams } from './auth.js';
|
||||
|
||||
const mockAuth = auth as jest.MockedFunction<typeof auth>;
|
||||
const mockExtractResourceMetadataUrl = extractResourceMetadataUrl as jest.MockedFunction<typeof extractResourceMetadataUrl>;
|
||||
const mockExtractWWWAuthenticateParams = extractWWWAuthenticateParams as jest.MockedFunction<typeof extractWWWAuthenticateParams>;
|
||||
|
||||
describe('withOAuth', () => {
|
||||
let mockProvider: jest.Mocked<OAuthClientProvider>;
|
||||
|
|
@ -129,8 +129,11 @@ describe('withOAuth', () => {
|
|||
|
||||
mockFetch.mockResolvedValueOnce(unauthorizedResponse).mockResolvedValueOnce(successResponse);
|
||||
|
||||
const mockResourceUrl = new URL('https://oauth.example.com/.well-known/oauth-protected-resource');
|
||||
mockExtractResourceMetadataUrl.mockReturnValue(mockResourceUrl);
|
||||
const mockWWWAuthenticateParams = {
|
||||
resourceMetadataUrl: new URL('https://oauth.example.com/.well-known/oauth-protected-resource'),
|
||||
scope: 'read'
|
||||
};
|
||||
mockExtractWWWAuthenticateParams.mockReturnValue(mockWWWAuthenticateParams);
|
||||
mockAuth.mockResolvedValue('AUTHORIZED');
|
||||
|
||||
const enhancedFetch = withOAuth(mockProvider, 'https://api.example.com')(mockFetch);
|
||||
|
|
@ -141,7 +144,8 @@ describe('withOAuth', () => {
|
|||
expect(mockFetch).toHaveBeenCalledTimes(2);
|
||||
expect(mockAuth).toHaveBeenCalledWith(mockProvider, {
|
||||
serverUrl: 'https://api.example.com',
|
||||
resourceMetadataUrl: mockResourceUrl,
|
||||
resourceMetadataUrl: mockWWWAuthenticateParams.resourceMetadataUrl,
|
||||
scope: mockWWWAuthenticateParams.scope,
|
||||
fetchFn: mockFetch
|
||||
});
|
||||
|
||||
|
|
@ -172,8 +176,11 @@ describe('withOAuth', () => {
|
|||
|
||||
mockFetch.mockResolvedValueOnce(unauthorizedResponse).mockResolvedValueOnce(successResponse);
|
||||
|
||||
const mockResourceUrl = new URL('https://oauth.example.com/.well-known/oauth-protected-resource');
|
||||
mockExtractResourceMetadataUrl.mockReturnValue(mockResourceUrl);
|
||||
const mockWWWAuthenticateParams = {
|
||||
resourceMetadataUrl: new URL('https://oauth.example.com/.well-known/oauth-protected-resource'),
|
||||
scope: 'read'
|
||||
};
|
||||
mockExtractWWWAuthenticateParams.mockReturnValue(mockWWWAuthenticateParams);
|
||||
mockAuth.mockResolvedValue('AUTHORIZED');
|
||||
|
||||
// Test without baseUrl - should extract from request URL
|
||||
|
|
@ -185,7 +192,8 @@ describe('withOAuth', () => {
|
|||
expect(mockFetch).toHaveBeenCalledTimes(2);
|
||||
expect(mockAuth).toHaveBeenCalledWith(mockProvider, {
|
||||
serverUrl: 'https://api.example.com', // Should be extracted from request URL
|
||||
resourceMetadataUrl: mockResourceUrl,
|
||||
resourceMetadataUrl: mockWWWAuthenticateParams.resourceMetadataUrl,
|
||||
scope: mockWWWAuthenticateParams.scope,
|
||||
fetchFn: mockFetch
|
||||
});
|
||||
|
||||
|
|
@ -203,7 +211,7 @@ describe('withOAuth', () => {
|
|||
});
|
||||
|
||||
mockFetch.mockResolvedValue(new Response('Unauthorized', { status: 401 }));
|
||||
mockExtractResourceMetadataUrl.mockReturnValue(undefined);
|
||||
mockExtractWWWAuthenticateParams.mockReturnValue({});
|
||||
mockAuth.mockResolvedValue('REDIRECT');
|
||||
|
||||
// Test without baseUrl
|
||||
|
|
@ -222,7 +230,7 @@ describe('withOAuth', () => {
|
|||
});
|
||||
|
||||
mockFetch.mockResolvedValue(new Response('Unauthorized', { status: 401 }));
|
||||
mockExtractResourceMetadataUrl.mockReturnValue(undefined);
|
||||
mockExtractWWWAuthenticateParams.mockReturnValue({});
|
||||
mockAuth.mockRejectedValue(new Error('Network error'));
|
||||
|
||||
const enhancedFetch = withOAuth(mockProvider, 'https://api.example.com')(mockFetch);
|
||||
|
|
@ -239,7 +247,7 @@ describe('withOAuth', () => {
|
|||
|
||||
// Always return 401
|
||||
mockFetch.mockResolvedValue(new Response('Unauthorized', { status: 401 }));
|
||||
mockExtractResourceMetadataUrl.mockReturnValue(undefined);
|
||||
mockExtractWWWAuthenticateParams.mockReturnValue({});
|
||||
mockAuth.mockResolvedValue('AUTHORIZED');
|
||||
|
||||
const enhancedFetch = withOAuth(mockProvider, 'https://api.example.com')(mockFetch);
|
||||
|
|
@ -345,7 +353,7 @@ describe('withOAuth', () => {
|
|||
|
||||
mockFetch.mockResolvedValueOnce(unauthorizedResponse).mockResolvedValueOnce(successResponse);
|
||||
|
||||
mockExtractResourceMetadataUrl.mockReturnValue(undefined);
|
||||
mockExtractWWWAuthenticateParams.mockReturnValue({});
|
||||
mockAuth.mockResolvedValue('AUTHORIZED');
|
||||
|
||||
const enhancedFetch = withOAuth(mockProvider)(mockFetch);
|
||||
|
|
@ -876,7 +884,10 @@ describe('Integration Tests', () => {
|
|||
|
||||
mockFetch.mockResolvedValueOnce(unauthorizedResponse).mockResolvedValueOnce(successResponse);
|
||||
|
||||
mockExtractResourceMetadataUrl.mockReturnValue(new URL('https://auth.example.com/.well-known/oauth-protected-resource'));
|
||||
mockExtractWWWAuthenticateParams.mockReturnValue({
|
||||
resourceMetadataUrl: new URL('https://auth.example.com/.well-known/oauth-protected-resource'),
|
||||
scope: 'read'
|
||||
});
|
||||
mockAuth.mockResolvedValue('AUTHORIZED');
|
||||
|
||||
// Use custom logger to avoid console output
|
||||
|
|
@ -896,6 +907,7 @@ describe('Integration Tests', () => {
|
|||
expect(mockAuth).toHaveBeenCalledWith(mockProvider, {
|
||||
serverUrl: 'https://mcp-server.example.com',
|
||||
resourceMetadataUrl: new URL('https://auth.example.com/.well-known/oauth-protected-resource'),
|
||||
scope: 'read',
|
||||
fetchFn: mockFetch
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue