[GH-ISSUE #5116] Magic link tokens are not invalidated when new tokens are requested #10166

Closed
opened 2026-04-13 06:07:43 -05:00 by GiteaMirror · 4 comments
Owner

Originally created by @josepchetrit12 on GitHub (Oct 6, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/5116

Is this suited for github?

  • Yes, this is suited for github

When a user requests multiple magic links in succession, all previously issued tokens remain valid until they naturally expire. This creates a issue where an attacker who gains access to an old email/link can still authenticate successfully, even after the user has requested a new magic link.

Describe the solution you'd like

When a new magic link is requested, all previous tokens for that email should be invalidated, ensuring only the most recent link is valid.

Describe alternatives you've considered

magicLink({
            sendMagicLink: async ({ email, token, url }, request) => {
                // Delete all previous magic link tokens for this email, keeping only the most recent one
                await invalidateOldMagicLinkTokens(email);
                
                // Send the new magic link email
                await sendMagicLinkEmail({ email, token, url })
            }
}),

Additional context

No response

Originally created by @josepchetrit12 on GitHub (Oct 6, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/5116 ### Is this suited for github? - [x] Yes, this is suited for github ### Is your feature request related to a problem? Please describe. When a user requests multiple magic links in succession, all previously issued tokens remain valid until they naturally expire. This creates a issue where an attacker who gains access to an old email/link can still authenticate successfully, even after the user has requested a new magic link. ### Describe the solution you'd like When a new magic link is requested, all previous tokens for that email should be invalidated, ensuring only the most recent link is valid. ### Describe alternatives you've considered ```ts magicLink({ sendMagicLink: async ({ email, token, url }, request) => { // Delete all previous magic link tokens for this email, keeping only the most recent one await invalidateOldMagicLinkTokens(email); // Send the new magic link email await sendMagicLinkEmail({ email, token, url }) } }), ``` ### Additional context _No response_
GiteaMirror added the locked label 2026-04-13 06:07:43 -05:00
Author
Owner

@Bekacru commented on GitHub (Oct 6, 2025):

This is intentional as there are valid use cases like when a user generates a magic link from different devices/browsers, where they should still be able to log in. It’s a short-lived token, so it should be fine

<!-- gh-comment-id:3373866214 --> @Bekacru commented on GitHub (Oct 6, 2025): This is intentional as there are valid use cases like when a user generates a magic link from different devices/browsers, where they should still be able to log in. It’s a short-lived token, so it should be fine
Author
Owner

@Blackmamoth commented on GitHub (Oct 7, 2025):

@Bekacru saw this was closed. I have an implementation approach for this as an opt-in feature (invalidateOldTokens: false by default). When true, it would invalidate previous tokens for that email before generating a new one. If you're open to it as a config option, I can put together a PR. Let me know

<!-- gh-comment-id:3375720783 --> @Blackmamoth commented on GitHub (Oct 7, 2025): @Bekacru saw this was closed. I have an implementation approach for this as an opt-in feature (invalidateOldTokens: false by default). When true, it would invalidate previous tokens for that email before generating a new one. If you're open to it as a config option, I can put together a PR. Let me know
Author
Owner

@sypion commented on GitHub (Feb 23, 2026):

@Bekacru saw this was closed. I have an implementation approach for this as an opt-in feature (invalidateOldTokens: false by default). When true, it would invalidate previous tokens for that email before generating a new one. If you're open to it as a config option, I can put together a PR. Let me know

I like this idea! I understand there's a case when, for example, slow email clients, but I have set up an onboarding experience where, in some specific cases, previous magic links should no longer be working if a new one is generated and sent.

<!-- gh-comment-id:3942108789 --> @sypion commented on GitHub (Feb 23, 2026): > [@Bekacru](https://github.com/Bekacru) saw this was closed. I have an implementation approach for this as an opt-in feature (invalidateOldTokens: false by default). When true, it would invalidate previous tokens for that email before generating a new one. If you're open to it as a config option, I can put together a PR. Let me know I like this idea! I understand there's a case when, for example, slow email clients, but I have set up an onboarding experience where, in some specific cases, previous magic links should no longer be working if a new one is generated and sent.
Author
Owner

@github-actions[bot] commented on GitHub (Apr 1, 2026):

This issue has been locked as it was closed more than 7 days ago. If you're experiencing a similar problem or you have additional context, please open a new issue and reference this one.

<!-- gh-comment-id:4166557530 --> @github-actions[bot] commented on GitHub (Apr 1, 2026): This issue has been locked as it was closed more than 7 days ago. If you're experiencing a similar problem or you have additional context, please open a new issue and reference this one.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#10166