Skip to content

Commit 76938c7

Browse files
committed
Claude-authored tests
1 parent 6a6dcba commit 76938c7

File tree

9 files changed

+1808
-1
lines changed

9 files changed

+1808
-1
lines changed

src/server/auth/clients.test.ts

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
import { OAuthRegisteredClientsStore } from './clients.js';
2+
import { OAuthClientInformationFull } from '../../shared/auth.js';
3+
4+
describe('OAuthRegisteredClientsStore', () => {
5+
// Create a mock implementation class for testing
6+
class MockClientStore implements OAuthRegisteredClientsStore {
7+
private clients: Record<string, OAuthClientInformationFull> = {};
8+
9+
async getClient(clientId: string): Promise<OAuthClientInformationFull | undefined> {
10+
const client = this.clients[clientId];
11+
12+
// Return undefined for non-existent client
13+
if (!client) return undefined;
14+
15+
// Check if client secret has expired
16+
if (client.client_secret &&
17+
client.client_secret_expires_at &&
18+
client.client_secret_expires_at < Math.floor(Date.now() / 1000)) {
19+
// If expired, retain client but remove the secret
20+
const { client_secret: _unused, ...clientWithoutSecret } = client;
21+
return clientWithoutSecret as OAuthClientInformationFull;
22+
}
23+
24+
return client;
25+
}
26+
27+
async registerClient(client: OAuthClientInformationFull): Promise<OAuthClientInformationFull> {
28+
this.clients[client.client_id] = { ...client };
29+
return client;
30+
}
31+
}
32+
33+
let mockStore: MockClientStore;
34+
35+
beforeEach(() => {
36+
mockStore = new MockClientStore();
37+
});
38+
39+
describe('getClient', () => {
40+
it('returns undefined for non-existent client', async () => {
41+
const result = await mockStore.getClient('non-existent-id');
42+
expect(result).toBeUndefined();
43+
});
44+
45+
it('returns client information for existing client', async () => {
46+
const mockClient: OAuthClientInformationFull = {
47+
client_id: 'test-client-123',
48+
client_secret: 'secret456',
49+
redirect_uris: ['https://example.com/callback']
50+
};
51+
52+
await mockStore.registerClient(mockClient);
53+
const result = await mockStore.getClient('test-client-123');
54+
55+
expect(result).toEqual(mockClient);
56+
});
57+
58+
it('handles expired client secrets correctly', async () => {
59+
const now = Math.floor(Date.now() / 1000);
60+
61+
// Client with expired secret (one hour in the past)
62+
const expiredClient: OAuthClientInformationFull = {
63+
client_id: 'expired-client',
64+
client_secret: 'expired-secret',
65+
client_secret_expires_at: now - 3600,
66+
redirect_uris: ['https://example.com/callback']
67+
};
68+
69+
await mockStore.registerClient(expiredClient);
70+
const result = await mockStore.getClient('expired-client');
71+
72+
// Expect client to be returned but without the secret
73+
expect(result).toBeDefined();
74+
expect(result!.client_id).toBe('expired-client');
75+
expect(result!.client_secret).toBeUndefined();
76+
});
77+
78+
it('keeps valid client secrets', async () => {
79+
const now = Math.floor(Date.now() / 1000);
80+
81+
// Client with valid secret (expires one hour in the future)
82+
const validClient: OAuthClientInformationFull = {
83+
client_id: 'valid-client',
84+
client_secret: 'valid-secret',
85+
client_secret_expires_at: now + 3600,
86+
redirect_uris: ['https://example.com/callback']
87+
};
88+
89+
await mockStore.registerClient(validClient);
90+
const result = await mockStore.getClient('valid-client');
91+
92+
// Secret should still be present
93+
expect(result?.client_secret).toBe('valid-secret');
94+
});
95+
});
96+
97+
describe('registerClient', () => {
98+
it('successfully registers a new client', async () => {
99+
const newClient: OAuthClientInformationFull = {
100+
client_id: 'new-client-id',
101+
client_secret: 'new-client-secret',
102+
redirect_uris: ['https://example.com/callback']
103+
};
104+
105+
const result = await mockStore.registerClient(newClient);
106+
107+
// Verify registration returns the client
108+
expect(result).toEqual(newClient);
109+
110+
// Verify the client is retrievable
111+
const storedClient = await mockStore.getClient('new-client-id');
112+
expect(storedClient).toEqual(newClient);
113+
});
114+
115+
it('handles clients with all metadata fields', async () => {
116+
const fullClient: OAuthClientInformationFull = {
117+
client_id: 'full-client',
118+
client_secret: 'full-secret',
119+
client_id_issued_at: Math.floor(Date.now() / 1000),
120+
client_secret_expires_at: Math.floor(Date.now() / 1000) + 86400, // 24 hours
121+
redirect_uris: ['https://example.com/callback'],
122+
token_endpoint_auth_method: 'client_secret_basic',
123+
grant_types: ['authorization_code', 'refresh_token'],
124+
response_types: ['code'],
125+
client_name: 'Test Client',
126+
client_uri: 'https://example.com',
127+
logo_uri: 'https://example.com/logo.png',
128+
scope: 'profile email',
129+
contacts: ['[email protected]'],
130+
tos_uri: 'https://example.com/tos',
131+
policy_uri: 'https://example.com/privacy',
132+
jwks_uri: 'https://example.com/jwks',
133+
software_id: 'test-software',
134+
software_version: '1.0.0'
135+
};
136+
137+
await mockStore.registerClient(fullClient);
138+
const result = await mockStore.getClient('full-client');
139+
140+
expect(result).toEqual(fullClient);
141+
});
142+
});
143+
});

0 commit comments

Comments
 (0)