@@ -311,7 +311,7 @@ describe("Automatic skipLocalStorage Detection", () => {
311311 describe ( "Combined scenarios" , ( ) => {
312312 test ( "client-side: tokens persist in localStorage across page reloads" , async ( ) => {
313313 const manager1 = new OAuthManager ( "/api/integrate/oauth" ) ;
314-
314+
315315 const tokenData : ProviderTokenData = {
316316 accessToken : "persistent-token" ,
317317 tokenType : "Bearer" ,
@@ -414,7 +414,7 @@ describe("Automatic skipLocalStorage Detection", () => {
414414
415415 // Should call removeProviderToken callback
416416 expect ( removeTokenMock ) . toHaveBeenCalledWith ( "github" , undefined ) ;
417-
417+
418418 // Should be removed from database
419419 expect ( dbTokens [ "github" ] ) . toBeUndefined ( ) ;
420420
@@ -492,6 +492,57 @@ describe("Automatic skipLocalStorage Detection", () => {
492492 const allTokens = manager . getAllProviderTokens ( ) ;
493493 expect ( allTokens . get ( "github" ) ) . toEqual ( newToken ) ;
494494 } ) ;
495+
496+ test ( "pending auths are always cleaned up even with database callbacks" , async ( ) => {
497+ const setTokenMock = mock ( async ( provider : string , tokenData : ProviderTokenData ) => {
498+ // Simulate database save
499+ } ) ;
500+
501+ const manager = new OAuthManager (
502+ "/api/integrate/oauth" ,
503+ undefined ,
504+ undefined ,
505+ {
506+ setProviderToken : setTokenMock ,
507+ }
508+ ) ;
509+
510+ // Simulate OAuth flow: create pending auth
511+ const state = "test-state-123" ;
512+ const pendingAuth = {
513+ provider : "github" ,
514+ state,
515+ codeVerifier : "verifier" ,
516+ codeChallenge : "challenge" ,
517+ redirectUri : "http://localhost/callback" ,
518+ returnUrl : undefined ,
519+ initiatedAt : Date . now ( ) ,
520+ } ;
521+
522+ // Save pending auth to memory and localStorage (simulating initiateFlow)
523+ ( manager as any ) . pendingAuths . set ( state , pendingAuth ) ;
524+ const pendingKey = `integrate_oauth_pending_${ state } ` ;
525+ mockLocalStorage . set ( pendingKey , JSON . stringify ( pendingAuth ) ) ;
526+ expect ( mockLocalStorage . has ( pendingKey ) ) . toBe ( true ) ;
527+
528+ // Simulate callback completion with token (backend redirect flow)
529+ const tokenData : ProviderTokenData = {
530+ accessToken : "db-token" ,
531+ tokenType : "Bearer" ,
532+ expiresIn : 3600 ,
533+ } ;
534+
535+ await manager . handleCallbackWithToken ( "code" , state , { ...tokenData , provider : "github" } ) ;
536+
537+ // Pending auth should be removed from localStorage even though we're using database for tokens
538+ expect ( mockLocalStorage . has ( pendingKey ) ) . toBe ( false ) ;
539+
540+ // Token should NOT be in localStorage (goes to database instead)
541+ expect ( mockLocalStorage . has ( "integrate_token_github" ) ) . toBe ( false ) ;
542+
543+ // But token should be saved via callback
544+ expect ( setTokenMock ) . toHaveBeenCalledWith ( "github" , tokenData , undefined ) ;
545+ } ) ;
495546 } ) ;
496547} ) ;
497548
0 commit comments