@@ -37,6 +37,7 @@ const (
3737
3838 // SDK-generated error codes
3939 idTokenRevoked = "ID_TOKEN_REVOKED"
40+ userDisabled = "USER_DISABLED"
4041 sessionCookieRevoked = "SESSION_COOKIE_REVOKED"
4142 tenantIDMismatch = "TENANT_ID_MISMATCH"
4243)
@@ -288,14 +289,14 @@ func (c *baseClient) withTenantID(tenantID string) *baseClient {
288289// These keys get cached up to 24 hours, and therefore the RPC overhead gets amortized
289290// over many invocations of this function.
290291//
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()`
292293// when a revocation check is needed.
293294func (c * baseClient ) VerifyIDToken (ctx context.Context , idToken string ) (* Token , error ) {
294295 return c .verifyIDToken (ctx , idToken , false )
295296}
296297
297298// 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 .
299300//
300301// Unlike `VerifyIDToken()`, this function must make an RPC call to perform the revocation check.
301302// 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
304305 return c .verifyIDToken (ctx , idToken , true )
305306}
306307
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 ) {
308309 decoded , err := c .idTokenVerifier .VerifyToken (ctx , idToken , c .isEmulator )
309310 if err != nil {
310311 return nil , err
@@ -320,21 +321,11 @@ func (c *baseClient) verifyIDToken(ctx context.Context, idToken string, checkRev
320321 }
321322 }
322323
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" )
325326 if err != nil {
326327 return nil , err
327328 }
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- }
338329 }
339330
340331 return decoded , nil
@@ -347,11 +338,18 @@ func IsTenantIDMismatch(err error) bool {
347338
348339// IsIDTokenRevoked checks if the given error was due to a revoked ID token.
349340//
350- // When IsIDTokenRevoked returns true, IsIDTokenInvalid is guranteed to return true.
341+ // When IsIDTokenRevoked returns true, IsIDTokenInvalid is guaranteed to return true.
351342func IsIDTokenRevoked (err error ) bool {
352343 return hasAuthErrorCode (err , idTokenRevoked )
353344}
354345
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+
355353// VerifySessionCookie verifies the signature and payload of the provided Firebase session cookie.
356354//
357355// 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)
371369}
372370
373371// 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 .
375373//
376374// Unlike `VerifySessionCookie()`, this function must make an RPC call to perform the revocation check.
377375// 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
380378 return c .verifySessionCookie (ctx , sessionCookie , true )
381379}
382380
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 ) {
384382 decoded , err := c .cookieVerifier .VerifyToken (ctx , sessionCookie , c .isEmulator )
385383 if err != nil {
386384 return nil , err
387385 }
388386
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" )
391389 if err != nil {
392390 return nil , err
393391 }
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- }
404392 }
405393
406394 return decoded , nil
407395}
408396
409397// IsSessionCookieRevoked checks if the given error was due to a revoked session cookie.
410398//
411- // When IsSessionCookieRevoked returns true, IsSessionCookieInvalid is guranteed to return true.
399+ // When IsSessionCookieRevoked returns true, IsSessionCookieInvalid is guaranteed to return true.
412400func IsSessionCookieRevoked (err error ) bool {
413401 return hasAuthErrorCode (err , sessionCookieRevoked )
414402}
415403
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 {
417406 user , err := c .GetUser (ctx , token .UID )
418407 if err != nil {
419- return false , err
408+ return err
420409 }
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+ }
421418
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
423430}
424431
425432func hasAuthErrorCode (err error , code string ) bool {
0 commit comments