Only use path-based discovery URLs from the authorization server to discover metadata (#1070)

This commit is contained in:
Vinay Dandekar 2025-11-03 09:52:33 -05:00 • committed by GitHub
commit 664e66e575
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 11 additions and 21 deletions

View file

@ -712,16 +712,12 @@ describe('OAuth Authorization', () => {
it('generates correct URLs for server with path', () => {
const urls = buildDiscoveryUrls('https://auth.example.com/tenant1');
expect(urls).toHaveLength(4);
expect(urls).toHaveLength(3);
expect(urls.map(u => ({ url: u.url.toString(), type: u.type }))).toEqual([
{
url: 'https://auth.example.com/.well-known/oauth-authorization-server/tenant1',
type: 'oauth'
},
{
url: 'https://auth.example.com/.well-known/oauth-authorization-server',
type: 'oauth'
},
{
url: 'https://auth.example.com/.well-known/openid-configuration/tenant1',
type: 'oidc'
@ -736,7 +732,7 @@ describe('OAuth Authorization', () => {
it('handles URL object input', () => {
const urls = buildDiscoveryUrls(new URL('https://auth.example.com/tenant1'));
expect(urls).toHaveLength(4);
expect(urls).toHaveLength(3);
expect(urls[0].url.toString()).toBe('https://auth.example.com/.well-known/oauth-authorization-server/tenant1');
});
});
@ -763,28 +759,28 @@ describe('OAuth Authorization', () => {
};
it('tries URLs in order and returns first successful metadata', async () => {
// First OAuth URL fails with 404
// First OAuth URL (path before well-known) fails with 404
mockFetch.mockResolvedValueOnce({
ok: false,
status: 404
});
// Second OAuth URL (root) succeeds
// Second OIDC URL (path before well-known) succeeds
mockFetch.mockResolvedValueOnce({
ok: true,
status: 200,
json: async () => validOAuthMetadata
json: async () => validOpenIdMetadata
});
const metadata = await discoverAuthorizationServerMetadata('https://auth.example.com/tenant1');
expect(metadata).toEqual(validOAuthMetadata);
expect(metadata).toEqual(validOpenIdMetadata);
// Verify it tried the URLs in the correct order
const calls = mockFetch.mock.calls;
expect(calls.length).toBe(2);
expect(calls[0][0].toString()).toBe('https://auth.example.com/.well-known/oauth-authorization-server/tenant1');
expect(calls[1][0].toString()).toBe('https://auth.example.com/.well-known/oauth-authorization-server');
expect(calls[1][0].toString()).toBe('https://auth.example.com/.well-known/openid-configuration/tenant1');
});
it('continues on 4xx errors', async () => {
@ -878,7 +874,7 @@ describe('OAuth Authorization', () => {
expect(metadata).toBeUndefined();
// Verify that all discovery URLs were attempted
expect(mockFetch).toHaveBeenCalledTimes(8); // 4 URLs × 2 attempts each (with and without headers)
expect(mockFetch).toHaveBeenCalledTimes(6); // 3 URLs × 2 attempts each (with and without headers)
});
});

View file

@ -669,8 +669,7 @@ export async function discoverOAuthMetadata(
* Builds a list of discovery URLs to try for authorization server metadata.
* URLs are returned in priority order:
* 1. OAuth metadata at the given URL
* 2. OAuth metadata at root (if URL has path)
* 3. OIDC metadata endpoints
* 2. OIDC metadata endpoints at the given URL
*/
export function buildDiscoveryUrls(authorizationServerUrl: string | URL): { url: URL; type: 'oauth' | 'oidc' }[] {
const url = typeof authorizationServerUrl === 'string' ? new URL(authorizationServerUrl) : authorizationServerUrl;
@ -706,18 +705,13 @@ export function buildDiscoveryUrls(authorizationServerUrl: string | URL): { url:
type: 'oauth'
});
// Root path: https://example.com/.well-known/oauth-authorization-server
urlsToTry.push({
url: new URL('/.well-known/oauth-authorization-server', url.origin),
type: 'oauth'
});
// 3. OIDC metadata endpoints
// 2. OIDC metadata endpoints
// RFC 8414 style: Insert /.well-known/openid-configuration before the path
urlsToTry.push({
url: new URL(`/.well-known/openid-configuration${pathname}`, url.origin),
type: 'oidc'
});
// OIDC Discovery 1.0 style: Append /.well-known/openid-configuration after the path
urlsToTry.push({
url: new URL(`${pathname}/.well-known/openid-configuration`, url.origin),