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:
- Posting the form issues
?Cmd=RecoverPassword - If a recovery email is sent (or the account isn’t found - handled the same way for privacy), the next
GETcan show a success message
If the request contains a RecoveryToken query parameter (from the email link), the app renders a change password form:
- Posting that form issues
?Cmd=ChangePassword - The app validates the new password against complexity and reuse rules, and either shows an error or completes the reset
- 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

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
- Reset password: choose a Razor template from
- 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=RecoverPasswordwith 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 whenIsNewUser=trueis 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.