@@ -9,6 +9,7 @@ import type {
9
9
import { MongoDBOIDCError } from './types' ;
10
10
import {
11
11
errorString ,
12
+ getRefreshTokenId ,
12
13
messageFromError ,
13
14
normalizeObject ,
14
15
throwIfAborted ,
@@ -147,6 +148,7 @@ export function automaticRefreshTimeoutMS(
147
148
}
148
149
149
150
const kEnableFallback = Symbol . for ( '@@mdb.oidcplugin.kEnableFallback' ) ;
151
+ let updateIdCounter = 0 ;
150
152
151
153
function allowFallbackIfFailed < T > ( promise : Promise < T > ) : Promise < T > {
152
154
return promise . catch ( ( err ) => {
@@ -558,6 +560,9 @@ export class MongoDBOIDCPluginImpl implements MongoDBOIDCPlugin {
558
560
this . logger . emit ( 'mongodb-oidc-plugin:missing-id-token' ) ;
559
561
}
560
562
563
+ const refreshTokenId = getRefreshTokenId ( tokenSet . refresh_token ) ;
564
+ const updateId = updateIdCounter ++ ;
565
+
561
566
const timerDuration = automaticRefreshTimeoutMS ( tokenSet ) ;
562
567
// Use `.call()` because in browsers, `setTimeout()` requires that it is called
563
568
// without a `this` value. `.unref()` is not available in browsers either.
@@ -577,21 +582,38 @@ export class MongoDBOIDCPluginImpl implements MongoDBOIDCPlugin {
577
582
}
578
583
// Only refresh this token set if it is the one currently
579
584
// being used.
580
- if ( state . currentTokenSet ?. set !== tokenSet ) return false ;
585
+ if ( state . currentTokenSet ?. set !== tokenSet ) {
586
+ this . logger . emit ( 'mongodb-oidc-plugin:refresh-skipped' , {
587
+ triggeringUpdateId : updateId ,
588
+ expectedRefreshToken : refreshTokenId ,
589
+ actualRefreshToken : getRefreshTokenId (
590
+ state . currentTokenSet ?. set ?. refresh_token
591
+ ) ,
592
+ } ) ;
593
+ return false ;
594
+ }
581
595
try {
582
- this . logger . emit ( 'mongodb-oidc-plugin:refresh-started' ) ;
596
+ this . logger . emit ( 'mongodb-oidc-plugin:refresh-started' , {
597
+ triggeringUpdateId : updateId ,
598
+ refreshToken : refreshTokenId ,
599
+ } ) ;
583
600
584
601
const { client } = await this . getOIDCClient ( state ) ;
585
602
const refreshedTokens = await client . refresh ( tokenSet ) ;
586
603
// Check again to avoid race conditions.
587
604
if ( state . currentTokenSet ?. set === tokenSet ) {
588
- this . logger . emit ( 'mongodb-oidc-plugin:refresh-succeeded' ) ;
605
+ this . logger . emit ( 'mongodb-oidc-plugin:refresh-succeeded' , {
606
+ triggeringUpdateId : updateId ,
607
+ refreshToken : refreshTokenId ,
608
+ } ) ;
589
609
this . updateStateWithTokenSet ( state , refreshedTokens ) ;
590
610
return true ;
591
611
}
592
612
} catch ( err : unknown ) {
593
613
this . logger . emit ( 'mongodb-oidc-plugin:refresh-failed' , {
594
614
error : errorString ( err ) ,
615
+ triggeringUpdateId : updateId ,
616
+ refreshToken : refreshTokenId ,
595
617
} ) ;
596
618
}
597
619
return false ;
@@ -602,7 +624,10 @@ export class MongoDBOIDCPluginImpl implements MongoDBOIDCPlugin {
602
624
tryRefresh,
603
625
} ;
604
626
605
- this . logger . emit ( 'mongodb-oidc-plugin:state-updated' ) ;
627
+ this . logger . emit ( 'mongodb-oidc-plugin:state-updated' , {
628
+ updateId,
629
+ timerDuration,
630
+ } ) ;
606
631
}
607
632
608
633
static readonly defaultRedirectURI = 'http://localhost:27097/redirect' ;
@@ -667,6 +692,7 @@ export class MongoDBOIDCPluginImpl implements MongoDBOIDCPlugin {
667
692
new Promise < never > ( ( resolve , reject ) => {
668
693
this . openBrowser ( { url : localUrl , signal } )
669
694
. then ( ( browserHandle ) => {
695
+ this . logger . emit ( 'mongodb-oidc-plugin:open-browser-complete' ) ;
670
696
const extraErrorInfo = ( ) =>
671
697
browserHandle ?. spawnargs
672
698
? ` (${ JSON . stringify ( browserHandle . spawnargs ) } )`
@@ -697,11 +723,14 @@ export class MongoDBOIDCPluginImpl implements MongoDBOIDCPlugin {
697
723
const timeout : Promise < never > = allowFallbackIfFailed (
698
724
new Promise ( ( resolve , reject ) => {
699
725
if ( this . options . openBrowserTimeout !== 0 ) {
700
- setTimeout (
701
- reject ,
702
- this . options . openBrowserTimeout ?? kDefaultOpenBrowserTimeout ,
703
- new MongoDBOIDCError ( 'Opening browser timed out' )
704
- ) . unref ( ) ;
726
+ this . timers . setTimeout
727
+ . call (
728
+ null ,
729
+ ( ) =>
730
+ reject ( new MongoDBOIDCError ( 'Opening browser timed out' ) ) ,
731
+ this . options . openBrowserTimeout ?? kDefaultOpenBrowserTimeout
732
+ )
733
+ ?. unref ?.( ) ;
705
734
}
706
735
} )
707
736
) ;
@@ -777,6 +806,7 @@ export class MongoDBOIDCPluginImpl implements MongoDBOIDCPlugin {
777
806
} ;
778
807
this . options . signal ?. addEventListener ( 'abort' , optionsAbortCb ) ;
779
808
driverAbortSignal ?. addEventListener ( 'abort' , driverAbortCb ) ;
809
+ const { passIdTokenAsAccessToken } = this . options ;
780
810
const signal = combinedAbortController . signal ;
781
811
782
812
try {
@@ -831,7 +861,9 @@ export class MongoDBOIDCPluginImpl implements MongoDBOIDCPlugin {
831
861
if ( error ) throw error ;
832
862
}
833
863
834
- if ( ! state . currentTokenSet ?. set ?. access_token ) {
864
+ if ( passIdTokenAsAccessToken && ! state . currentTokenSet ?. set ?. id_token ) {
865
+ throw new MongoDBOIDCError ( 'Could not retrieve valid ID token' ) ;
866
+ } else if ( ! state . currentTokenSet ?. set ?. access_token ) {
835
867
throw new MongoDBOIDCError ( 'Could not retrieve valid access token' ) ;
836
868
}
837
869
} catch ( err : unknown ) {
@@ -844,17 +876,24 @@ export class MongoDBOIDCPluginImpl implements MongoDBOIDCPlugin {
844
876
driverAbortSignal ?. removeEventListener ( 'abort' , driverAbortCb ) ;
845
877
}
846
878
879
+ const { token_type, expires_at, access_token, id_token, refresh_token } =
880
+ state . currentTokenSet . set ;
881
+
847
882
this . logger . emit ( 'mongodb-oidc-plugin:auth-succeeded' , {
848
- tokenType : state . currentTokenSet . set . token_type ?? null , // DPoP or Bearer
849
- hasRefreshToken : ! ! state . currentTokenSet . set . refresh_token ,
850
- expiresAt : state . currentTokenSet . set . expires_at
851
- ? new Date ( state . currentTokenSet . set . expires_at * 1000 ) . toISOString ( )
852
- : null ,
883
+ tokenType : token_type ?? null , // DPoP or Bearer
884
+ refreshToken : getRefreshTokenId ( refresh_token ) ,
885
+ expiresAt : expires_at ? new Date ( expires_at * 1000 ) . toISOString ( ) : null ,
886
+ passIdTokenAsAccessToken : ! ! passIdTokenAsAccessToken ,
887
+ tokens : {
888
+ accessToken : access_token ,
889
+ idToken : id_token ,
890
+ refreshToken : refresh_token ,
891
+ } ,
853
892
} ) ;
854
893
855
894
return {
856
- accessToken : state . currentTokenSet . set . access_token ,
857
- refreshToken : state . currentTokenSet . set . refresh_token ,
895
+ accessToken : passIdTokenAsAccessToken ? id_token || '' : access_token ,
896
+ refreshToken : refresh_token ,
858
897
// Passing `expiresInSeconds: 0` results in the driver not caching the token.
859
898
// We perform our own caching here inside the plugin, so interactions with the
860
899
// cache of the driver are not really required or necessarily helpful.
0 commit comments