Skip to content

Commit 9b5a8a8

Browse files
authored
Firebase Auth API (#6)
* Implementing the NewApp function based on the new APIs available in Go API client. * Renamed package admin to firebase; Updated documentation * Using JSON key exposed via credential * Finishing the Go API client integration * Added some integration tests * Updated documentation; Using the net/context package where needed * Added Version constant * Moved public functions in integration to integration/internal * Minor renaming
1 parent d23313a commit 9b5a8a8

File tree

9 files changed

+342
-368
lines changed

9 files changed

+342
-368
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
testdata/integration_*

admin.go

Lines changed: 0 additions & 217 deletions
This file was deleted.

auth/auth.go

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
// Package auth contains functions for minting custom authentication tokens, and verifying Firebase ID tokens.
12
package auth
23

34
import (
5+
"encoding/json"
46
"encoding/pem"
57
"errors"
68
"fmt"
@@ -15,7 +17,6 @@ import (
1517
const firebaseAudience = "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit"
1618
const googleCertURL = "https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com"
1719
const issuerPrefix = "https://securetoken.google.com/"
18-
const gcloudProject = "GCLOUD_PROJECT"
1920
const tokenExpSeconds = 3600
2021

2122
var reservedClaims = []string{
@@ -54,24 +55,42 @@ type Client struct {
5455
// NewClient creates a new instance of the Firebase Auth Client.
5556
//
5657
// This function can only be invoked from within the SDK. Client applications should access the
57-
// the Auth service through admin.App.
58+
// the Auth service through firebase.App.
5859
func NewClient(c *internal.AuthConfig) (*Client, error) {
59-
client := &Client{ks: newHTTPKeySource(googleCertURL), projectID: c.ProjectID}
60-
if c.Config != nil {
61-
client.email = c.Config.Email
62-
pk, err := parseKey(c.Config.PrivateKey)
60+
client := &Client{
61+
ks: newHTTPKeySource(googleCertURL),
62+
projectID: c.ProjectID,
63+
}
64+
if c.Creds == nil || len(c.Creds.JSON) == 0 {
65+
return client, nil
66+
}
67+
68+
var svcAcct struct {
69+
ClientEmail string `json:"client_email"`
70+
PrivateKey string `json:"private_key"`
71+
}
72+
err := json.Unmarshal(c.Creds.JSON, &svcAcct)
73+
if err != nil {
74+
return nil, err
75+
}
76+
77+
if svcAcct.PrivateKey != "" {
78+
pk, err := parseKey(svcAcct.PrivateKey)
6379
if err != nil {
6480
return nil, err
6581
}
6682
client.pk = pk
6783
}
84+
client.email = svcAcct.ClientEmail
6885
return client, nil
6986
}
7087

7188
// CustomToken creates a signed custom authentication token with the specified user ID. The resulting
72-
// JWT can be used in a Firebase client SDK to trigger an authentication flow.
89+
// JWT can be used in a Firebase client SDK to trigger an authentication flow. See
90+
// https://firebase.google.com/docs/auth/admin/create-custom-tokens#sign_in_using_custom_tokens_on_clients
91+
// for more details on how to use custom tokens for client authentication.
7392
func (c *Client) CustomToken(uid string) (string, error) {
74-
return c.CustomTokenWithClaims(uid, make(map[string]interface{}))
93+
return c.CustomTokenWithClaims(uid, nil)
7594
}
7695

7796
// CustomTokenWithClaims is similar to CustomToken, but in addition to the user ID, it also encodes
@@ -117,7 +136,9 @@ func (c *Client) CustomTokenWithClaims(uid string, devClaims map[string]interfac
117136
//
118137
// VerifyIDToken accepts a signed JWT token string, and verifies that it is current, issued for the
119138
// correct Firebase project, and signed by the Google Firebase services in the cloud. It returns
120-
// a Token containing the decoded claims in the input JWT.
139+
// a Token containing the decoded claims in the input JWT. See
140+
// https://firebase.google.com/docs/auth/admin/verify-id-tokens#retrieve_id_tokens_on_clients for
141+
// more details on how to obtain an ID token in a client app.
121142
func (c *Client) VerifyIDToken(idToken string) (*Token, error) {
122143
if c.projectID == "" {
123144
return nil, errors.New("project id not available")
@@ -171,14 +192,15 @@ func (c *Client) VerifyIDToken(idToken string) (*Token, error) {
171192
return p, nil
172193
}
173194

174-
func parseKey(key []byte) (*rsa.PrivateKey, error) {
175-
block, _ := pem.Decode(key)
176-
if block != nil {
177-
key = block.Bytes
195+
func parseKey(key string) (*rsa.PrivateKey, error) {
196+
block, _ := pem.Decode([]byte(key))
197+
if block == nil {
198+
return nil, fmt.Errorf("no private key data found in: %v", key)
178199
}
179-
parsedKey, err := x509.ParsePKCS8PrivateKey(key)
200+
k := block.Bytes
201+
parsedKey, err := x509.ParsePKCS8PrivateKey(k)
180202
if err != nil {
181-
parsedKey, err = x509.ParsePKCS1PrivateKey(key)
203+
parsedKey, err = x509.ParsePKCS1PrivateKey(k)
182204
if err != nil {
183205
return nil, fmt.Errorf("private key should be a PEM or plain PKSC1 or PKCS8; parse error: %v", err)
184206
}

0 commit comments

Comments
 (0)