Email & password management
This pack adds an account settings area where signed-in users manage their own account. They update their name and email on a profile page and change their password on a security page.
- A pending email change can be resent or cancelled from the profile page, and the account keeps signing in with its confirmed address until then.
- A branded, MJML change-email message that names both the old and the new address.
This pack extends the auth pack's User model and reuses its email-verification flow. Apply the auth pack first.
Apply the email & password management pack with Flow. Start a new session in your selected coding agent and execute the following slash command inside it.
After applying, Flow will make the following changes to your app.
-
Reuse your account settings area to host the profile and security pages, or establish one when you have none.
-
Land the backend as shipped, from the profile, security, and account-password controllers through the validators, the change-email mailer and template, the resend branch, and the routes.
-
Restyle the profile and security pages to your design system.
-
Run the tests, then walk the profile update, email change, and password change and show you the result.
Apply the email & password management pack to your app by hand by working through the steps below in order. It builds on the auth pack, adding a profile and a security page to your account settings so signed-in users can update their name and email and change their password.
-
Confirm your auth foundation
This pack builds on the auth pack. Make sure your app already has it before continuing.
- Your User model composes
withAuthFinder(...)andwithManagedEmail(). - The email-verification flow is wired: the
account_activation_provisionmailer and theemailLayoutemail component exist, mail is configured, and theemail_verifications.showandemail_verifications.updateroutes resolve. - A web session guard and the
authnamed middleware are registered.
- Your User model composes
Flow adapts the pack to your app, so the exact set of created and edited files depends on what you already have. This is the shape of an apply onto the hypermedia starter kit with the auth pack in place.
Configuration
The change-email link is backed by the withManagedEmail() mixin on the User model, the same mixin auth composes. It mints each verification token and stores it in a database table. Pass an options object to the mixin to change its defaults.
expiresIn
How long a change-email link stays valid, as a number of seconds or a time expression. Defaults to 1 day.
table
The table verification tokens are read from and written to. Defaults to email_verification_tokens.
tokenSecretLength
The length of the random secret behind each token. Defaults to 40.
export default class User extends compose(
UserSchema,
withAuthFinder(hash),
withManagedEmail({ expiresIn: '2 hours' })
) {}
Changing an email keeps the old one active
An account carries two addresses. email is the confirmed one that signs the user in, and unverifiedEmail holds a change still waiting on confirmation. Submitting a new email writes it to unverifiedEmail and sends the change-email message there, while the confirmed address goes on working for login until the new one is confirmed.
Submitting the current confirmed email while a change is pending reverts it. The pending address is cleared and no mail is sent, which is what cancelling a pending change relies on. Because the uniqueness check ignores the user's own row, resubmitting an unchanged email is never a duplicate.
A pending change can also be resent, throttled to one message a minute. Inside that window the request does nothing and answers as it would have, so the timing stays invisible.
A password change needs the current password
The change verifies the current password with a constant-time comparison before setting the new one. A wrong current password is rejected and nothing changes. Assigning the new password re-hashes it on save, so only the hash is ever stored.
1.0.0
Initial release.