Skip to content

User password reset request responds as successful, but fails silently - TTL Issue #13604

Description

@MitchDrage

problem

When a user requests a password reset at the login page, with password reset emails enabled, it returns a successful message to the user and emails them a reset token.
If the user requests another reset within that token's window (user.password.reset.ttl), it will still return a successful message to the user but willl fail internally with the message:
DEBUG [o.a.c.u.UserPasswordResetManagerImpl] Failed to reset token and send email. Password reset token is already set for user user@emaildomain.com in domain id: xy with account primary and email user@emaildomain.com

This doesn't appear in the event log of the user either.

versions

4.22.1.0

The steps to reproduce the bug

  1. Have settings enabled for user password reset (user.password.reset.enabled = true) and an email host configured (user.password.reset.smtp.host)
  2. Request a password reset.
  3. Observe the first reset email.
  4. Request another password reset.

What to do about it?

There's a few issues here I think should be addressed:

  1. Consider if password reset attemps should be visible in the user's Event's page. It might create spam in the events list, so might not be a good idea.
  2. Consider either:
  • Allowing a user to re-request a new password reset token and reset the TTL window using the new token (my desired outcome, and what I'd expect end-users would be familiar with).
  • If not the above, then wait for the email to be successfully queued/sent and return the success from that. If the email isn't sent due to the token being within the TTL, then return a user-friendly message that they cannot request a new token until a specified datetime.

Activity

  1. added theissue type on Jul 20, 2026
  2. added this to the 4.22.2 milestone on Jul 20, 2026
  3. DaanHoogland commented on Jul 27, 2026

    @DaanHoogland
    Contributor
    • Allowing a user to re-request a new password reset token and reset the TTL window using the new token (my desired outcome, and what I'd expect end-users would be familiar with).
    • If not the above, then wait for the email to be successfully queued/sent and return the success from that. If the email isn't sent due to the token being within the TTL, then return a user-friendly message that they cannot request a new token until a specified datetime.

    I think a third option could be

    • if within the ttl window, resend the existing token.

    that said handling the silent fail is the major issue.

  4. modified the milestones: 4.22.2, 4.22.3 on Nov 9, 2026
  5. modified the milestones: 4.22.2, 4.22.3 on Nov 9, 2026
  6. MitchDrage commented on Nov 10, 2026

    @MitchDrage
    ContributorAuthor

    I had a think about this and I still believe most implementations would issue a new token on each request.

    1. Issuing a new token rotates the token and resets the expiry together. Resending the existing token requires that we either:
      Keep the original expiry, which is confusing if the user asks near the end of the window as the link may only work for a few minutes, or
      Reset the expiry, which lets a single token live indefinitely, provided the rate limit allows it.
    2. OWASP says reset tokens should be "stored in a secure manner, as discussed in the Password Storage Cheat Sheet" (https://cheatsheetseries.owasp.org/cheatsheets/Forgot_Password_Cheat_Sheet.html#general-security-practices), which recommends hashing. The token is currently stored in plaintext in user_details. I wouldn't change that under this issue, but if it ever moves to a hash we couldn't resend the existing token.

    Raising a PR for option 1.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions