@@ -7,6 +7,7 @@ import supertest from 'supertest';
77import * as pkceChallenge from 'pkce-challenge' ;
88import { InvalidGrantError , InvalidTokenError } from '../errors.js' ;
99import { AuthInfo } from '../types.js' ;
10+ import { ProxyOAuthServerProvider } from '../proxyProvider.js' ;
1011
1112// Mock pkce-challenge
1213jest . mock ( 'pkce-challenge' , ( ) => ( {
@@ -280,6 +281,66 @@ describe('Token Handler', () => {
280281 expect ( response . body . expires_in ) . toBe ( 3600 ) ;
281282 expect ( response . body . refresh_token ) . toBe ( 'mock_refresh_token' ) ;
282283 } ) ;
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+ } ) ;
283344 } ) ;
284345
285346 describe ( 'Refresh token grant' , ( ) => {
0 commit comments