@@ -46,15 +46,15 @@ func (c *Client) setHeader(ic identitytoolkitCall) {
46
46
47
47
// UserInfo is a collection of standard profile information for a user.
48
48
type UserInfo struct {
49
- DisplayName string
50
- Email string
51
- PhoneNumber string
52
- PhotoURL string
49
+ DisplayName string `json:"displayName,omitempty"`
50
+ Email string `json:"email,omitempty"`
51
+ PhoneNumber string `json:"phoneNumber,omitempty"`
52
+ PhotoURL string `json:"photoUrl,omitempty"`
53
53
// In the ProviderUserInfo[] ProviderID can be a short domain name (e.g. google.com),
54
54
// or the identity of an OpenID identity provider.
55
55
// In UserRecord.UserInfo it will return the constant string "firebase".
56
- ProviderID string
57
- UID string
56
+ ProviderID string `json:"providerId,omitempty"`
57
+ UID string `json:"rawId,omitempty"`
58
58
}
59
59
60
60
// UserMetadata contains additional metadata associated with a user account.
@@ -350,39 +350,6 @@ func (c *Client) DeleteUser(ctx context.Context, uid string) error {
350
350
return nil
351
351
}
352
352
353
- // GetUser gets the user data corresponding to the specified user ID.
354
- func (c * Client ) GetUser (ctx context.Context , uid string ) (* UserRecord , error ) {
355
- if err := validateUID (uid ); err != nil {
356
- return nil , err
357
- }
358
- request := & identitytoolkit.IdentitytoolkitRelyingpartyGetAccountInfoRequest {
359
- LocalId : []string {uid },
360
- }
361
- return c .getUser (ctx , request )
362
- }
363
-
364
- // GetUserByPhoneNumber gets the user data corresponding to the specified user phone number.
365
- func (c * Client ) GetUserByPhoneNumber (ctx context.Context , phone string ) (* UserRecord , error ) {
366
- if err := validatePhone (phone ); err != nil {
367
- return nil , err
368
- }
369
- request := & identitytoolkit.IdentitytoolkitRelyingpartyGetAccountInfoRequest {
370
- PhoneNumber : []string {phone },
371
- }
372
- return c .getUser (ctx , request )
373
- }
374
-
375
- // GetUserByEmail gets the user data corresponding to the specified email.
376
- func (c * Client ) GetUserByEmail (ctx context.Context , email string ) (* UserRecord , error ) {
377
- if err := validateEmail (email ); err != nil {
378
- return nil , err
379
- }
380
- request := & identitytoolkit.IdentitytoolkitRelyingpartyGetAccountInfoRequest {
381
- Email : []string {email },
382
- }
383
- return c .getUser (ctx , request )
384
- }
385
-
386
353
// RevokeRefreshTokens revokes all refresh tokens issued to a user.
387
354
//
388
355
// RevokeRefreshTokens updates the user's TokensValidAfterMillis to the current UTC second.
@@ -611,32 +578,6 @@ func (c *Client) updateUser(ctx context.Context, uid string, user *UserToUpdate)
611
578
return nil
612
579
}
613
580
614
- func (c * Client ) getUser (ctx context.Context , request * identitytoolkit.IdentitytoolkitRelyingpartyGetAccountInfoRequest ) (* UserRecord , error ) {
615
- call := c .is .Relyingparty .GetAccountInfo (request )
616
- c .setHeader (call )
617
- resp , err := call .Context (ctx ).Do ()
618
- if err != nil {
619
- return nil , handleServerError (err )
620
- }
621
- if len (resp .Users ) == 0 {
622
- var msg string
623
- if len (request .LocalId ) == 1 {
624
- msg = fmt .Sprintf ("cannot find user from uid: %q" , request .LocalId [0 ])
625
- } else if len (request .Email ) == 1 {
626
- msg = fmt .Sprintf ("cannot find user from email: %q" , request .Email [0 ])
627
- } else {
628
- msg = fmt .Sprintf ("cannot find user from phone number: %q" , request .PhoneNumber [0 ])
629
- }
630
- return nil , internal .Error (userNotFound , msg )
631
- }
632
-
633
- eu , err := makeExportedUser (resp .Users [0 ])
634
- if err != nil {
635
- return nil , err
636
- }
637
- return eu .UserRecord , nil
638
- }
639
-
640
581
const idToolkitEndpoint = "https://identitytoolkit.googleapis.com/v1/projects"
641
582
642
583
// userManagementClient is a helper for interacting with the Identity Toolkit REST API.
@@ -652,6 +593,146 @@ type userManagementClient struct {
652
593
httpClient * internal.HTTPClient
653
594
}
654
595
596
+ // GetUser gets the user data corresponding to the specified user ID.
597
+ func (c * userManagementClient ) GetUser (ctx context.Context , uid string ) (* UserRecord , error ) {
598
+ return c .getUser (ctx , & userQuery {
599
+ field : "localId" ,
600
+ value : uid ,
601
+ label : "uid" ,
602
+ })
603
+ }
604
+
605
+ // GetUserByEmail gets the user data corresponding to the specified email.
606
+ func (c * userManagementClient ) GetUserByEmail (ctx context.Context , email string ) (* UserRecord , error ) {
607
+ if err := validateEmail (email ); err != nil {
608
+ return nil , err
609
+ }
610
+ return c .getUser (ctx , & userQuery {
611
+ field : "email" ,
612
+ value : email ,
613
+ })
614
+ }
615
+
616
+ // GetUserByPhoneNumber gets the user data corresponding to the specified user phone number.
617
+ func (c * userManagementClient ) GetUserByPhoneNumber (ctx context.Context , phone string ) (* UserRecord , error ) {
618
+ if err := validatePhone (phone ); err != nil {
619
+ return nil , err
620
+ }
621
+ return c .getUser (ctx , & userQuery {
622
+ field : "phoneNumber" ,
623
+ value : phone ,
624
+ label : "phone number" ,
625
+ })
626
+ }
627
+
628
+ type userQuery struct {
629
+ field string
630
+ value string
631
+ label string
632
+ }
633
+
634
+ func (q * userQuery ) description () string {
635
+ label := q .label
636
+ if label == "" {
637
+ label = q .field
638
+ }
639
+ return fmt .Sprintf ("%s: %q" , label , q .value )
640
+ }
641
+
642
+ func (q * userQuery ) build () map [string ]interface {} {
643
+ return map [string ]interface {}{
644
+ q .field : []string {q .value },
645
+ }
646
+ }
647
+
648
+ func (c * userManagementClient ) getUser (ctx context.Context , query * userQuery ) (* UserRecord , error ) {
649
+ resp , err := c .post (ctx , "/accounts:lookup" , query .build ())
650
+ if err != nil {
651
+ return nil , err
652
+ }
653
+
654
+ if resp .Status != http .StatusOK {
655
+ return nil , handleHTTPError (resp )
656
+ }
657
+
658
+ var parsed struct {
659
+ Users []* userQueryResponse `json:"users"`
660
+ }
661
+ if err := json .Unmarshal (resp .Body , & parsed ); err != nil {
662
+ return nil , err
663
+ }
664
+
665
+ if len (parsed .Users ) == 0 {
666
+ return nil , internal .Errorf (userNotFound , "cannot find user from %s" , query .description ())
667
+ }
668
+
669
+ return parsed .Users [0 ].makeUserRecord ()
670
+ }
671
+
672
+ type userQueryResponse struct {
673
+ UID string `json:"localId,omitempty"`
674
+ DisplayName string `json:"displayName,omitempty"`
675
+ Email string `json:"email,omitempty"`
676
+ PhoneNumber string `json:"phoneNumber,omitempty"`
677
+ PhotoURL string `json:"photoUrl,omitempty"`
678
+ CreationTimestamp int64 `json:"createdAt,string,omitempty"`
679
+ LastLogInTimestamp int64 `json:"lastLoginAt,string,omitempty"`
680
+ ProviderID string `json:"providerId,omitempty"`
681
+ CustomAttributes string `json:"customAttributes,omitempty"`
682
+ Disabled bool `json:"disabled,omitempty"`
683
+ EmailVerified bool `json:"emailVerified,omitempty"`
684
+ ProviderUserInfo []* UserInfo `json:"providerUserInfo,omitempty"`
685
+ PasswordHash string `json:"passwordHash,omitempty"`
686
+ PasswordSalt string `json:"salt,omitempty"`
687
+ ValidSinceSeconds int64 `json:"validSince,string,omitempty"`
688
+ }
689
+
690
+ func (r * userQueryResponse ) makeUserRecord () (* UserRecord , error ) {
691
+ exported , err := r .makeExportedUserRecord ()
692
+ if err != nil {
693
+ return nil , err
694
+ }
695
+
696
+ return exported .UserRecord , nil
697
+ }
698
+
699
+ func (r * userQueryResponse ) makeExportedUserRecord () (* ExportedUserRecord , error ) {
700
+ var customClaims map [string ]interface {}
701
+ if r .CustomAttributes != "" {
702
+ err := json .Unmarshal ([]byte (r .CustomAttributes ), & customClaims )
703
+ if err != nil {
704
+ return nil , err
705
+ }
706
+ if len (customClaims ) == 0 {
707
+ customClaims = nil
708
+ }
709
+ }
710
+
711
+ return & ExportedUserRecord {
712
+ UserRecord : & UserRecord {
713
+ UserInfo : & UserInfo {
714
+ DisplayName : r .DisplayName ,
715
+ Email : r .Email ,
716
+ PhoneNumber : r .PhoneNumber ,
717
+ PhotoURL : r .PhotoURL ,
718
+ UID : r .UID ,
719
+ ProviderID : defaultProviderID ,
720
+ },
721
+ CustomClaims : customClaims ,
722
+ Disabled : r .Disabled ,
723
+ EmailVerified : r .EmailVerified ,
724
+ ProviderUserInfo : r .ProviderUserInfo ,
725
+ TokensValidAfterMillis : r .ValidSinceSeconds * 1000 ,
726
+ UserMetadata : & UserMetadata {
727
+ LastLogInTimestamp : r .LastLogInTimestamp ,
728
+ CreationTimestamp : r .CreationTimestamp ,
729
+ },
730
+ },
731
+ PasswordHash : r .PasswordHash ,
732
+ PasswordSalt : r .PasswordSalt ,
733
+ }, nil
734
+ }
735
+
655
736
// SessionCookie creates a new Firebase session cookie from the given ID token and expiry
656
737
// duration. The returned JWT can be set as a server-side session cookie with a custom cookie
657
738
// policy. Expiry duration must be at least 5 minutes but may not exceed 14 days.
0 commit comments