Skip to content

Password reset

Included free on every install.

Password reset is the "forgot password" flow for admin console accounts. A person asks for a reset with their email address, receives a link that works once for one hour, and sets a new password with it. Setting the new password signs the account out of every device.

StepWhat happens
RequestThe console posts the address to /api/admin/auth/password-reset/request. The answer is the same, in about the same time, whether or not the account exists. A new request cancels the account's earlier unused links.
EmailThe link <LYEVE_CONSOLE_URL>/reset-password?token=<token> is mailed.
ConfirmThe person chooses a new password of at least 12 characters, and the console sends it with the token.
Sign-outEvery session and refresh token the account held ends.

Password reset runs on every install. To deliver the email, give the instance a mail relay. With the email feature configured, the mail goes through it and is the tenant's password-reset template, so its wording and design are yours to change. See required templates. Otherwise the instance's own SMTP settings are used. Set LYEVE_CONSOLE_URL to the address people open the console at, such as https://admin.example.com. In production, password reset refuses to start without it.

With no relay configured, a request still answers 200 and no mail is sent. The server log records that a token was issued, with only its first eight characters.

In the admin console, the sign-in page links to Forgot password?, which opens /forgot-password. The link in the email opens /reset-password. The console checks the length before it sends the token, so a password that is too short does not spend the link.

Both routes are public and take no Authorization header.

  1. Ask for a reset:

    Terminal window
    curl -X POST http://localhost:3001/api/admin/auth/password-reset/request \
    -H "Content-Type: application/json" \
    -d '{"email": "you@example.com"}'
    { "message": "If an account with that email exists, a password reset link has been sent." }
  2. Open the email and copy the token from the link.

  3. Try a password that is too short. The token is not spent:

    Terminal window
    curl -X POST http://localhost:3001/api/admin/auth/password-reset/confirm \
    -H "Content-Type: application/json" \
    -d '{"token": "<token from the link>", "password": "short"}'
    { "error": "password must be at least 12 characters" }
  4. Set the new password:

    Terminal window
    curl -X POST http://localhost:3001/api/admin/auth/password-reset/confirm \
    -H "Content-Type: application/json" \
    -d '{"token": "<token from the link>", "password": "a-new-password-2026"}'
    { "message": "Password has been reset successfully." }
  5. Send the same token again. The answer is 400 with invalid or expired reset token, even when two confirms arrive at once.

VariableWhat it doesDefault
SMTP_HOSTMail relay host. Without it and without the email feature, no mail is sent.unset
SMTP_PORTRelay port.587
SMTP_FROMSender address.unset
SMTP_USER, SMTP_PASSRelay credentials. Both must be set to authenticate.unset
LYEVE_CONSOLE_URLThe console address the link points to. Required in production, where it must use https.http://localhost:5173 outside production

If you set LYEVE_PLUGINS, include password-reset in it.

LimitDefault
Link lifetime1 hour
Minimum password length12 characters, whatever PASSWORD_MIN_LENGTH says
Reset requests per client address (password-reset.ip)10 per minute
Reset mails per email address (password-reset.email)1 per 5 minutes
Request route, per client address3 per second, burst 5
Confirm route, per client address5 per second, burst 10

A super admin can change the two named limits on the rate limiting page. A request over the per-address mail limit still answers 200 and sends nothing, so the limit reveals nothing about the account. PUBLIC_RATE_LIMITS changes the two per-route limits.

Spent and expired tokens are deleted by a daily sweep. Deleting a tenant, or a privacy erasure, deletes them at once.

Errors answer a JSON body with an error message.

StatusMessageCause
400invalid or expired reset tokenThe token is wrong, expired or already used. Request a new link.
400password must be at least 12 charactersThe new password is too short.
503password reset is not configuredLYEVE_CONSOLE_URL is not set.
Every other error
StatusMessageCause
400invalid JSONThe body is not JSON.
400A validation error with a fields objectA field is missing, or email is not an address.
429too many requestsOver 10 requests a minute from one client address.
429rate limit exceededOver a per-route limit.
  • No email arrives. Check that SMTP_HOST is set, or that the email feature is configured, and look in the server log for failed to send email.
  • The link points to the wrong address. Set LYEVE_CONSOLE_URL to the console's public URL.
  • Password reset is missing. In production it does not start without LYEVE_CONSOLE_URL. The server log names the setting at startup.