feat: password reset

This commit is contained in:
2026-05-04 08:33:45 +02:00
parent 2c2459c833
commit 0bbc76be1d
5 changed files with 190 additions and 4 deletions
+74
View File
@@ -166,3 +166,77 @@ func (app *application) activateUserHandler(w http.ResponseWriter, r *http.Reque
app.serverErrorResponse(w, r, err)
}
}
// Verify the password reset token and set a new password for the user.
func (app *application) updateUserPasswordHandler(w http.ResponseWriter, r *http.Request) {
// Parse and validate the user's new password and password reset token.
var input struct {
Password string `json:"password"`
TokenPlaintext string `json:"token"`
}
err := app.readJSON(w, r, &input)
if err != nil {
app.badRequestResponse(w, r, err)
return
}
v := validator.New()
data.ValidatePasswordPlaintext(v, input.Password)
data.ValidateTokenPlaintext(v, input.TokenPlaintext)
if !v.Valid() {
app.failedValidationResponse(w, r, v.Errors)
return
}
// Retrieve the details of the user associated with the password reset token,
// returning an error message if no matching record was found.
user, err := app.models.Users.GetForToken(data.ScopePasswordReset, input.TokenPlaintext)
if err != nil {
switch {
case errors.Is(err, data.ErrRecordNotFound):
v.AddError("token", "invalid or expired password reset token")
app.failedValidationResponse(w, r, v.Errors)
default:
app.serverErrorResponse(w, r, err)
}
return
}
// Set the new password for the user.
err = user.Password.Set(input.Password)
if err != nil {
app.serverErrorResponse(w, r, err)
return
}
// Save the updated user record in our database, checking for any edit conflicts as
// normal.
err = app.models.Users.Update(user)
if err != nil {
switch {
case errors.Is(err, data.ErrEditConflict):
app.editConflictResponse(w, r)
default:
app.serverErrorResponse(w, r, err)
}
return
}
// If everything was successful, then delete all password reset tokens for the user.
err = app.models.Tokens.DeleteAllForUser(data.ScopePasswordReset, user.ID)
if err != nil {
app.serverErrorResponse(w, r, err)
return
}
// Send the user a confirmation message.
env := envelope{"message": "your password was successfully reset"}
err = app.writeJSON(w, http.StatusOK, env, nil)
if err != nil {
app.serverErrorResponse(w, r, err)
}
}