Magic link tokens are not invalidated when new tokens are requested #2080

Closed
opened 2026-03-13 09:25:22 -05:00 by GiteaMirror · 3 comments
Owner

Originally created by @josepchetrit12 on GitHub (Oct 6, 2025).

Is this suited for github?

  • 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

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). ### 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 security label 2026-03-13 09:25:22 -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

@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

@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.

@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.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#2080