Repository: firebase/firebase-admin-go (go)

Issue:
BUG: UpdateUser() is not able to update MFA
### Describe your environment

  * Operating System version: Mac OS Ventura 13.0.1
  * Firebase SDK version: Firebase Admin SDK v4
  * Library version: v4.10.0
  * Firebase Product: auth

### Describe the problem

It's not possible to update multi factor enrollments with `UpdateUser()` function. Create and update API requests have different structure when we speaking about MFA (don't know who thought it will be cool to do that). It's also not required to pass fields like `UID` or `DisplayName` when updating or creating MFA.

We can see the valid implementation in the [firebase-admin-node repository](https://github.com/firebase/firebase-admin-node/blob/b2a28aee5cac172ed183bc47f71a55b31f79696a/test/unit/auth/auth-api-request.spec.ts#L2034)

#### Steps to reproduce:

1. Create user (or have existing firebase user) without MFA
2. Try to add MFA with `UpdateUser`
3. Nothing will happen, used will not have MFA after update

#### Relevant Code:

```go
// 1. Create user
createParams := (&auth.UserToCreate{}).
		UID("01GM6YCBT7T0VNPNTCP44S7E8G").
		Email("john@doe.com").
		EmailVerified(true).
		Password("secret").
		DisplayName("John Doe").
		Disabled(false).
                MFASettings(auth.MultiFactorSettings{EnrolledFactors: nil})

user, err := firebaseAuth.CreateUser(ctx, params)
require.NoError(t, err)

// 2. Update user
updateParams := (&auth.UserToUpdate{}).
		MFASettings(auth.MultiFactorSettings{
			EnrolledFactors: []*auth.MultiFactorInfo{{
                                // problems will arise even on this stage
                                // because library things that it's required to pass UID and DisplayName
				FactorID:    "phone",
				PhoneNumber: "+16505557348",
			}},
		})

user, err = firebaseAuth.UpdateUser(ctx, user.UID, params)
assert.NoError(t, err)
assert.Len(t, user.MultiFactor.EnrolledFactors, 1)
```


Pull request:
fix(auth): Allow to update MFA 
- `UpdateUser` can update MFA
- `UID` is not required when updating MFA
- `DisplayName` is not required field

Fixes #529.

RELEASE NOTE: Allow updating multi factor enrollments in `UpdateUser()` API

Patch:
diff --git a/auth/user_mgt.go b/auth/user_mgt.go
index fe6ac98..338a976 100644
--- a/auth/user_mgt.go
+++ b/auth/user_mgt.go
@@ -68,6 +68,10 @@ type multiFactorInfoResponse struct {
 	EnrolledAt      string `json:"enrolledAt,omitempty"`
 }
 
+type multiFactorEnrollments struct {
+	Enrollments []*multiFactorInfoResponse `json:"enrollments"`
+}
+
 // MultiFactorInfo describes a user enrolled second phone factor.
 // TODO : convert PhoneNumber to PhoneMultiFactorInfo struct
 type MultiFactorInfo struct {
@@ -166,18 +170,19 @@ func (u *UserToCreate) set(key string, value interface{}) *UserToCreate {
 
 // Converts a client format second factor object to server format.
 func convertMultiFactorInfoToServerFormat(mfaInfo MultiFactorInfo) (multiFactorInfoResponse, error) {
-	var authFactorInfo multiFactorInfoResponse
+	authFactorInfo := multiFactorInfoResponse{DisplayName: mfaInfo.DisplayName}
 	if mfaInfo.EnrollmentTimestamp != 0 {
 		authFactorInfo.EnrolledAt = time.Unix(mfaInfo.EnrollmentTimestamp, 0).Format("2006-01-02T15:04:05Z07:00Z")
 	}
+	if mfaInfo.UID != "" {
+		authFactorInfo.MFAEnrollmentID = mfaInfo.UID
+	}
 	if mfaInfo.FactorID == phoneMultiFactorID {
 		authFactorInfo.PhoneInfo = mfaInfo.PhoneNumber
-		authFactorInfo.DisplayName = mfaInfo.DisplayName
-		authFactorInfo.MFAEnrollmentID = mfaInfo.UID
 		return authFactorInfo, nil
 	}
 	out, _ := json.Marshal(mfaInfo)
-	return multiFactorInfoResponse{}, fmt.Errorf("Unsupported second factor %s provided", string(out))
+	return multiFactorInfoResponse{}, fmt.Errorf("unsupported second factor %s provided", string(out))
 }
 
 func (u *UserToCreate) validatedRequest() (map[string]interface{}, error) {
@@ -333,7 +338,9 @@ func (u *UserToUpdate) validatedRequest() (map[string]interface{}, error) {
 			if err != nil {
 				return nil, err
 			}
-			req["mfaInfo"] = mfaInfo
+
+			// https://cloud.google.com/identity-platform/docs/reference/rest/v1/accounts/update
+			req["mfa"] = multiFactorEnrollments{mfaInfo}
 		} else {
 			req[k] = v
 		}
@@ -665,9 +672,6 @@ func validateAndFormatMfaSettings(mfaSettings MultiFactorSettings, methodType st
 				return nil, fmt.Errorf("\"uid\" is not supported when adding second factors via \"createUser()\"")
 			}
 		case updateUserMethod:
-			if multiFactorInfo.UID == "" {
-				return nil, fmt.Errorf("the second factor \"uid\" must be a valid non-empty string when adding second factors via \"updateUser()\"")
-			}
 		default:
 			return nil, fmt.Errorf("unsupported methodType: %s", methodType)
 		}


Test patch:
diff --git a/auth/user_mgt_test.go b/auth/user_mgt_test.go
index 943810c..5143a2f 100644
--- a/auth/user_mgt_test.go
+++ b/auth/user_mgt_test.go
@@ -894,17 +894,6 @@ func TestInvalidUpdateUser(t *testing.T) {
 				},
 			}),
 			`the second factor "phoneNumber" for "invalid" must be a non-empty E.164 standard compliant identifier string`,
-		}, {
-			(&UserToUpdate{}).MFASettings(MultiFactorSettings{
-				EnrolledFactors: []*MultiFactorInfo{
-					{
-						PhoneNumber: "+11234567890",
-						FactorID:    "phone",
-						DisplayName: "Spouse's phone number",
-					},
-				},
-			}),
-			`the second factor "uid" must be a valid non-empty string when adding second factors via "updateUser()"`,
 		}, {
 			(&UserToUpdate{}).ProviderToLink(&UserProvider{UID: "google_uid"}),
 			"user provider must specify a provider ID",
@@ -1059,10 +1048,14 @@ var updateUserCases = []struct {
 					PhoneNumber: "+11234567890",
 					DisplayName: "Spouse's phone number",
 					FactorID:    "phone",
+				}, {
+					PhoneNumber: "+11234567890",
+					DisplayName: "Spouse's phone number",
+					FactorID:    "phone",
 				},
 			},
 		}),
-		map[string]interface{}{"mfaInfo": []*multiFactorInfoResponse{
+		map[string]interface{}{"mfa": multiFactorEnrollments{Enrollments: []*multiFactorInfoResponse{
 			{
 				MFAEnrollmentID: "enrolledSecondFactor1",
 				PhoneInfo:       "+11234567890",
@@ -1074,12 +1067,16 @@ var updateUserCases = []struct {
 				DisplayName:     "Spouse's phone number",
 				PhoneInfo:       "+11234567890",
 			},
-		},
+			{
+				DisplayName: "Spouse's phone number",
+				PhoneInfo:   "+11234567890",
+			},
+		}},
 		},
 	},
 	{
 		(&UserToUpdate{}).MFASettings(MultiFactorSettings{}),
-		map[string]interface{}{"mfaInfo": nil},
+		map[string]interface{}{"mfa": multiFactorEnrollments{Enrollments: nil}},
 	},
 	{
 		(&UserToUpdate{}).ProviderToLink(&UserProvider{