Table of Contents

Forgot Password

Recover password in frontend

The Users - Forgot Password app provides a two‑step flow for password resets. Anonymous visitors request a reset link by entering their email or username. The app sends an email containing a time‑limited recovery token that opens a page where the user can set a new password.

Note

Template locations:

  • Reset template: /Templates/Users/UserForgotPassword/Reset
  • Change password template: /Templates/Users/UserForgotPassword/Change
  • Email template: /Templates/Users/UserForgotPassword/Email

What the app does

When the app runs and the user is not signed in, it renders a reset password form:

  1. Posting the form issues ?Cmd=RecoverPassword
  2. If a recovery email is sent (or the account isn’t found - handled the same way for privacy), the next GET can show a success message

If the request contains a RecoveryToken query parameter (from the email link), the app renders a change password form:

  1. Posting that form issues ?Cmd=ChangePassword
  2. The app validates the new password against complexity and reuse rules, and either shows an error or completes the reset
  3. If configured, a successful change redirects to your Login page.

The template receives a UserForgotPasswordViewModel with:

  • Result – the outcome of the most recent operation.

Paragraph app settings

User recover password

From the paragraph app you have these settings:

  • Templates
    • Reset password: choose a Razor template from /Templates/Users/UserForgotPassword/Reset
    • Change password: choose a Razor template from /Templates/Users/UserForgotPassword/Change
    • Email template: choose a Razor template from /Templates/Users/UserForgotPassword/Email
  • Email
    • Sender name, Sender email, Email subject
  • Pages
    • Page to login (used as the redirect target after a successful password change)

Reset template

Place a .cshtml file in /Templates/Users/UserForgotPassword/Reset. The template should inherit ViewModelTemplate<UserForgotPasswordViewModel> and import the Dynamicweb.Users.Frontend.UserForgotPassword namespace.

Minimal example

@inherits ViewModelTemplate<Dynamicweb.Users.Frontend.UserForgotPassword.UserForgotPasswordViewModel>
@using Dynamicweb
@using Dynamicweb.Rendering
@using Dynamicweb.Users.Frontend.UserForgotPassword

@{
  var recoverAction = Model.GetRecoverPasswordLink(Pageview.Page.ID);
}

<!-- Create a form that sends an email with a link for creating a new password -->
<form method="post" action="@recoverAction">
  <div class="form-control">
    <label for="Email">Email</label>
    <input type="email" id="Email" name="Email" />
  </div>

  <div class="form-control">
    <label for="Username">Username</label>
    <input type="text" id="Username" name="Username" />
  </div>

  <button type="submit" id="PasswordRecoveryButton">Send password link</button>

  <!-- Use the UserForgotPasswordResultType property to display the form result to the user -->
  @if (Model.Result != Dynamicweb.Users.Frontend.UserForgotPassword.UserForgotPasswordResultType.None) {
    <p class="form-message">@Translate(Model.Result.ToString())</p>
  }
</form>
Tip

Either Email or Username must be provided. The UI can show both fields; the module accepts either.

Change password template

Place a .cshtml file in /Templates/Users/UserForgotPassword/Change. The template should inherit ViewModelTemplate<UserForgotPasswordViewModel> and import the same namespace. The page is reached via the emailed link and includes a RecoveryToken query parameter.

Minimal example

@inherits ViewModelTemplate<Dynamicweb.Users.Frontend.UserForgotPassword.UserForgotPasswordViewModel>
@using Dynamicweb
@using Dynamicweb.Rendering
@using Dynamicweb.Users.Frontend.UserForgotPassword

@{
  var changeAction = Model.GetChangePasswordLink(Pageview.Page.ID);
}

<form method="post" action="@changeAction">
  <div class="form-control">
    <label for="NewPassword">New password</label>
    <input type="password" id="NewPassword" name="NewPassword" autocomplete="new-password" required />
  </div>

  <div class="form-control">
    <label for="ConfirmNewPassword">Confirm new password</label>
    <input type="password" id="ConfirmNewPassword" name="ConfirmNewPassword" autocomplete="new-password" required />
  </div>

  <!-- Optional: if you also use this page to activate newly created accounts-->
  <input type="hidden" name="IsNewUser" value="true" /> 

  <button type="submit" id="ChangePassword">Change password</button>

  @if (Model.Result != Dynamicweb.Users.Frontend.UserForgotPassword.UserForgotPasswordResultType.None) {
    <p class="form-message">@Translate(Model.Result.ToString())</p>
  }
</form>

Email template

Place a .cshtml file in /Templates/Users/UserForgotPassword/Email. Inherit ViewModelTemplate<UserPasswordRecoveryEmailViewModel>. The model exposes User and a RecoveryLink back to your Change password page.

@inherits ViewModelTemplate<Dynamicweb.Frontend.UserPasswordRecoveryEmailViewModel>
@using Dynamicweb.Rendering

<h2>Password recovery</h2>

@if (!string.IsNullOrWhiteSpace(Model.RecoveryLink))
{   
    <p>
        Hi @Model.User.UserName
        We have received a request to set your password for your account.
        Click on the link below to set a new password.
    </p>
    <!-- Provide the recovery link -->
    <a href="@Model.RecoveryLink">Create new password</a>
    <p>
        If you didn't ask to set your password, ignore this email and your password will not be changed.
    </p>
}

Handling results in your template

Use Model.Result to show success or specific validation errors.

@switch (Model.Result)
{
  case Dynamicweb.Users.Frontend.UserForgotPassword.UserForgotPasswordResultType.None:
    break;
  case Dynamicweb.Users.Frontend.UserForgotPassword.UserForgotPasswordResultType.MissingValue:
    <div class="error">Please enter your email or username.</div>
    break;
  case Dynamicweb.Users.Frontend.UserForgotPassword.UserForgotPasswordResultType.PasswordNotDifferent:
    <div class="error">Your new password must be different from the current password.</div>
    break;
  case Dynamicweb.Users.Frontend.UserForgotPassword.UserForgotPasswordResultType.MismatchedPasswords:
    <div class="error">The passwords do not match.</div>
    break;
  case Dynamicweb.Users.Frontend.UserForgotPassword.UserForgotPasswordResultType.InvalidPasswordLength:
    <div class="error">Password length is invalid.</div>
    break;
  case Dynamicweb.Users.Frontend.UserForgotPassword.UserForgotPasswordResultType.InvalidPasswordComplexity:
    <div class="error">Password does not meet the complexity requirements.</div>
    break;
  case Dynamicweb.Users.Frontend.UserForgotPassword.UserForgotPasswordResultType.MustContainNumbersAndCharacters:
    <div class="error">Password must contain both letters and numbers.</div>
    break;
  case Dynamicweb.Users.Frontend.UserForgotPassword.UserForgotPasswordResultType.PasswordMissingCharacterVariety:
    <div class="error">Use uppercase, lowercase, numbers, and special characters.</div>
    break;
  case Dynamicweb.Users.Frontend.UserForgotPassword.UserForgotPasswordResultType.RecoveryTokenExpired:
    <div class="error">Your recovery link has expired. Request a new email.</div>
    break;
  case Dynamicweb.Users.Frontend.UserForgotPassword.UserForgotPasswordResultType.ViolatingReuseRules:
    <div class="error">This password was used recently. Choose a different one.</div>
    break;
  case Dynamicweb.Users.Frontend.UserForgotPassword.UserForgotPasswordResultType.Success:
    <div class="success">Success. Check your inbox or sign in with your new password.</div>
    break;
}

How the flow works

  • Reset step: POST ?Cmd=RecoverPassword with an email or username. If a matching user exists, the app saves a time‑limited recovery token and sends an email. For security, the response is the same whether the user exists or not.
  • Change step: Follow the emailed link (includes RecoveryToken). On POST ?Cmd=ChangePassword, the app validates the new password and, on success, expires the token and (optionally) activates the account when IsNewUser=true is posted.
  • Redirect after success: If a Login page is configured, a successful change redirects there (with a success flag in the URL); otherwise a success message is rendered on the page.
To top