Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,8 @@ program
const result = await runAuthorizationServerConformanceTest(
validated.url,
scenarioName,
outputDir
outputDir,
specVersionFilter
);
allResults.push({ scenario: scenarioName, checks: result.checks });
} catch (error) {
Expand Down
7 changes: 4 additions & 3 deletions src/runner/authorization-server.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { promises as fs } from 'fs';
import path from 'path';
import { ConformanceCheck } from '../types';
import { ConformanceCheck, SpecVersion } from '../types';
import { getClientScenarioForAuthorizationServer } from '../scenarios';
import { createResultDir } from './utils';

export async function runAuthorizationServerConformanceTest(
serverUrl: string,
scenarioName: string,
outputDir?: string
outputDir?: string,
specVersion?: SpecVersion
): Promise<{
checks: ConformanceCheck[];
resultDir?: string;
Expand All @@ -31,7 +32,7 @@ export async function runAuthorizationServerConformanceTest(
`Running client scenario for authorization server '${scenarioName}' against server: ${serverUrl}`
);

const checks = await scenario.run(serverUrl);
const checks = await scenario.run(serverUrl, specVersion);

if (resultDir) {
await fs.writeFile(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,84 @@ describe('AuthorizationServerMetadataEndpointScenario', () => {
expect(check.status).toBe('FAILURE');
expect(check.errorMessage).toContain('code_challenge_methods_supported');
});

it('returns SUCCESS for CIMD check when server metadata includes client_id_metadata_document_supported=true with spec version 2025-11-25', async () => {
const scenario = new AuthorizationServerMetadataEndpointScenario();
mockMetadataResponse({
...validMetadata,
client_id_metadata_document_supported: true
});

const checks = await scenario.run(SERVER_URL, '2025-11-25');

expect(checks).toHaveLength(2);

const metadataCheck = checks[0];
expect(metadataCheck.status).toBe('SUCCESS');

const cimdCheck = checks[1];
expect(cimdCheck.id).toBe('authorization-server-metadata-cimd');
expect(cimdCheck.status).toBe('SUCCESS');
expect(cimdCheck.errorMessage).toBeUndefined();
expect(cimdCheck.details).toEqual({
client_id_metadata_document_supported: true
});
});

it('returns FAILURE for CIMD check when server metadata lacks client_id_metadata_document_supported with spec version 2025-11-25', async () => {
const scenario = new AuthorizationServerMetadataEndpointScenario();
mockMetadataResponse(validMetadata);

const checks = await scenario.run(SERVER_URL, '2025-11-25');

expect(checks).toHaveLength(2);

const metadataCheck = checks[0];
expect(metadataCheck.status).toBe('SUCCESS');

const cimdCheck = checks[1];
expect(cimdCheck.id).toBe('authorization-server-metadata-cimd');
expect(cimdCheck.status).toBe('FAILURE');
expect(cimdCheck.errorMessage).toContain(
'client_id_metadata_document_supported'
);
});

it('returns FAILURE for CIMD check when client_id_metadata_document_supported is false with spec version 2025-11-25', async () => {
const scenario = new AuthorizationServerMetadataEndpointScenario();
mockMetadataResponse({
...validMetadata,
client_id_metadata_document_supported: false
});

const checks = await scenario.run(SERVER_URL, '2025-11-25');

expect(checks).toHaveLength(2);

const metadataCheck = checks[0];
expect(metadataCheck.status).toBe('SUCCESS');

const cimdCheck = checks[1];
expect(cimdCheck.id).toBe('authorization-server-metadata-cimd');
expect(cimdCheck.status).toBe('FAILURE');
expect(cimdCheck.errorMessage).toContain(
'client_id_metadata_document_supported'
);
expect(cimdCheck.errorMessage).toContain('false');
});

it('does not add CIMD check when spec version is 2025-06-18 even if claim is false', async () => {
const scenario = new AuthorizationServerMetadataEndpointScenario();
mockMetadataResponse({
...validMetadata,
client_id_metadata_document_supported: false
});

const checks = await scenario.run(SERVER_URL, '2025-06-18');

expect(checks).toHaveLength(1);

const metadataCheck = checks[0];
expect(metadataCheck.status).toBe('SUCCESS');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,15 @@ export class AuthorizationServerMetadataEndpointScenario implements ClientScenar
- Return a JSON response including issuer, authorization_endpoint, token_endpoint and response_types_supported
- The issuer value MUST match the URI obtained by removing the well-known URI string from the authorization server metadata URI.`;

async run(serverUrl: string): Promise<ConformanceCheck[]> {
async run(
serverUrl: string,
specVersion?: SpecVersion
): Promise<ConformanceCheck[]> {
let status: Status = 'SUCCESS';
let errorMessage: string | undefined;
let details: any;
let response: any | null = null;
let body: Record<string, any> | undefined;
try {
const wellKnownUrls = this.createWellKnownUrl(serverUrl);

Expand All @@ -53,7 +57,7 @@ export class AuthorizationServerMetadataEndpointScenario implements ClientScenar

this.validateContentType(response.headers['content-type']);

const body = await this.parseJson(response);
body = await this.parseJson(response);
const errors: string[] = [];
this.validateMetadataBody(body, serverUrl, errors);

Expand All @@ -71,7 +75,7 @@ export class AuthorizationServerMetadataEndpointScenario implements ClientScenar
errorMessage = error instanceof Error ? error.message : String(error);
}

return [
const checks: ConformanceCheck[] = [
{
id: 'authorization-server-metadata',
name: 'AuthorizationServerMetadata',
Expand All @@ -88,6 +92,38 @@ export class AuthorizationServerMetadataEndpointScenario implements ClientScenar
...(details ? { details } : {})
}
];

if (specVersion === '2025-11-25' && body) {
const cimdSupported = body.client_id_metadata_document_supported;
const cimdStatus: Status = cimdSupported === true ? 'SUCCESS' : 'FAILURE';
const cimdErrorMessage =
cimdSupported === true
? undefined
: cimdSupported === undefined
? 'Authorization server metadata does not include "client_id_metadata_document_supported"'
: `Expected "client_id_metadata_document_supported" to be true, got ${JSON.stringify(cimdSupported)}`;

checks.push({
id: 'authorization-server-metadata-cimd',
name: 'AuthorizationServerMetadataCIMD',
description:
'Authorization server metadata includes client_id_metadata_document_supported=true',
status: cimdStatus,
timestamp: new Date().toISOString(),
errorMessage: cimdErrorMessage,
specReferences: [
{
id: 'IETF-OAuth-Client-ID-Metadata-Document',
url: 'https://www.ietf.org/archive/id/draft-ietf-oauth-client-id-metadata-document-01.html#name-authorization-server-metada'
}
],
details: {
client_id_metadata_document_supported: cimdSupported
}
});
}

return checks;
}

private createWellKnownUrl(serverUrl: string): string[] {
Expand Down
5 changes: 4 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,8 @@ export interface ClientScenarioForAuthorizationServer {
name: string;
description: string;
specVersions: SpecVersion[];
run(serverUrl: string): Promise<ConformanceCheck[]>;
run(
serverUrl: string,
specVersion?: SpecVersion
): Promise<ConformanceCheck[]>;
}
Loading