@@ -23,13 +23,19 @@ import (
2323 "strings"
2424 "time"
2525
26- "firebase.google.com/go/internal"
26+ "firebase.google.com/go/v4/ internal"
2727 "google.golang.org/api/transport"
2828)
2929
3030const (
31+ authErrorCode = "authErrorCode"
3132 firebaseAudience = "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit"
3233 oneHourInSeconds = 3600
34+
35+ // SDK-generated error codes
36+ idTokenRevoked = "ID_TOKEN_REVOKED"
37+ sessionCookieRevoked = "SESSION_COOKIE_REVOKED"
38+ tenantIDMismatch = "TENANT_ID_MISMATCH"
3339)
3440
3541var reservedClaims = []string {
@@ -102,7 +108,6 @@ func NewClient(ctx context.Context, conf *internal.AuthConfig) (*Client, error)
102108
103109 hc := internal .WithDefaultRetryConfig (transport )
104110 hc .CreateErrFn = handleHTTPError
105- hc .SuccessFn = internal .HasSuccessStatus
106111 hc .Opts = []internal.HTTPOption {
107112 internal .WithHeader ("X-Client-Version" , fmt .Sprintf ("Go/Admin/%s" , conf .Version )),
108113 }
@@ -261,12 +266,23 @@ func (c *baseClient) withTenantID(tenantID string) *baseClient {
261266func (c * baseClient ) VerifyIDToken (ctx context.Context , idToken string ) (* Token , error ) {
262267 decoded , err := c .idTokenVerifier .VerifyToken (ctx , idToken )
263268 if err == nil && c .tenantID != "" && c .tenantID != decoded .Firebase .Tenant {
264- return nil , internal .Errorf (tenantIDMismatch , "invalid tenant id: %q" , decoded .Firebase .Tenant )
269+ return nil , & internal.FirebaseError {
270+ ErrorCode : internal .InvalidArgument ,
271+ String : fmt .Sprintf ("invalid tenant id: %q" , decoded .Firebase .Tenant ),
272+ Ext : map [string ]interface {}{
273+ authErrorCode : tenantIDMismatch ,
274+ },
275+ }
265276 }
266277
267278 return decoded , err
268279}
269280
281+ // IsTenantIDMismatch checks if the given error was due to a mismatched tenant ID in a JWT.
282+ func IsTenantIDMismatch (err error ) bool {
283+ return hasAuthErrorCode (err , tenantIDMismatch )
284+ }
285+
270286// VerifyIDTokenAndCheckRevoked verifies the provided ID token, and additionally checks that the
271287// token has not been revoked.
272288//
@@ -284,12 +300,27 @@ func (c *baseClient) VerifyIDTokenAndCheckRevoked(ctx context.Context, idToken s
284300 if err != nil {
285301 return nil , err
286302 }
303+
287304 if revoked {
288- return nil , internal .Error (idTokenRevoked , "ID token has been revoked" )
305+ return nil , & internal.FirebaseError {
306+ ErrorCode : internal .InvalidArgument ,
307+ String : "ID token has been revoked" ,
308+ Ext : map [string ]interface {}{
309+ authErrorCode : idTokenRevoked ,
310+ },
311+ }
289312 }
313+
290314 return decoded , nil
291315}
292316
317+ // IsIDTokenRevoked checks if the given error was due to a revoked ID token.
318+ //
319+ // When IsIDTokenRevoked returns true, IsIDTokenInvalid is guranteed to return true.
320+ func IsIDTokenRevoked (err error ) bool {
321+ return hasAuthErrorCode (err , idTokenRevoked )
322+ }
323+
293324// VerifySessionCookie verifies the signature and payload of the provided Firebase session cookie.
294325//
295326// VerifySessionCookie accepts a signed JWT token string, and verifies that it is current, issued for the
@@ -324,12 +355,27 @@ func (c *Client) VerifySessionCookieAndCheckRevoked(ctx context.Context, session
324355 if err != nil {
325356 return nil , err
326357 }
358+
327359 if revoked {
328- return nil , internal .Error (sessionCookieRevoked , "session cookie has been revoked" )
360+ return nil , & internal.FirebaseError {
361+ ErrorCode : internal .InvalidArgument ,
362+ String : "session cookie has been revoked" ,
363+ Ext : map [string ]interface {}{
364+ authErrorCode : sessionCookieRevoked ,
365+ },
366+ }
329367 }
368+
330369 return decoded , nil
331370}
332371
372+ // IsSessionCookieRevoked checks if the given error was due to a revoked session cookie.
373+ //
374+ // When IsSessionCookieRevoked returns true, IsSessionCookieInvalid is guranteed to return true.
375+ func IsSessionCookieRevoked (err error ) bool {
376+ return hasAuthErrorCode (err , sessionCookieRevoked )
377+ }
378+
333379func (c * baseClient ) checkRevoked (ctx context.Context , token * Token ) (bool , error ) {
334380 user , err := c .GetUser (ctx , token .UID )
335381 if err != nil {
@@ -338,3 +384,13 @@ func (c *baseClient) checkRevoked(ctx context.Context, token *Token) (bool, erro
338384
339385 return token .IssuedAt * 1000 < user .TokensValidAfterMillis , nil
340386}
387+
388+ func hasAuthErrorCode (err error , code string ) bool {
389+ fe , ok := err .(* internal.FirebaseError )
390+ if ! ok {
391+ return false
392+ }
393+
394+ got , ok := fe .Ext [authErrorCode ]
395+ return ok && got == code
396+ }
0 commit comments