@@ -37,6 +37,7 @@ const (
37
37
38
38
// SDK-generated error codes
39
39
idTokenRevoked = "ID_TOKEN_REVOKED"
40
+ userDisabled = "USER_DISABLED"
40
41
sessionCookieRevoked = "SESSION_COOKIE_REVOKED"
41
42
tenantIDMismatch = "TENANT_ID_MISMATCH"
42
43
)
@@ -288,14 +289,14 @@ func (c *baseClient) withTenantID(tenantID string) *baseClient {
288
289
// These keys get cached up to 24 hours, and therefore the RPC overhead gets amortized
289
290
// over many invocations of this function.
290
291
//
291
- // This does not check whether or not the token has been revoked. Use `VerifyIDTokenAndCheckRevoked()`
292
+ // This does not check whether or not the token has been revoked or disabled . Use `VerifyIDTokenAndCheckRevoked()`
292
293
// when a revocation check is needed.
293
294
func (c * baseClient ) VerifyIDToken (ctx context.Context , idToken string ) (* Token , error ) {
294
295
return c .verifyIDToken (ctx , idToken , false )
295
296
}
296
297
297
298
// VerifyIDTokenAndCheckRevoked verifies the provided ID token, and additionally checks that the
298
- // token has not been revoked.
299
+ // token has not been revoked or disabled .
299
300
//
300
301
// Unlike `VerifyIDToken()`, this function must make an RPC call to perform the revocation check.
301
302
// Developers are advised to take this additional overhead into consideration when including this
@@ -304,7 +305,7 @@ func (c *baseClient) VerifyIDTokenAndCheckRevoked(ctx context.Context, idToken s
304
305
return c .verifyIDToken (ctx , idToken , true )
305
306
}
306
307
307
- func (c * baseClient ) verifyIDToken (ctx context.Context , idToken string , checkRevoked bool ) (* Token , error ) {
308
+ func (c * baseClient ) verifyIDToken (ctx context.Context , idToken string , checkRevokedOrDisabled bool ) (* Token , error ) {
308
309
decoded , err := c .idTokenVerifier .VerifyToken (ctx , idToken , c .isEmulator )
309
310
if err != nil {
310
311
return nil , err
@@ -320,21 +321,11 @@ func (c *baseClient) verifyIDToken(ctx context.Context, idToken string, checkRev
320
321
}
321
322
}
322
323
323
- if c .isEmulator || checkRevoked {
324
- revoked , err : = c .checkRevoked (ctx , decoded )
324
+ if c .isEmulator || checkRevokedOrDisabled {
325
+ err = c .checkRevokedOrDisabled (ctx , decoded , idTokenRevoked , "ID token has been revoked" )
325
326
if err != nil {
326
327
return nil , err
327
328
}
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
329
}
339
330
340
331
return decoded , nil
@@ -347,11 +338,18 @@ func IsTenantIDMismatch(err error) bool {
347
338
348
339
// IsIDTokenRevoked checks if the given error was due to a revoked ID token.
349
340
//
350
- // When IsIDTokenRevoked returns true, IsIDTokenInvalid is guranteed to return true.
341
+ // When IsIDTokenRevoked returns true, IsIDTokenInvalid is guaranteed to return true.
351
342
func IsIDTokenRevoked (err error ) bool {
352
343
return hasAuthErrorCode (err , idTokenRevoked )
353
344
}
354
345
346
+ // IsUserDisabled checks if the given error was due to a disabled ID token
347
+ //
348
+ // When IsUserDisabled returns true, IsIDTokenInvalid is guaranteed to return true.
349
+ func IsUserDisabled (err error ) bool {
350
+ return hasAuthErrorCode (err , userDisabled )
351
+ }
352
+
355
353
// VerifySessionCookie verifies the signature and payload of the provided Firebase session cookie.
356
354
//
357
355
// VerifySessionCookie accepts a signed JWT token string, and verifies that it is current, issued for the
@@ -371,7 +369,7 @@ func (c *Client) VerifySessionCookie(ctx context.Context, sessionCookie string)
371
369
}
372
370
373
371
// VerifySessionCookieAndCheckRevoked verifies the provided session cookie, and additionally checks that the
374
- // cookie has not been revoked.
372
+ // cookie has not been revoked and the user has not been disabled .
375
373
//
376
374
// Unlike `VerifySessionCookie()`, this function must make an RPC call to perform the revocation check.
377
375
// Developers are advised to take this additional overhead into consideration when including this
@@ -380,46 +378,55 @@ func (c *Client) VerifySessionCookieAndCheckRevoked(ctx context.Context, session
380
378
return c .verifySessionCookie (ctx , sessionCookie , true )
381
379
}
382
380
383
- func (c * Client ) verifySessionCookie (ctx context.Context , sessionCookie string , checkRevoked bool ) (* Token , error ) {
381
+ func (c * Client ) verifySessionCookie (ctx context.Context , sessionCookie string , checkRevokedOrDisabled bool ) (* Token , error ) {
384
382
decoded , err := c .cookieVerifier .VerifyToken (ctx , sessionCookie , c .isEmulator )
385
383
if err != nil {
386
384
return nil , err
387
385
}
388
386
389
- if c .isEmulator || checkRevoked {
390
- revoked , err := c .checkRevoked (ctx , decoded )
387
+ if c .isEmulator || checkRevokedOrDisabled {
388
+ err := c .checkRevokedOrDisabled (ctx , decoded , sessionCookieRevoked , "session cookie has been revoked" )
391
389
if err != nil {
392
390
return nil , err
393
391
}
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
- }
403
- }
404
392
}
405
393
406
394
return decoded , nil
407
395
}
408
396
409
397
// IsSessionCookieRevoked checks if the given error was due to a revoked session cookie.
410
398
//
411
- // When IsSessionCookieRevoked returns true, IsSessionCookieInvalid is guranteed to return true.
399
+ // When IsSessionCookieRevoked returns true, IsSessionCookieInvalid is guaranteed to return true.
412
400
func IsSessionCookieRevoked (err error ) bool {
413
401
return hasAuthErrorCode (err , sessionCookieRevoked )
414
402
}
415
403
416
- func (c * baseClient ) checkRevoked (ctx context.Context , token * Token ) (bool , error ) {
404
+ // checkRevokedOrDisabled checks whether the input token has been revoked or disabled.
405
+ func (c * baseClient ) checkRevokedOrDisabled (ctx context.Context , token * Token , errCode string , errMessage string ) error {
417
406
user , err := c .GetUser (ctx , token .UID )
418
407
if err != nil {
419
- return false , err
408
+ return err
420
409
}
410
+ if user .Disabled {
411
+ return & internal.FirebaseError {
412
+ ErrorCode : internal .InvalidArgument ,
413
+ String : "user has been disabled" ,
414
+ Ext : map [string ]interface {}{
415
+ authErrorCode : userDisabled ,
416
+ },
417
+ }
421
418
422
- return token .IssuedAt * 1000 < user .TokensValidAfterMillis , nil
419
+ }
420
+ if token .IssuedAt * 1000 < user .TokensValidAfterMillis {
421
+ return & internal.FirebaseError {
422
+ ErrorCode : internal .InvalidArgument ,
423
+ String : errMessage ,
424
+ Ext : map [string ]interface {}{
425
+ authErrorCode : errCode ,
426
+ },
427
+ }
428
+ }
429
+ return nil
423
430
}
424
431
425
432
func hasAuthErrorCode (err error , code string ) bool {
0 commit comments