MCPcopy Create free account
hub / github.com/supabase/auth / enrollPhoneFactor

Method enrollPhoneFactor

internal/api/mfa.go:137–196  ·  view source on GitHub ↗
(w http.ResponseWriter, r *http.Request, params *EnrollFactorParams)

Source from the content-addressed store, hash-verified

135}
136
137func (a *API) enrollPhoneFactor(w http.ResponseWriter, r *http.Request, params *EnrollFactorParams) error {
138 ctx := r.Context()
139 config := a.config
140 user := getUser(ctx)
141 session := getSession(ctx)
142 db := a.db.WithContext(ctx)
143 if params.Phone == "" {
144 return apierrors.NewBadRequestError(apierrors.ErrorCodeValidationFailed, "Phone number required to enroll Phone factor")
145 }
146
147 phone, err := validatePhone(params.Phone)
148 if err != nil {
149 return apierrors.NewBadRequestError(apierrors.ErrorCodeValidationFailed, "Invalid phone number format (E.164 required)")
150 }
151
152 var factorsToDelete []models.Factor
153 for _, factor := range user.Factors {
154 if factor.IsPhoneFactor() && factor.Phone.String() == phone {
155 if factor.IsVerified() {
156 return apierrors.NewUnprocessableEntityError(
157 apierrors.ErrorCodeMFAVerifiedFactorExists,
158 "A verified phone factor already exists, unenroll the existing factor to continue",
159 )
160 } else if factor.IsUnverified() {
161 factorsToDelete = append(factorsToDelete, factor)
162 }
163 }
164 }
165
166 if err := db.Destroy(&factorsToDelete); err != nil {
167 return apierrors.NewInternalServerError("Database error deleting unverified phone factors").WithInternalError(err)
168 }
169
170 if err := validateFactors(db, user, params.FriendlyName, a.config, session); err != nil {
171 return err
172 }
173
174 factor := models.NewPhoneFactor(user, phone, params.FriendlyName)
175 err = db.Transaction(func(tx *storage.Connection) error {
176 if terr := tx.Create(factor); terr != nil {
177 return terr
178 }
179 if terr := models.NewAuditLogEntry(config.AuditLog, r, tx, user, models.EnrollFactorAction, utilities.GetIPAddress(r), map[string]interface{}{
180 "factor_id": factor.ID,
181 "factor_type": factor.FactorType,
182 }); terr != nil {
183 return terr
184 }
185 return nil
186 })
187 if err != nil {
188 return err
189 }
190 return sendJSON(w, http.StatusOK, &EnrollFactorResponse{
191 ID: factor.ID,
192 Type: models.Phone,
193 FriendlyName: factor.FriendlyName,
194 Phone: params.Phone,

Callers 1

EnrollFactorMethod · 0.95

Calls 15

NewBadRequestErrorFunction · 0.92
NewInternalServerErrorFunction · 0.92
NewPhoneFactorFunction · 0.92
NewAuditLogEntryFunction · 0.92
GetIPAddressFunction · 0.92
getUserFunction · 0.85
getSessionFunction · 0.85
validatePhoneFunction · 0.85
validateFactorsFunction · 0.85
sendJSONFunction · 0.85
WithContextMethod · 0.80

Tested by

no test coverage detected