@@ -2479,4 +2479,100 @@ describe('OAuthProvider', () => {
2479
2479
expect ( clientsAfterDelete . items . length ) . toBe ( 0 ) ;
2480
2480
} ) ;
2481
2481
} ) ;
2482
+
2483
+ describe ( 'Token Revocation' , ( ) => {
2484
+ let clientId : string ;
2485
+ let clientSecret : string ;
2486
+ let redirectUri : string ;
2487
+
2488
+ beforeEach ( async ( ) => {
2489
+ redirectUri = 'https://client.example.com/callback' ;
2490
+
2491
+ // Create a test client
2492
+ const clientResponse = await oauthProvider . fetch (
2493
+ createMockRequest (
2494
+ 'https://example.com/oauth/register' ,
2495
+ 'POST' ,
2496
+ {
2497
+ 'Content-Type' : 'application/json' ,
2498
+ } ,
2499
+ JSON . stringify ( {
2500
+ redirect_uris : [ redirectUri ] ,
2501
+ client_name : 'Test Client for Revocation' ,
2502
+ token_endpoint_auth_method : 'client_secret_basic' ,
2503
+ } )
2504
+ ) ,
2505
+ mockEnv ,
2506
+ mockCtx
2507
+ ) ;
2508
+
2509
+ expect ( clientResponse . status ) . toBe ( 201 ) ;
2510
+ const client = await clientResponse . json < any > ( ) ;
2511
+ clientId = client . client_id ;
2512
+ clientSecret = client . client_secret ;
2513
+ } ) ;
2514
+
2515
+ it ( 'should connect revokeGrant to token endpoint ' , async ( ) => {
2516
+ // Step 1: Get tokens through normal OAuth flow
2517
+ const authRequest = createMockRequest (
2518
+ `https://example.com/authorize?response_type=code&client_id=${ encodeURIComponent ( clientId ) } &redirect_uri=${ encodeURIComponent ( redirectUri ) } &scope=read&state=test-state`
2519
+ ) ;
2520
+ const authResponse = await oauthProvider . fetch ( authRequest , mockEnv , mockCtx ) ;
2521
+ const code = new URL ( authResponse . headers . get ( 'Location' ) ! ) . searchParams . get ( 'code' ) ;
2522
+
2523
+ const tokenRequest = createMockRequest (
2524
+ 'https://example.com/oauth/token' ,
2525
+ 'POST' ,
2526
+ {
2527
+ 'Content-Type' : 'application/x-www-form-urlencoded' ,
2528
+ Authorization : `Basic ${ btoa ( `${ clientId } :${ clientSecret } ` ) } ` ,
2529
+ } ,
2530
+ `grant_type=authorization_code&code=${ code } &redirect_uri=${ encodeURIComponent ( redirectUri ) } `
2531
+ ) ;
2532
+
2533
+ const tokenResponse = await oauthProvider . fetch ( tokenRequest , mockEnv , mockCtx ) ;
2534
+ expect ( tokenResponse . status ) . toBe ( 200 ) ;
2535
+ const tokens = await tokenResponse . json < any > ( ) ;
2536
+
2537
+ // Step 2:this should successfully revoke the token
2538
+ const revokeRequest = createMockRequest (
2539
+ 'https://example.com/oauth/token' ,
2540
+ 'POST' ,
2541
+ {
2542
+ 'Content-Type' : 'application/x-www-form-urlencoded' ,
2543
+ Authorization : `Basic ${ btoa ( `${ clientId } :${ clientSecret } ` ) } ` ,
2544
+ } ,
2545
+ `token=${ tokens . access_token } `
2546
+ ) ;
2547
+
2548
+ const revokeResponse = await oauthProvider . fetch ( revokeRequest , mockEnv , mockCtx ) ;
2549
+ // Verify response doesn't contain unsupported_grant_type error
2550
+ const revokeResponseText = await revokeResponse . text ( ) ;
2551
+ expect ( revokeResponseText ) . not . toContain ( 'unsupported_grant_type' ) ;
2552
+
2553
+ // Step 3: Verify the access token is actually revoked
2554
+ const apiRequest = createMockRequest ( 'https://example.com/api/test' , 'GET' , {
2555
+ Authorization : `Bearer ${ tokens . access_token } ` ,
2556
+ } ) ;
2557
+ const apiResponse = await oauthProvider . fetch ( apiRequest , mockEnv , mockCtx ) ;
2558
+ expect ( apiResponse . status ) . toBe ( 401 ) ; // Access token should no longer work
2559
+
2560
+ // Step 4: Verify refresh token still works
2561
+ const refreshRequest = createMockRequest (
2562
+ 'https://example.com/oauth/token' ,
2563
+ 'POST' ,
2564
+ {
2565
+ 'Content-Type' : 'application/x-www-form-urlencoded' ,
2566
+ Authorization : `Basic ${ btoa ( `${ clientId } :${ clientSecret } ` ) } ` ,
2567
+ } ,
2568
+ `grant_type=refresh_token&refresh_token=${ tokens . refresh_token } `
2569
+ ) ;
2570
+
2571
+ const refreshResponse = await oauthProvider . fetch ( refreshRequest , mockEnv , mockCtx ) ;
2572
+ expect ( refreshResponse . status ) . toBe ( 200 ) ; // Refresh token should still work
2573
+ const newTokens = await refreshResponse . json < any > ( ) ;
2574
+ expect ( newTokens . access_token ) . toBeDefined ( ) ;
2575
+ expect ( newTokens . refresh_token ) . toBeDefined ( ) ;
2576
+ } ) ;
2577
+ } ) ;
2482
2578
} ) ;
0 commit comments