Guide 07 · Developer docs

Members, accounts and gated content

Building a member area on Core dna: who a member is in the data, the sign-in flows and their templates, single sign-on and passkeys, the my-account routing convention, members-only content, sessions and the page cache, and the security checks to run before launch.

L2
Unit 02 · Registration, sign-in and password recovery

Forgotten and reset passwords

A member who has forgotten their password asks for a link, the emailed link signs them in, and they choose a new password. Both halves, the link's lifetime and number of uses, the reset email and how to override it, and what a reset changes on the account.

Who this is for. The theme developer building the two password pages and the reset email. Afterwards you can build both halves, brand the email, and answer "how long does the link work?"

Asking for a link

users/forgot-password.html, which you write, posts email to /forgot-password. The form is for signed-out visitors. Whatever address is entered, the visitor is redirected to /login with the same message:

"If a user account with the specified email address exists, a password reset link has been sent to it."

So the form never reveals whether an address has an account. Behind that message, an email is sent only when the address belongs to a person whose user is active. An empty field re-renders the form with "The email address needs to be specified".

The email holds a sign-in link, /token-login?t=…, built on a sign-in token made for the member (One-click sign-in links):

PropertyValue
Works forTwo days from the request
After its first useOne more hour, if that is sooner
UsesUp to ten, within those times
Lands on/reset-password

Following the link signs the member in, with a full session, and then shows the reset page. If they close the tab there, they are still signed in. The link is therefore a credential, equal to the password for as long as it works: never log it, forward it or show it anywhere but in the email (Personal data in logs, emails and the browser). A link that has expired or been used up sends the visitor to /login with "Could not login using token: The token has expired".

Setting the new password

users/reset-password.html, which you write, posts password and confirmPassword to /reset-password as a PUT, with the CSRF token, since the member is signed in by then. It does not ask for the current password, because the emailed link proved the member's identity. Link to this page only from that flow; everywhere else, a member changes a known password at /change-password (Changing a password).

On success the member is sent to their account with "The password has been successfully changed". The page receives localPasswordEnabled and passkeyEnabled; where passkeys are on, it is also where a member can add a passkey instead (Passkeys). Setting a password needs password sign-in to be enabled for the site.

A reset also changes the account:

  • Password sign-in is switched on for the member if they did not have it, so a member who only ever used Google can sign in with the new password from then on.
  • Their other signed-in sessions are ended, apart from a device kept signed in with Remember me, and the one the link started is kept.
Template code templates/users/forgot-password.html, the form
<form method="post" action="{$_url->getPath('forgotPassword')}">
  <label>Email address <input type="email" name="email" autocomplete="email" required></label>
  <button>Send me a link</button>
</form>
<p>The link works for two days. Not there? Check your spam folder, or <a href="/contact">contact us</a>.</p>
<form method="post" action="{{ _url.getPath('forgotPassword') }}">
  <label>Email address <input type="email" name="email" autocomplete="email" required></label>
  <button>Send me a link</button>
</form>
<p>The link works for two days. Not there? Check your spam folder, or <a href="/contact">contact us</a>.</p>

The reset email

The email's body is a file, looked for first in your site and then in the framework:

  • templates/users/emails/reset-password-smarty.html on a Smarty site. The framework ships one, branded "Core dna".
  • templates/users/emails/reset-password-twig.html on a Twig site. The framework ships none, so a Twig site must supply it.

The file is not rendered as a page template. It is read as it stands, and placeholders written as %name% are replaced:

PlaceholderReplaced with
%resetUrl%The sign-in link
%username%The member's username
%firstName%, %middleName%, %lastName%, %toName%, %email%The member's name, full name and email address
%hostname%The site's hostname
%recipient.*%Any of the member's own person fields (%recipient.firstName%, %recipient.email%, and so on)
%showInBrowserUrl%A link to view the email in the browser

A file that contains <body is sent as HTML; any other is sent as plain text. On a Twig site the placeholders are turned into Twig variables and the file is rendered with Twig, falling back to plain replacement if that fails, so keep Twig syntax out of the file unless you mean it.

The subject and sender are settings in the Users module, under Forgot password email in frontend. Their defaults name the platform, not the client, so change all three:

SettingDefault
SubjectCore dna: Password Reset
From emailno-reply@coredna.com
From nameCore dna DXP

Send from an address on the client's own domain, authenticated for sending, or the email is likely to be filtered as spam (The password reset email never arrives).

HTML templates/users/emails/reset-password-smarty.html, a minimal HTML version
<html>
<body>
  <p>Hello %firstName%,</p>
  <p>Someone asked to reset the password for your account, %username%. To choose a new password, open this link within two days:</p>
  <p><a href="%resetUrl%">Choose a new password</a></p>
  <p>If it was not you, ignore this email: your password has not changed.</p>
</body>
</html>
Go deeper

Was this page helpful?

Your answer goes to the docs team.