Skip to content
All articles
Security25 May 2026·7 min read

Magic links, and the four places they leak

A link that signs somebody in is a bearer credential delivered over a channel you do not control, into an inbox that may open it before its owner does.

Paycux security engineering

Magic links are popular for good reasons. There is no password to forget, no password to reuse, and the flow is shorter than a reset. They also move your authentication onto a transport with no confidentiality guarantees, into a mailbox that might be shared, scanned or forwarded.

That trade can be fine. It is fine when the token is short-lived, single-use, bound to the browser that asked for it, and unable to do anything a session should not.

The scanner opens it first

This is the failure that surprises teams, and it is common in exactly the accounts you care about. Corporate mail security products fetch every URL in an incoming message to check where it goes. Your single-use token is consumed by a scanner in a data centre, and the person clicking thirty seconds later is told their link has already been used.

The fix is to make the link's landing page inert. A GET request proves nothing and changes nothing; it renders a page with a button, and the sign-in happens on a POST that a scanner will not make. It costs the user one click and eliminates both the prefetch problem and the class of bugs where a link is activated by a preview pane.

A mail scanner will click your link before its recipient does. Do not let a GET consume the token.

Bind it to the browser that asked

When someone requests a link, set a cookie in that browser carrying a value tied to the request. When the link is opened, require both the token and the cookie. A token forwarded to somebody else — or intercepted in a shared mailbox — is then useless, because the second half never left the original device.

Where the browser genuinely differs, requested on a laptop and opened on a phone, fall back to displaying a short code on the requesting device that the person types on the other. Same guarantee, one extra step, and only in the case that actually needs it.

  • Token from a cryptographic source, hashed at rest, single use, expiring in minutes
  • Consume on POST, never on the initial GET
  • Second factor in a cookie on the requesting browser, or a code shown on it
  • Invalidate all outstanding links for the address once one is used
  • Rate limit per address and per source, or you have built an email cannon

What the link must not be allowed to do

A magic link proves control of an inbox. That is a reasonable basis for a session and a poor basis for anything stronger. It must not satisfy a second factor, and it must not by itself authorise changing the email address, adding a factor or removing one — otherwise inbox access silently becomes permanent account takeover.

Watch the redirect parameter too. Carrying an intended destination through the flow is useful, and it is attacker-supplied text that ends up in a Location header. Accept relative paths matching an allowlist, never a full URL, or somebody will send a genuine sign-in link that lands people on a page they chose.

  • Never accepts as a second factor; step-up still applies to sensitive actions
  • Cannot change the address it was sent to, or the factors protecting the account
  • Redirect target restricted to known internal paths
  • Response identical whether or not the address exists, to avoid enumeration

Everything here, already built

Sign-in, enterprise SSO, directory provisioning, roles and an audit trail behind one API. Start with the quickstart and have a working sign-in this afternoon.

Start selling to enterprise customers

Create an account, point sign-in at Paycux, and get back to the part of the product that is actually yours.