@@ -7,6 +7,7 @@ import supertest from 'supertest';
7
7
import * as pkceChallenge from 'pkce-challenge' ;
8
8
import { InvalidGrantError , InvalidTokenError } from '../errors.js' ;
9
9
import { AuthInfo } from '../types.js' ;
10
+ import { ProxyOAuthServerProvider } from '../proxyProvider.js' ;
10
11
11
12
// Mock pkce-challenge
12
13
jest . mock ( 'pkce-challenge' , ( ) => ( {
@@ -280,6 +281,66 @@ describe('Token Handler', () => {
280
281
expect ( response . body . expires_in ) . toBe ( 3600 ) ;
281
282
expect ( response . body . refresh_token ) . toBe ( 'mock_refresh_token' ) ;
282
283
} ) ;
284
+
285
+ it ( 'passes through PKCE verification for proxy providers' , async ( ) => {
286
+ const originalFetch = global . fetch ;
287
+
288
+ try {
289
+ global . fetch = jest . fn ( ) . mockResolvedValue ( {
290
+ ok : true ,
291
+ json : ( ) => Promise . resolve ( {
292
+ access_token : 'mock_access_token' ,
293
+ token_type : 'bearer' ,
294
+ expires_in : 3600 ,
295
+ refresh_token : 'mock_refresh_token'
296
+ } )
297
+ } ) ;
298
+
299
+ const proxyProvider = new ProxyOAuthServerProvider ( {
300
+ endpoints : {
301
+ tokenUrl : 'https://example.com/token'
302
+ } ,
303
+ verifyToken : async ( token ) => ( {
304
+ token,
305
+ clientId : 'valid-client' ,
306
+ scopes : [ 'read' , 'write' ] ,
307
+ expiresAt : Date . now ( ) / 1000 + 3600
308
+ } ) ,
309
+ getClient : async ( clientId ) => clientId === 'valid-client' ? validClient : undefined
310
+ } ) ;
311
+
312
+ const proxyApp = express ( ) ;
313
+ const options : TokenHandlerOptions = { provider : proxyProvider } ;
314
+ proxyApp . use ( '/token' , tokenHandler ( options ) ) ;
315
+
316
+ const response = await supertest ( proxyApp )
317
+ . post ( '/token' )
318
+ . type ( 'form' )
319
+ . send ( {
320
+ client_id : 'valid-client' ,
321
+ client_secret : 'valid-secret' ,
322
+ grant_type : 'authorization_code' ,
323
+ code : 'valid_code' ,
324
+ code_verifier : 'any_verifier'
325
+ } ) ;
326
+
327
+ expect ( response . status ) . toBe ( 200 ) ;
328
+ expect ( response . body . access_token ) . toBe ( 'mock_access_token' ) ;
329
+
330
+ expect ( global . fetch ) . toHaveBeenCalledWith (
331
+ 'https://example.com/token' ,
332
+ expect . objectContaining ( {
333
+ method : 'POST' ,
334
+ headers : {
335
+ 'Content-Type' : 'application/x-www-form-urlencoded'
336
+ } ,
337
+ body : expect . stringContaining ( 'code_verifier=any_verifier' )
338
+ } )
339
+ ) ;
340
+ } finally {
341
+ global . fetch = originalFetch ;
342
+ }
343
+ } ) ;
283
344
} ) ;
284
345
285
346
describe ( 'Refresh token grant' , ( ) => {
0 commit comments