Skip to content

Commit d4a0b41

Browse files
whoiskatrinthreepointone
authored andcommitted
tests cleanup
1 parent 6366702 commit d4a0b41

File tree

1 file changed

+168
-168
lines changed

1 file changed

+168
-168
lines changed

__tests__/oauth-provider.test.ts

Lines changed: 168 additions & 168 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,135 @@ describe('OAuthProvider', () => {
198198
mockEnv.OAUTH_KV.clear();
199199
});
200200

201+
describe('API Route Configuration', () => {
202+
it('should support multi-handler configuration with apiHandlers', async () => {
203+
// Create handler classes for different API routes
204+
class UsersApiHandler extends WorkerEntrypoint {
205+
fetch(request: Request) {
206+
return new Response('Users API response', { status: 200 });
207+
}
208+
}
209+
210+
class DocumentsApiHandler extends WorkerEntrypoint {
211+
fetch(request: Request) {
212+
return new Response('Documents API response', { status: 200 });
213+
}
214+
}
215+
216+
// Create provider with multi-handler configuration
217+
const providerWithMultiHandler = new OAuthProvider({
218+
apiHandlers: {
219+
'/api/users/': UsersApiHandler,
220+
'/api/documents/': DocumentsApiHandler,
221+
},
222+
defaultHandler: testDefaultHandler,
223+
authorizeEndpoint: '/authorize',
224+
tokenEndpoint: '/oauth/token',
225+
clientRegistrationEndpoint: '/oauth/register', // Important for registering clients in the test
226+
scopesSupported: ['read', 'write'],
227+
});
228+
229+
// Create a client and get an access token
230+
const clientData = {
231+
redirect_uris: ['https://client.example.com/callback'],
232+
client_name: 'Test Client',
233+
token_endpoint_auth_method: 'client_secret_basic',
234+
};
235+
236+
const registerRequest = createMockRequest(
237+
'https://example.com/oauth/register',
238+
'POST',
239+
{ 'Content-Type': 'application/json' },
240+
JSON.stringify(clientData)
241+
);
242+
243+
const registerResponse = await providerWithMultiHandler.fetch(registerRequest, mockEnv, mockCtx);
244+
const client = await registerResponse.json();
245+
const clientId = client.client_id;
246+
const clientSecret = client.client_secret;
247+
const redirectUri = 'https://client.example.com/callback';
248+
249+
// Get an auth code
250+
const authRequest = createMockRequest(
251+
`https://example.com/authorize?response_type=code&client_id=${clientId}` +
252+
`&redirect_uri=${encodeURIComponent(redirectUri)}` +
253+
`&scope=read%20write&state=xyz123`
254+
);
255+
256+
const authResponse = await providerWithMultiHandler.fetch(authRequest, mockEnv, mockCtx);
257+
const location = authResponse.headers.get('Location')!;
258+
const code = new URL(location).searchParams.get('code')!;
259+
260+
// Exchange for tokens
261+
const params = new URLSearchParams();
262+
params.append('grant_type', 'authorization_code');
263+
params.append('code', code);
264+
params.append('redirect_uri', redirectUri);
265+
params.append('client_id', clientId);
266+
params.append('client_secret', clientSecret);
267+
268+
const tokenRequest = createMockRequest(
269+
'https://example.com/oauth/token',
270+
'POST',
271+
{ 'Content-Type': 'application/x-www-form-urlencoded' },
272+
params.toString()
273+
);
274+
275+
const tokenResponse = await providerWithMultiHandler.fetch(tokenRequest, mockEnv, mockCtx);
276+
const tokens = await tokenResponse.json();
277+
const accessToken = tokens.access_token;
278+
279+
// Make requests to different API routes
280+
const usersApiRequest = createMockRequest('https://example.com/api/users/profile', 'GET', {
281+
Authorization: `Bearer ${accessToken}`,
282+
});
283+
284+
const documentsApiRequest = createMockRequest('https://example.com/api/documents/list', 'GET', {
285+
Authorization: `Bearer ${accessToken}`,
286+
});
287+
288+
// Request to Users API should be handled by UsersApiHandler
289+
const usersResponse = await providerWithMultiHandler.fetch(usersApiRequest, mockEnv, mockCtx);
290+
expect(usersResponse.status).toBe(200);
291+
expect(await usersResponse.text()).toBe('Users API response');
292+
293+
// Request to Documents API should be handled by DocumentsApiHandler
294+
const documentsResponse = await providerWithMultiHandler.fetch(documentsApiRequest, mockEnv, mockCtx);
295+
expect(documentsResponse.status).toBe(200);
296+
expect(await documentsResponse.text()).toBe('Documents API response');
297+
});
298+
299+
it('should throw an error when both single-handler and multi-handler configs are provided', () => {
300+
expect(() => {
301+
new OAuthProvider({
302+
apiRoute: '/api/',
303+
apiHandler: {
304+
fetch: () => Promise.resolve(new Response()),
305+
},
306+
apiHandlers: {
307+
'/api/users/': {
308+
fetch: () => Promise.resolve(new Response()),
309+
},
310+
},
311+
defaultHandler: testDefaultHandler,
312+
authorizeEndpoint: '/authorize',
313+
tokenEndpoint: '/oauth/token',
314+
});
315+
}).toThrow('Cannot use both apiRoute/apiHandler and apiHandlers');
316+
});
317+
318+
it('should throw an error when neither single-handler nor multi-handler config is provided', () => {
319+
expect(() => {
320+
new OAuthProvider({
321+
// Intentionally omitting apiRoute and apiHandler and apiHandlers
322+
defaultHandler: testDefaultHandler,
323+
authorizeEndpoint: '/authorize',
324+
tokenEndpoint: '/oauth/token',
325+
});
326+
}).toThrow('Must provide either apiRoute + apiHandler OR apiHandlers');
327+
});
328+
});
329+
201330
describe('OAuth Metadata Discovery', () => {
202331
it('should return correct metadata at .well-known/oauth-authorization-server', async () => {
203332
const request = createMockRequest('https://example.com/.well-known/oauth-authorization-server');
@@ -679,6 +808,44 @@ describe('OAuthProvider', () => {
679808
expect(error.error_description).toBe('redirect_uri is required when not using PKCE');
680809
});
681810

811+
it('should reject token exchange with code_verifier when PKCE was not used in authorization', async () => {
812+
// First get an auth code WITHOUT using PKCE
813+
const authRequest = createMockRequest(
814+
`https://example.com/authorize?response_type=code&client_id=${clientId}` +
815+
`&redirect_uri=${encodeURIComponent(redirectUri)}` +
816+
`&scope=read%20write&state=xyz123`
817+
);
818+
819+
const authResponse = await oauthProvider.fetch(authRequest, mockEnv, mockCtx);
820+
const location = authResponse.headers.get('Location')!;
821+
const url = new URL(location);
822+
const code = url.searchParams.get('code')!;
823+
824+
// Now exchange the code and incorrectly provide a code_verifier
825+
const params = new URLSearchParams();
826+
params.append('grant_type', 'authorization_code');
827+
params.append('code', code);
828+
params.append('redirect_uri', redirectUri);
829+
params.append('client_id', clientId);
830+
params.append('client_secret', clientSecret);
831+
params.append('code_verifier', 'some_random_verifier_that_wasnt_used_in_auth');
832+
833+
const tokenRequest = createMockRequest(
834+
'https://example.com/oauth/token',
835+
'POST',
836+
{ 'Content-Type': 'application/x-www-form-urlencoded' },
837+
params.toString()
838+
);
839+
840+
const tokenResponse = await oauthProvider.fetch(tokenRequest, mockEnv, mockCtx);
841+
842+
// Should fail because code_verifier is provided but PKCE wasn't used in authorization
843+
expect(tokenResponse.status).toBe(400);
844+
const error = await tokenResponse.json();
845+
expect(error.error).toBe('invalid_request');
846+
expect(error.error_description).toBe('code_verifier provided for a flow that did not use PKCE');
847+
});
848+
682849
// Helper function for PKCE tests
683850
function generateRandomString(length: number): string {
684851
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
@@ -746,44 +913,6 @@ describe('OAuthProvider', () => {
746913
expect(tokens.expires_in).toBe(3600);
747914
});
748915

749-
it('should reject token exchange with code_verifier when PKCE was not used in authorization', async () => {
750-
// First get an auth code WITHOUT using PKCE
751-
const authRequest = createMockRequest(
752-
`https://example.com/authorize?response_type=code&client_id=${clientId}` +
753-
`&redirect_uri=${encodeURIComponent(redirectUri)}` +
754-
`&scope=read%20write&state=xyz123`
755-
);
756-
757-
const authResponse = await oauthProvider.fetch(authRequest, mockEnv, mockCtx);
758-
const location = authResponse.headers.get('Location')!;
759-
const url = new URL(location);
760-
const code = url.searchParams.get('code')!;
761-
762-
// Now exchange the code and incorrectly provide a code_verifier
763-
const params = new URLSearchParams();
764-
params.append('grant_type', 'authorization_code');
765-
params.append('code', code);
766-
params.append('redirect_uri', redirectUri);
767-
params.append('client_id', clientId);
768-
params.append('client_secret', clientSecret);
769-
params.append('code_verifier', 'some_random_verifier_that_wasnt_used_in_auth');
770-
771-
const tokenRequest = createMockRequest(
772-
'https://example.com/oauth/token',
773-
'POST',
774-
{ 'Content-Type': 'application/x-www-form-urlencoded' },
775-
params.toString()
776-
);
777-
778-
const tokenResponse = await oauthProvider.fetch(tokenRequest, mockEnv, mockCtx);
779-
780-
// Should fail because code_verifier is provided but PKCE wasn't used in authorization
781-
expect(tokenResponse.status).toBe(400);
782-
const error = await tokenResponse.json();
783-
expect(error.error).toBe('invalid_request');
784-
expect(error.error_description).toBe('code_verifier provided for a flow that did not use PKCE');
785-
});
786-
787916
it('should accept the access token for API requests', async () => {
788917
// Get an auth code
789918
const authRequest = createMockRequest(
@@ -2137,135 +2266,6 @@ describe('OAuthProvider', () => {
21372266
});
21382267
});
21392268

2140-
describe('API Route Configuration', () => {
2141-
it('should support multi-handler configuration with apiHandlers', async () => {
2142-
// Create handler classes for different API routes
2143-
class UsersApiHandler extends WorkerEntrypoint {
2144-
fetch(request: Request) {
2145-
return new Response('Users API response', { status: 200 });
2146-
}
2147-
}
2148-
2149-
class DocumentsApiHandler extends WorkerEntrypoint {
2150-
fetch(request: Request) {
2151-
return new Response('Documents API response', { status: 200 });
2152-
}
2153-
}
2154-
2155-
// Create provider with multi-handler configuration
2156-
const providerWithMultiHandler = new OAuthProvider({
2157-
apiHandlers: {
2158-
'/api/users/': UsersApiHandler,
2159-
'/api/documents/': DocumentsApiHandler,
2160-
},
2161-
defaultHandler: testDefaultHandler,
2162-
authorizeEndpoint: '/authorize',
2163-
tokenEndpoint: '/oauth/token',
2164-
clientRegistrationEndpoint: '/oauth/register', // Important for registering clients in the test
2165-
scopesSupported: ['read', 'write'],
2166-
});
2167-
2168-
// Create a client and get an access token
2169-
const clientData = {
2170-
redirect_uris: ['https://client.example.com/callback'],
2171-
client_name: 'Test Client',
2172-
token_endpoint_auth_method: 'client_secret_basic',
2173-
};
2174-
2175-
const registerRequest = createMockRequest(
2176-
'https://example.com/oauth/register',
2177-
'POST',
2178-
{ 'Content-Type': 'application/json' },
2179-
JSON.stringify(clientData)
2180-
);
2181-
2182-
const registerResponse = await providerWithMultiHandler.fetch(registerRequest, mockEnv, mockCtx);
2183-
const client = await registerResponse.json();
2184-
const clientId = client.client_id;
2185-
const clientSecret = client.client_secret;
2186-
const redirectUri = 'https://client.example.com/callback';
2187-
2188-
// Get an auth code
2189-
const authRequest = createMockRequest(
2190-
`https://example.com/authorize?response_type=code&client_id=${clientId}` +
2191-
`&redirect_uri=${encodeURIComponent(redirectUri)}` +
2192-
`&scope=read%20write&state=xyz123`
2193-
);
2194-
2195-
const authResponse = await providerWithMultiHandler.fetch(authRequest, mockEnv, mockCtx);
2196-
const location = authResponse.headers.get('Location')!;
2197-
const code = new URL(location).searchParams.get('code')!;
2198-
2199-
// Exchange for tokens
2200-
const params = new URLSearchParams();
2201-
params.append('grant_type', 'authorization_code');
2202-
params.append('code', code);
2203-
params.append('redirect_uri', redirectUri);
2204-
params.append('client_id', clientId);
2205-
params.append('client_secret', clientSecret);
2206-
2207-
const tokenRequest = createMockRequest(
2208-
'https://example.com/oauth/token',
2209-
'POST',
2210-
{ 'Content-Type': 'application/x-www-form-urlencoded' },
2211-
params.toString()
2212-
);
2213-
2214-
const tokenResponse = await providerWithMultiHandler.fetch(tokenRequest, mockEnv, mockCtx);
2215-
const tokens = await tokenResponse.json();
2216-
const accessToken = tokens.access_token;
2217-
2218-
// Make requests to different API routes
2219-
const usersApiRequest = createMockRequest('https://example.com/api/users/profile', 'GET', {
2220-
Authorization: `Bearer ${accessToken}`,
2221-
});
2222-
2223-
const documentsApiRequest = createMockRequest('https://example.com/api/documents/list', 'GET', {
2224-
Authorization: `Bearer ${accessToken}`,
2225-
});
2226-
2227-
// Request to Users API should be handled by UsersApiHandler
2228-
const usersResponse = await providerWithMultiHandler.fetch(usersApiRequest, mockEnv, mockCtx);
2229-
expect(usersResponse.status).toBe(200);
2230-
expect(await usersResponse.text()).toBe('Users API response');
2231-
2232-
// Request to Documents API should be handled by DocumentsApiHandler
2233-
const documentsResponse = await providerWithMultiHandler.fetch(documentsApiRequest, mockEnv, mockCtx);
2234-
expect(documentsResponse.status).toBe(200);
2235-
expect(await documentsResponse.text()).toBe('Documents API response');
2236-
});
2237-
2238-
it('should throw an error when both single-handler and multi-handler configs are provided', () => {
2239-
expect(() => {
2240-
new OAuthProvider({
2241-
apiRoute: '/api/',
2242-
apiHandler: {
2243-
fetch: () => Promise.resolve(new Response()),
2244-
},
2245-
apiHandlers: {
2246-
'/api/users/': {
2247-
fetch: () => Promise.resolve(new Response()),
2248-
},
2249-
},
2250-
defaultHandler: testDefaultHandler,
2251-
authorizeEndpoint: '/authorize',
2252-
tokenEndpoint: '/oauth/token',
2253-
});
2254-
}).toThrow('Cannot use both apiRoute/apiHandler and apiHandlers');
2255-
});
2256-
2257-
it('should throw an error when neither single-handler nor multi-handler config is provided', () => {
2258-
expect(() => {
2259-
new OAuthProvider({
2260-
// Intentionally omitting apiRoute and apiHandler and apiHandlers
2261-
defaultHandler: testDefaultHandler,
2262-
authorizeEndpoint: '/authorize',
2263-
tokenEndpoint: '/oauth/token',
2264-
});
2265-
}).toThrow('Must provide either apiRoute + apiHandler OR apiHandlers');
2266-
});
2267-
});
2268-
22692269
describe('Token Revocation', () => {
22702270
let clientId: string;
22712271
let clientSecret: string;
@@ -2346,4 +2346,4 @@ describe('OAuthProvider', () => {
23462346
expect(apiResponse.status).toBe(401); // Token should no longer work
23472347
});
23482348
});
2349-
});
2349+
});

0 commit comments

Comments
 (0)