@@ -337,6 +337,22 @@ describe("Auth2Stamper", () => {
337337 } ) ;
338338
339339 describe ( "stamp()" , ( ) => {
340+ it ( "awaits maybeRefreshTokens() before building the OIDC stamp" , async ( ) => {
341+ const storage = makeStorage ( ) ;
342+ const stamper = new Auth2Stamper ( storage ) ;
343+
344+ await stamper . init ( ) ;
345+
346+ storage . load . mockResolvedValueOnce ( { keyPair : mockKeyPair , keyInfo : stamper . getKeyInfo ( ) ! } ) ;
347+ await stamper . setTokens ( { accessToken : "my-access-token" , idType : "Bearer" } ) ;
348+
349+ const maybeRefreshSpy = jest . spyOn ( stamper , "maybeRefreshTokens" ) . mockResolvedValue ( false ) ;
350+
351+ await stamper . stamp ( { type : "OIDC" , data : Buffer . from ( "payload" ) } ) ;
352+
353+ expect ( maybeRefreshSpy ) . toHaveBeenCalled ( ) ;
354+ } ) ;
355+
340356 it ( "throws before init()" , async ( ) => {
341357 const stamper = new Auth2Stamper ( makeStorage ( ) ) ;
342358
@@ -593,19 +609,8 @@ describe("Auth2Stamper", () => {
593609 } ) ;
594610
595611 describe ( "token refresh" , ( ) => {
596- it ( "triggers a background refresh when the token is near expiry " , async ( ) => {
612+ it ( "does not trigger refresh as a side effect of bearerToken access " , async ( ) => {
597613 const mockFetch = globalThis . fetch as jest . Mock ;
598- mockFetch . mockResolvedValueOnce ( {
599- ok : true ,
600- json : ( ) =>
601- Promise . resolve ( {
602- access_token : "new-access" ,
603- refresh_token : "new-refresh" ,
604- token_type : "Bearer" ,
605- expires_in : 3600 ,
606- } ) ,
607- } ) ;
608-
609614 const storage = makeStorage ( STORED_RECORD ) ;
610615 const stamper = new Auth2Stamper ( storage , {
611616 authApiBaseUrl : "https://auth.example.com" ,
@@ -614,84 +619,28 @@ describe("Auth2Stamper", () => {
614619 } ) ;
615620
616621 await stamper . init ( ) ;
617-
618- // Force the token to be near expiry.
619622 ( stamper as any ) . _tokenExpiresAt = Date . now ( ) - 1000 ;
620623 ( stamper as any ) . _refreshToken = "stored-refresh-token" ;
621624
622- // Access bearerToken to fire the background refresh.
623- stamper . bearerToken ;
624-
625- // Flush microtasks so the background refresh completes.
626- await new Promise ( resolve => setTimeout ( resolve , 0 ) ) ;
627-
628- expect ( mockFetch ) . toHaveBeenCalledWith (
629- "https://auth.example.com/oauth2/token" ,
630- expect . objectContaining ( { method : "POST" } ) ,
631- ) ;
632- expect ( stamper . bearerToken ) . toBe ( "Bearer new-access" ) ;
633- } ) ;
634-
635- it ( "does not refresh when no refreshConfig is provided" , async ( ) => {
636- const mockFetch = globalThis . fetch as jest . Mock ;
637-
638- const storage = makeStorage ( STORED_RECORD ) ;
639- const stamper = new Auth2Stamper ( storage ) ;
640-
641- await stamper . init ( ) ;
642-
643- ( stamper as any ) . _tokenExpiresAt = Date . now ( ) - 1000 ;
644-
645- // Access bearerToken to fire the background refresh.
646- stamper . bearerToken ;
647-
648- // Flush microtasks so the background refresh completes.
649- await new Promise ( resolve => setTimeout ( resolve , 0 ) ) ;
650-
625+ expect ( stamper . bearerToken ) . toBe ( "Bearer stored-access-token" ) ;
651626 expect ( mockFetch ) . not . toHaveBeenCalled ( ) ;
652627 } ) ;
653628
654- it ( "does not fire a second refresh while one is already in flight " , async ( ) => {
629+ it ( "does not trigger refresh as a side effect of auth2Token access " , async ( ) => {
655630 const mockFetch = globalThis . fetch as jest . Mock ;
656- // Slow refresh that we can control.
657- let resolveRefresh ! : ( ) => void ;
658- mockFetch . mockReturnValueOnce (
659- new Promise ( resolve => {
660- resolveRefresh = ( ) =>
661- resolve ( {
662- ok : true ,
663- json : ( ) =>
664- Promise . resolve ( {
665- access_token : "new" ,
666- refresh_token : "new-r" ,
667- token_type : "Bearer" ,
668- expires_in : 3600 ,
669- } ) ,
670- } ) ;
671- } ) ,
672- ) ;
673-
674631 const storage = makeStorage ( STORED_RECORD ) ;
675632 const stamper = new Auth2Stamper ( storage , {
676633 authApiBaseUrl : "https://auth.example.com" ,
677- clientId : "c " ,
678- redirectUri : "https://app.example.com/cb " ,
634+ clientId : "client-1 " ,
635+ redirectUri : "https://app.example.com/callback " ,
679636 } ) ;
680637
681638 await stamper . init ( ) ;
682-
683639 ( stamper as any ) . _tokenExpiresAt = Date . now ( ) - 1000 ;
684- ( stamper as any ) . _refreshToken = "r" ;
685-
686- // Trigger two concurrent getter accesses.
687- stamper . bearerToken ;
688- stamper . bearerToken ;
689-
690- resolveRefresh ( ) ;
691- await new Promise ( resolve => setTimeout ( resolve , 0 ) ) ;
640+ ( stamper as any ) . _refreshToken = "stored-refresh-token" ;
692641
693- // fetch should only have been called once despite two accesses.
694- expect ( mockFetch ) . toHaveBeenCalledTimes ( 1 ) ;
642+ expect ( stamper . auth2Token ?. sub ) . toBe ( "default-user" ) ;
643+ expect ( mockFetch ) . not . toHaveBeenCalled ( ) ;
695644 } ) ;
696645 } ) ;
697646} ) ;
0 commit comments