@@ -64,8 +64,6 @@ export class CompassAuthService {
6464
6565 private static signInPromise : Promise < AtlasUserInfo > | null = null ;
6666
67- private static userInfo : AtlasUserInfo | null = null ;
68-
6967 private static fetch = async (
7068 url : string ,
7169 init : RequestInit = { }
@@ -151,7 +149,7 @@ export class CompassAuthService {
151149 allowedFlows : this . getAllowedAuthFlows . bind ( this ) ,
152150 logger : this . oidcPluginLogger ,
153151 serializedState,
154- customFetch : this . httpClient
152+ customFetch : this
155153 . fetch as unknown as MongoDBOIDCPluginOptions [ 'customFetch' ] ,
156154 } ) ;
157155 oidcPluginHookLoggerToMongoLogWriter (
@@ -261,18 +259,20 @@ export class CompassAuthService {
261259
262260 try {
263261 const tokens = await this . requestOAuthToken ( { signal } ) ;
264- this . userInfo = this . getUserInfoFromAccessToken ( tokens . accessToken ) ;
262+ this . currentUser = this . getUserInfoFromAccessToken (
263+ tokens . accessToken
264+ ) ;
265265 log . info (
266266 mongoLogId ( 1_001_000_219 ) ,
267267 'AtlasService' ,
268268 'Signed in successfully'
269269 ) ;
270- const { auid } = getTrackingUserInfo ( this . userInfo ) ;
270+ const { auid } = getTrackingUserInfo ( this . currentUser ) ;
271271 track ( 'Atlas Sign In Success' , { auid } ) ;
272272 await this . preferences . savePreferences ( {
273273 telemetryAtlasUserId : auid ,
274274 } ) ;
275- return this . userInfo ;
275+ return this . currentUser ;
276276 } catch ( err ) {
277277 track ( 'Atlas Sign In Error' , {
278278 error : ( err as Error ) . message ,
@@ -296,17 +296,10 @@ export class CompassAuthService {
296296 if ( ! this . currentUser ) {
297297 throw new Error ( "Can't sign out if not signed in yet" ) ;
298298 }
299- // Reset and recreate event emitter first so that we don't accidentally
300- // react on any old plugin instance events
301- this . oidcPluginLogger . removeAllListeners ( ) ;
302- this . oidcPluginLogger = new OidcPluginLogger ( ) ;
303- this . attachOidcPluginLoggerEvents ( ) ;
304- // Destroy old plugin and setup new one
305- await this . plugin ?. destroy ( ) ;
306- this . setupPlugin ( ) ;
307- // Revoke tokens. Revoking refresh token will also revoke associated access
308- // tokens
309- // https://developer.okta.com/docs/guides/revoke-tokens/main/#revoke-an-access-token-or-a-refresh-token
299+ // Revoke tokens BEFORE destroying the plugin — otherwise maybeGetToken
300+ // reads from a fresh, empty plugin and posts an empty token, which the
301+ // revocation endpoint rejects with 400. Revoking the refresh token also
302+ // invalidates the associated access token (RFC 7009 §2.1).
310303 try {
311304 await this . revoke ( { tokenType : 'refreshToken' } ) ;
312305 } catch ( err ) {
@@ -317,15 +310,20 @@ export class CompassAuthService {
317310 // this is not a failed state for the app, we already cleaned up token
318311 // from everywhere, so we just ignore this
319312 }
313+ // Reset and recreate event emitter so that we don't accidentally react on
314+ // any old plugin instance events
315+ this . oidcPluginLogger . removeAllListeners ( ) ;
316+ this . oidcPluginLogger = new OidcPluginLogger ( ) ;
317+ this . attachOidcPluginLoggerEvents ( ) ;
318+ // Destroy old plugin and setup new one
319+ await this . plugin ?. destroy ( ) ;
320+ this . setupPlugin ( ) ;
320321 // Keep a copy of current user info for tracking
321322 const userInfo = this . currentUser ;
322323 // Reset service state
323324 this . currentUser = null ;
324325 this . oidcPluginLogger . emit ( 'atlas-service-signed-out' ) ;
325- // Open Atlas sign out page to end the browser session created for sign in
326- const signOutUrl = new URL ( this . config . authPortalUrl ) ;
327- signOutUrl . searchParams . set ( 'signedOut' , 'true' ) ;
328- void this . openExternal ( signOutUrl . toString ( ) ) ;
326+
329327 track ( 'Atlas Sign Out' , getTrackingUserInfo ( userInfo ) ) ;
330328 }
331329
@@ -386,7 +384,7 @@ export class CompassAuthService {
386384
387385 const token = await this . maybeGetToken ( { signal, tokenType } ) ;
388386
389- const res = await this . fetch ( url . toString ( ) , {
387+ const res = await this . httpClient . fetch ( url . toString ( ) , {
390388 method : 'POST' ,
391389 body : new URLSearchParams ( [
392390 [ 'token' , token ?? '' ] ,
@@ -414,18 +412,20 @@ export class CompassAuthService {
414412 throwIfAborted ( signal ) ;
415413 this . throwIfNetworkTrafficDisabled ( ) ;
416414
417- const url = new URL ( ` ${ this . config . atlasLogin . issuer } /v1/revoke` ) ;
418- url . searchParams . set ( 'client_id' , this . config . atlasLogin . clientId ) ;
415+ // TODO: check if we should use the discovery endpoint instead of hardcoding this
416+ const url = new URL ( ` ${ this . config . atlasLogin . issuer } /tokens/revoke` ) ;
419417
420418 tokenType ??= 'accessToken' ;
421419
420+ console . log ( '[sign out] revoking token' , tokenType ) ;
422421 const token = await this . maybeGetToken ( { signal, tokenType } ) ;
423422
424- const res = await this . fetch ( url . toString ( ) , {
423+ const res = await this . httpClient . fetch ( url . toString ( ) , {
425424 method : 'POST' ,
426425 body : new URLSearchParams ( [
427426 [ 'token' , token ?? '' ] ,
428427 [ 'token_type_hint' , TOKEN_TYPE_TO_HINT [ tokenType ] ] ,
428+ [ 'client_id' , this . config . atlasLogin . clientId ] ,
429429 ] ) ,
430430 headers : {
431431 Accept : 'application/json' ,
@@ -434,6 +434,16 @@ export class CompassAuthService {
434434 signal : signal ,
435435 } ) ;
436436
437+ if ( ! res . ok ) {
438+ const body = await res . text ( ) . catch ( ( ) => '<unreadable>' ) ;
439+ console . log (
440+ '[sign out] revocation failed' ,
441+ res . status ,
442+ res . statusText ,
443+ body
444+ ) ;
445+ }
446+
437447 await throwIfNotOk ( res ) ;
438448 }
439449
0 commit comments