@@ -103,12 +103,12 @@ func NewClient(ctx context.Context, conf *internal.AuthConfig) (*Client, error)
103
103
}
104
104
}
105
105
106
- idTokenVerifier , err := newIDTokenVerifier (ctx , conf .ProjectID , isEmulator )
106
+ idTokenVerifier , err := newIDTokenVerifier (ctx , conf .ProjectID )
107
107
if err != nil {
108
108
return nil , err
109
109
}
110
110
111
- cookieVerifier , err := newSessionCookieVerifier (ctx , conf .ProjectID , isEmulator )
111
+ cookieVerifier , err := newSessionCookieVerifier (ctx , conf .ProjectID )
112
112
if err != nil {
113
113
return nil , err
114
114
}
@@ -144,6 +144,7 @@ func NewClient(ctx context.Context, conf *internal.AuthConfig) (*Client, error)
144
144
cookieVerifier : cookieVerifier ,
145
145
signer : signer ,
146
146
clock : internal .SystemClock ,
147
+ isEmulator : isEmulator ,
147
148
}
148
149
return & Client {
149
150
baseClient : base ,
@@ -265,6 +266,7 @@ type baseClient struct {
265
266
cookieVerifier * tokenVerifier
266
267
signer cryptoSigner
267
268
clock internal.Clock
269
+ isEmulator bool
268
270
}
269
271
270
272
func (c * baseClient ) withTenantID (tenantID string ) * baseClient {
@@ -281,63 +283,68 @@ func (c *baseClient) withTenantID(tenantID string) *baseClient {
281
283
// https://firebase.google.com/docs/auth/admin/verify-id-tokens#retrieve_id_tokens_on_clients for
282
284
// more details on how to obtain an ID token in a client app.
283
285
//
284
- // This function does not make any RPC calls most of the time. The only time it makes an RPC call
285
- // is when Google public keys need to be refreshed. These keys get cached up to 24 hours, and
286
- // therefore the RPC overhead gets amortized over many invocations of this function.
286
+ // In non-emulator mode, this function does not make any RPC calls most of the time.
287
+ // The only time it makes an RPC call is when Google public keys need to be refreshed.
288
+ // These keys get cached up to 24 hours, and therefore the RPC overhead gets amortized
289
+ // over many invocations of this function.
287
290
//
288
291
// This does not check whether or not the token has been revoked. Use `VerifyIDTokenAndCheckRevoked()`
289
292
// when a revocation check is needed.
290
293
func (c * baseClient ) VerifyIDToken (ctx context.Context , idToken string ) (* Token , error ) {
291
- decoded , err := c .idTokenVerifier .VerifyToken (ctx , idToken )
292
- if err == nil && c .tenantID != "" && c .tenantID != decoded .Firebase .Tenant {
293
- return nil , & internal.FirebaseError {
294
- ErrorCode : internal .InvalidArgument ,
295
- String : fmt .Sprintf ("invalid tenant id: %q" , decoded .Firebase .Tenant ),
296
- Ext : map [string ]interface {}{
297
- authErrorCode : tenantIDMismatch ,
298
- },
299
- }
300
- }
301
-
302
- return decoded , err
303
- }
304
-
305
- // IsTenantIDMismatch checks if the given error was due to a mismatched tenant ID in a JWT.
306
- func IsTenantIDMismatch (err error ) bool {
307
- return hasAuthErrorCode (err , tenantIDMismatch )
294
+ return c .verifyIDToken (ctx , idToken , false )
308
295
}
309
296
310
297
// VerifyIDTokenAndCheckRevoked verifies the provided ID token, and additionally checks that the
311
298
// token has not been revoked.
312
299
//
313
- // This function uses `VerifyIDToken()` internally to verify the ID token JWT. However, unlike
314
- // `VerifyIDToken()` this function must make an RPC call to perform the revocation check.
300
+ // Unlike `VerifyIDToken()`, this function must make an RPC call to perform the revocation check.
315
301
// Developers are advised to take this additional overhead into consideration when including this
316
302
// function in an authorization flow that gets executed often.
317
303
func (c * baseClient ) VerifyIDTokenAndCheckRevoked (ctx context.Context , idToken string ) (* Token , error ) {
318
- decoded , err := c .VerifyIDToken (ctx , idToken )
319
- if err != nil {
320
- return nil , err
321
- }
304
+ return c .verifyIDToken (ctx , idToken , true )
305
+ }
322
306
323
- revoked , err := c .checkRevoked (ctx , decoded )
307
+ func (c * baseClient ) verifyIDToken (ctx context.Context , idToken string , checkRevoked bool ) (* Token , error ) {
308
+ decoded , err := c .idTokenVerifier .VerifyToken (ctx , idToken , c .isEmulator )
324
309
if err != nil {
325
310
return nil , err
326
311
}
327
312
328
- if revoked {
313
+ if c . tenantID != "" && c . tenantID != decoded . Firebase . Tenant {
329
314
return nil , & internal.FirebaseError {
330
315
ErrorCode : internal .InvalidArgument ,
331
- String : "ID token has been revoked" ,
316
+ String : fmt . Sprintf ( "invalid tenant id: %q" , decoded . Firebase . Tenant ) ,
332
317
Ext : map [string ]interface {}{
333
- authErrorCode : idTokenRevoked ,
318
+ authErrorCode : tenantIDMismatch ,
334
319
},
335
320
}
336
321
}
337
322
323
+ if c .isEmulator || checkRevoked {
324
+ revoked , err := c .checkRevoked (ctx , decoded )
325
+ if err != nil {
326
+ return nil , err
327
+ }
328
+
329
+ if revoked {
330
+ return nil , & internal.FirebaseError {
331
+ ErrorCode : internal .InvalidArgument ,
332
+ String : "ID token has been revoked" ,
333
+ Ext : map [string ]interface {}{
334
+ authErrorCode : idTokenRevoked ,
335
+ },
336
+ }
337
+ }
338
+ }
339
+
338
340
return decoded , nil
339
341
}
340
342
343
+ // IsTenantIDMismatch checks if the given error was due to a mismatched tenant ID in a JWT.
344
+ func IsTenantIDMismatch (err error ) bool {
345
+ return hasAuthErrorCode (err , tenantIDMismatch )
346
+ }
347
+
341
348
// IsIDTokenRevoked checks if the given error was due to a revoked ID token.
342
349
//
343
350
// When IsIDTokenRevoked returns true, IsIDTokenInvalid is guranteed to return true.
@@ -352,41 +359,47 @@ func IsIDTokenRevoked(err error) bool {
352
359
// decoded claims in the input JWT. See https://firebase.google.com/docs/auth/admin/manage-cookies for more details on
353
360
// how to obtain a session cookie.
354
361
//
355
- // This function does not make any RPC calls most of the time. The only time it makes an RPC call
356
- // is when Google public keys need to be refreshed. These keys get cached up to 24 hours, and
357
- // therefore the RPC overhead gets amortized over many invocations of this function.
362
+ // In non-emulator mode, this function does not make any RPC calls most of the time.
363
+ // The only time it makes an RPC call is when Google public keys need to be refreshed.
364
+ // These keys get cached up to 24 hours, and therefore the RPC overhead gets amortized
365
+ // over many invocations of this function.
358
366
//
359
367
// This does not check whether or not the cookie has been revoked. Use `VerifySessionCookieAndCheckRevoked()`
360
368
// when a revocation check is needed.
361
369
func (c * Client ) VerifySessionCookie (ctx context.Context , sessionCookie string ) (* Token , error ) {
362
- return c .cookieVerifier . VerifyToken (ctx , sessionCookie )
370
+ return c .verifySessionCookie (ctx , sessionCookie , false )
363
371
}
364
372
365
373
// VerifySessionCookieAndCheckRevoked verifies the provided session cookie, and additionally checks that the
366
374
// cookie has not been revoked.
367
375
//
368
- // This function uses `VerifySessionCookie()` internally to verify the cookie JWT. However, unlike
369
- // `VerifySessionCookie()` this function must make an RPC call to perform the revocation check.
376
+ // Unlike `VerifySessionCookie()`, this function must make an RPC call to perform the revocation check.
370
377
// Developers are advised to take this additional overhead into consideration when including this
371
378
// function in an authorization flow that gets executed often.
372
379
func (c * Client ) VerifySessionCookieAndCheckRevoked (ctx context.Context , sessionCookie string ) (* Token , error ) {
373
- decoded , err := c .VerifySessionCookie (ctx , sessionCookie )
374
- if err != nil {
375
- return nil , err
376
- }
380
+ return c .verifySessionCookie (ctx , sessionCookie , true )
381
+ }
377
382
378
- revoked , err := c .checkRevoked (ctx , decoded )
383
+ func (c * Client ) verifySessionCookie (ctx context.Context , sessionCookie string , checkRevoked bool ) (* Token , error ) {
384
+ decoded , err := c .cookieVerifier .VerifyToken (ctx , sessionCookie , c .isEmulator )
379
385
if err != nil {
380
386
return nil , err
381
387
}
382
388
383
- if revoked {
384
- return nil , & internal.FirebaseError {
385
- ErrorCode : internal .InvalidArgument ,
386
- String : "session cookie has been revoked" ,
387
- Ext : map [string ]interface {}{
388
- authErrorCode : sessionCookieRevoked ,
389
- },
389
+ if c .isEmulator || checkRevoked {
390
+ revoked , err := c .checkRevoked (ctx , decoded )
391
+ if err != nil {
392
+ return nil , err
393
+ }
394
+
395
+ if revoked {
396
+ return nil , & internal.FirebaseError {
397
+ ErrorCode : internal .InvalidArgument ,
398
+ String : "session cookie has been revoked" ,
399
+ Ext : map [string ]interface {}{
400
+ authErrorCode : sessionCookieRevoked ,
401
+ },
402
+ }
390
403
}
391
404
}
392
405
0 commit comments