Skip to content

Commit 0684410

Browse files
authored
Implement SessionCookie() API (#226)
* Breaking the user_mgt.go into multiple files * Implemented CreateSessionCookie() API * Renamed CreateSessionCookie() to SessionCookie() * Updated changelog * Updated comments * Implemented VerifySessionCookie() API (#230) * Implemented VerifySessionCookie() API * Added more tests for session cookie verification * Reordered for clarity * Fixing a typo; Logging random seed in auth integration tests
1 parent 494dfce commit 0684410

File tree

8 files changed

+618
-13
lines changed

8 files changed

+618
-13
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Unreleased
22

3+
- [added] Implemented `auth.SessionCookie()` function for creating
4+
new Firebase session cookies given an ID token.
5+
- [added] Implemented `auth.VerifySessionCookie()` and
6+
`auth.VerifySessionCookieAndCheckRevoked()` functions for verifying
7+
Firebase session cookies.
38
- [added] Implemented HTTP retries for the `db` package. This package
49
now retries HTTP calls on low-level connection and socket read errors, as
510
well as HTTP 500 and 503 errors.

auth/auth.go

Lines changed: 71 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import (
2424

2525
"firebase.google.com/go/internal"
2626
"google.golang.org/api/identitytoolkit/v3"
27-
"google.golang.org/api/transport"
2827
)
2928

3029
const (
@@ -42,8 +41,10 @@ var reservedClaims = []string{
4241
// Client facilitates generating custom JWT tokens for Firebase clients, and verifying ID tokens issued
4342
// by Firebase backend services.
4443
type Client struct {
45-
is *identitytoolkit.Service
44+
is *identitytoolkit.Service
45+
userManagementClient
4646
idTokenVerifier *tokenVerifier
47+
cookieVerifier *tokenVerifier
4748
signer cryptoSigner
4849
version string
4950
clock internal.Clock
@@ -84,12 +85,12 @@ func NewClient(ctx context.Context, conf *internal.AuthConfig) (*Client, error)
8485
}
8586
}
8687

87-
hc, _, err := transport.NewHTTPClient(ctx, conf.Opts...)
88+
hc, _, err := internal.NewHTTPClient(ctx, conf.Opts...)
8889
if err != nil {
8990
return nil, err
9091
}
9192

92-
is, err := identitytoolkit.New(hc)
93+
is, err := identitytoolkit.New(hc.Client)
9394
if err != nil {
9495
return nil, err
9596
}
@@ -98,11 +99,25 @@ func NewClient(ctx context.Context, conf *internal.AuthConfig) (*Client, error)
9899
if err != nil {
99100
return nil, err
100101
}
102+
103+
cookieVerifier, err := newSessionCookieVerifier(ctx, conf.ProjectID)
104+
if err != nil {
105+
return nil, err
106+
}
107+
108+
version := "Go/Admin/" + conf.Version
101109
return &Client{
110+
userManagementClient: userManagementClient{
111+
baseURL: idToolkitEndpoint,
112+
projectID: conf.ProjectID,
113+
version: version,
114+
httpClient: hc,
115+
},
102116
is: is,
103117
idTokenVerifier: idTokenVerifier,
118+
cookieVerifier: cookieVerifier,
104119
signer: signer,
105-
version: "Go/Admin/" + conf.Version,
120+
version: version, // This can be removed when userManagementClient implements all user mgt APIs.
106121
clock: internal.SystemClock,
107122
}, nil
108123
}
@@ -216,13 +231,61 @@ func (c *Client) VerifyIDTokenAndCheckRevoked(ctx context.Context, idToken strin
216231
return nil, err
217232
}
218233

219-
user, err := c.GetUser(ctx, p.UID)
234+
revoked, err := c.checkRevoked(ctx, p)
220235
if err != nil {
221236
return nil, err
222237
}
223-
224-
if p.IssuedAt*1000 < user.TokensValidAfterMillis {
238+
if revoked {
225239
return nil, internal.Error(idTokenRevoked, "ID token has been revoked")
226240
}
227241
return p, nil
228242
}
243+
244+
// VerifySessionCookie verifies the signature and payload of the provided Firebase session cookie.
245+
//
246+
// VerifySessionCookie accepts a signed JWT token string, and verifies that it is current, issued for the
247+
// correct Firebase project, and signed by the Google Firebase services in the cloud. It returns a Token containing the
248+
// decoded claims in the input JWT. See https://firebase.google.com/docs/auth/admin/manage-cookies for more details on
249+
// how to obtain a session cookie.
250+
//
251+
// This function does not make any RPC calls most of the time. The only time it makes an RPC call
252+
// is when Google public keys need to be refreshed. These keys get cached up to 24 hours, and
253+
// therefore the RPC overhead gets amortized over many invocations of this function.
254+
//
255+
// This does not check whether or not the cookie has been revoked. Use `VerifySessionCookieAndCheckRevoked()`
256+
// when a revocation check is needed.
257+
func (c *Client) VerifySessionCookie(ctx context.Context, sessionCookie string) (*Token, error) {
258+
return c.cookieVerifier.VerifyToken(ctx, sessionCookie)
259+
}
260+
261+
// VerifySessionCookieAndCheckRevoked verifies the provided session cookie, and additionally checks that the
262+
// cookie has not been revoked.
263+
//
264+
// This function uses `VerifySessionCookie()` internally to verify the cookie JWT. However, unlike
265+
// `VerifySessionCookie()` this function must make an RPC call to perform the revocation check.
266+
// Developers are advised to take this additional overhead into consideration when including this
267+
// function in an authorization flow that gets executed often.
268+
func (c *Client) VerifySessionCookieAndCheckRevoked(ctx context.Context, sessionCookie string) (*Token, error) {
269+
p, err := c.VerifySessionCookie(ctx, sessionCookie)
270+
if err != nil {
271+
return nil, err
272+
}
273+
274+
revoked, err := c.checkRevoked(ctx, p)
275+
if err != nil {
276+
return nil, err
277+
}
278+
if revoked {
279+
return nil, internal.Error(sessionCookieRevoked, "session cookie has been revoked")
280+
}
281+
return p, nil
282+
}
283+
284+
func (c *Client) checkRevoked(ctx context.Context, token *Token) (bool, error) {
285+
user, err := c.GetUser(ctx, token.UID)
286+
if err != nil {
287+
return false, err
288+
}
289+
290+
return token.IssuedAt*1000 < user.TokensValidAfterMillis, nil
291+
}

0 commit comments

Comments
 (0)