1
+ // Package auth contains functions for minting custom authentication tokens, and verifying Firebase ID tokens.
1
2
package auth
2
3
3
4
import (
5
+ "encoding/json"
4
6
"encoding/pem"
5
7
"errors"
6
8
"fmt"
@@ -15,7 +17,6 @@ import (
15
17
const firebaseAudience = "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit"
16
18
const googleCertURL = "https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com"
17
19
const issuerPrefix = "https://securetoken.google.com/"
18
- const gcloudProject = "GCLOUD_PROJECT"
19
20
const tokenExpSeconds = 3600
20
21
21
22
var reservedClaims = []string {
@@ -54,24 +55,42 @@ type Client struct {
54
55
// NewClient creates a new instance of the Firebase Auth Client.
55
56
//
56
57
// 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.
58
59
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 )
63
79
if err != nil {
64
80
return nil , err
65
81
}
66
82
client .pk = pk
67
83
}
84
+ client .email = svcAcct .ClientEmail
68
85
return client , nil
69
86
}
70
87
71
88
// 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.
73
92
func (c * Client ) CustomToken (uid string ) (string , error ) {
74
- return c .CustomTokenWithClaims (uid , make ( map [ string ] interface {}) )
93
+ return c .CustomTokenWithClaims (uid , nil )
75
94
}
76
95
77
96
// 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
117
136
//
118
137
// VerifyIDToken accepts a signed JWT token string, and verifies that it is current, issued for the
119
138
// 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.
121
142
func (c * Client ) VerifyIDToken (idToken string ) (* Token , error ) {
122
143
if c .projectID == "" {
123
144
return nil , errors .New ("project id not available" )
@@ -171,14 +192,15 @@ func (c *Client) VerifyIDToken(idToken string) (*Token, error) {
171
192
return p , nil
172
193
}
173
194
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 )
178
199
}
179
- parsedKey , err := x509 .ParsePKCS8PrivateKey (key )
200
+ k := block .Bytes
201
+ parsedKey , err := x509 .ParsePKCS8PrivateKey (k )
180
202
if err != nil {
181
- parsedKey , err = x509 .ParsePKCS1PrivateKey (key )
203
+ parsedKey , err = x509 .ParsePKCS1PrivateKey (k )
182
204
if err != nil {
183
205
return nil , fmt .Errorf ("private key should be a PEM or plain PKSC1 or PKCS8; parse error: %v" , err )
184
206
}
0 commit comments