@@ -23,13 +23,19 @@ import (
23
23
"strings"
24
24
"time"
25
25
26
- "firebase.google.com/go/internal"
26
+ "firebase.google.com/go/v4/ internal"
27
27
"google.golang.org/api/transport"
28
28
)
29
29
30
30
const (
31
+ authErrorCode = "authErrorCode"
31
32
firebaseAudience = "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit"
32
33
oneHourInSeconds = 3600
34
+
35
+ // SDK-generated error codes
36
+ idTokenRevoked = "ID_TOKEN_REVOKED"
37
+ sessionCookieRevoked = "SESSION_COOKIE_REVOKED"
38
+ tenantIDMismatch = "TENANT_ID_MISMATCH"
33
39
)
34
40
35
41
var reservedClaims = []string {
@@ -102,7 +108,6 @@ func NewClient(ctx context.Context, conf *internal.AuthConfig) (*Client, error)
102
108
103
109
hc := internal .WithDefaultRetryConfig (transport )
104
110
hc .CreateErrFn = handleHTTPError
105
- hc .SuccessFn = internal .HasSuccessStatus
106
111
hc .Opts = []internal.HTTPOption {
107
112
internal .WithHeader ("X-Client-Version" , fmt .Sprintf ("Go/Admin/%s" , conf .Version )),
108
113
}
@@ -261,12 +266,23 @@ func (c *baseClient) withTenantID(tenantID string) *baseClient {
261
266
func (c * baseClient ) VerifyIDToken (ctx context.Context , idToken string ) (* Token , error ) {
262
267
decoded , err := c .idTokenVerifier .VerifyToken (ctx , idToken )
263
268
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
+ }
265
276
}
266
277
267
278
return decoded , err
268
279
}
269
280
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
+
270
286
// VerifyIDTokenAndCheckRevoked verifies the provided ID token, and additionally checks that the
271
287
// token has not been revoked.
272
288
//
@@ -284,12 +300,27 @@ func (c *baseClient) VerifyIDTokenAndCheckRevoked(ctx context.Context, idToken s
284
300
if err != nil {
285
301
return nil , err
286
302
}
303
+
287
304
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
+ }
289
312
}
313
+
290
314
return decoded , nil
291
315
}
292
316
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
+
293
324
// VerifySessionCookie verifies the signature and payload of the provided Firebase session cookie.
294
325
//
295
326
// 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
324
355
if err != nil {
325
356
return nil , err
326
357
}
358
+
327
359
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
+ }
329
367
}
368
+
330
369
return decoded , nil
331
370
}
332
371
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
+
333
379
func (c * baseClient ) checkRevoked (ctx context.Context , token * Token ) (bool , error ) {
334
380
user , err := c .GetUser (ctx , token .UID )
335
381
if err != nil {
@@ -338,3 +384,13 @@ func (c *baseClient) checkRevoked(ctx context.Context, token *Token) (bool, erro
338
384
339
385
return token .IssuedAt * 1000 < user .TokensValidAfterMillis , nil
340
386
}
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