Our system uses passwordless login to send user a login code+link by e-mail by which they can login.

We found one of our customers has a mail scanner that actually follows those links. We invalidate the login codes on use to the reduce the attack surface for an attacker. But now such emails no longer have a valid login link.

There seem to be two solutions to this:

  • Do not provide a login link but only a code in the message.
  • Let the login code be valid after first time use for X period (say it invalidates after 15 minutes)

Option 1 seems to be unacceptable by our UX team.

Option two seems to be much less secure:

  • Provides a bigger attack surface because more codes will be active in our database
  • Social engineering will be easier: a user could take a picture of someones mail and type of the code within the valid period (even though user already used the code) and login with this code.

Would there be any other or better solution that would be both UX friendly and (atleast as) secure?

  • 4
    This exact same question has been asked before. I can't find it right now, but I know it is here.
    – user163495
    Jul 4, 2019 at 12:45
  • 5
    Does the one-off customer mail scanner have a sufficiently unique user-agent that you can simply block it on your server? Possibly coupled with the customer static IP ? Jul 4, 2019 at 15:41
  • 5
    So annoying that I won't make it a real answer: Put a CAPTCHA on the page that the login link goes to.
    – Barmar
    Jul 4, 2019 at 23:35
  • 1
  • 1
    Maybe invalidate after he actually did something on the page? When the link is clicked it would not mean a password is set
    – EpicKip
    Jul 5, 2019 at 14:52

6 Answers 6


It is unclear in which context the password-less login is used. But, if the user gets send the link to login only after visiting the site, then you could issue a cookie to the users browser and expect this cookie when the user logs in.

Most users will likely use the same browser to login after getting the link via mail and in this case you could align the clicked URL with the cookie send by the browser. Since the security appliance has no knowledge of the end users cookies you can easily reject the click from this appliance.

In case the user uses a different browser for clicking the link or if the user has deleted the cookies explicitly or implicitly (like when using a new private browser session) you can still have an explicit token in the mail the user can manually enter to continue with the authentication.

This way almost all users are handled transparently when clicking the link, the remaining users can continue manually by entering the token and any automatic systems are left out - even if they are able to execute the Javascript on the page.

I would not count on the inability of these analysis systems to run script. I'm pretty sure that many will actually handle script since this is also a typical mechanism used in phishing mails to complicate analysis. Instead you should count on missing knowledge of the system (i.e. does not know the cookie) and not missing capabilities.

  • 1
    This approach seems kind of frickle. What if your local IT admin created the account for you? What if the user signed up with a different device? What if the user has set something such as Firefox Focus (acts like incognito mode) as his default browser? What if the user visits your site on chrome, clicks on the mail notification and his smartphone opens the link with Samsung browser? etc pp Jul 5, 2019 at 7:08
  • @pytago: These points are actually addressed in my answer. Please read the parts "In case the user uses a different browser ... almost all users are handled transparently when clicking the link, the remaining users can continue manually by entering the token and any automatic systems are left out... ". The main point of my answer that it does not rely on some currently incapable analysis which might be capable to click some link or execute script later. It relies instead on missing knowledge and not missing capability by the analysis. Jul 5, 2019 at 7:35

Instead of invalidating the login code when the link is clicked, have a script on the page that runs and makes a request to your server to invalidate the code. This will only be effective if the "mail scanner" just visits the page and doesn't run any scripts on it.

You should also invalidate the code after a period of time (your second option), because if the user is running a browser with scripts disabled the code will not be invalidated by this method. The timeout serves as a backup if this is the case.

If you find that whatever "mail scanner" your users have is running scripts on the page, this won't work. Instead, you could require a user action on the linked page to complete the login process. Your users would click the link in the e-mail and be taken to a simple page with a login button, and perhaps some text like Log in as <username>?. Only log them in (and invalidate the login code) when they click the button. This would require two clicks from your users instead of one, but I don't think that's too inconvenient.

Since the "mail scanner" will only visit the page and not click the button, it won't use up the code.

The more I think about it, the more I like requiring a click. It doesn't rely on the mail scanner not running scripts so it should be more robust. You could even combine it with Steffen Ullrich's cookie idea. If the user clicks the login link in the e-mail and has the cookie, you know they're not the mail scanner so you can log them in right away. One click and they're logged in. If the cookie is NOT present, the click might actually be coming from the mail scanner, so you show a page with a login button. If it's actually just the user on a different browser (or the same browser with cookies disabled), they'll click the button and log in. In this case it took them two clicks, but that's only a slight inconvenience and it's only necessary if the cookie isn't there.

See this similar question.

  • 12
    Normally this is handled with a form that makes a POST request, since automated tools are unlikely to submit those. It also eliminates dependency on scripts.
    – domen
    Jul 4, 2019 at 14:13
  • Yes, this was the one I was looking for!
    – user163495
    Jul 4, 2019 at 18:05
  • 13
    Instead of editing with "Edit:", just... edit the post to say the new thing. If people care what it was in the past, they'll look at the revision history.
    – anon
    Jul 4, 2019 at 21:11

Log in only on POST request. The link in the email should not cause a login: it should simply link to a login page. The URL code can be extracted from the URL and put into a hidden form field. When the form is submitted, which the email scanner will not do, then, and only then, is the user logged in.

If you want to reduce user friction, you can have javascript submit the form automatically once the page loads.

  • The idea with POST is good.
    – mentallurg
    Jul 6, 2019 at 20:32

When link is opened, show only a page with a button, but don't do anything with the code. Only after user clicked the button, invalidate the code.

  1. Avoid single-use tokens. These do not lend themselves well to fault tolerance, e.g. if a user tries to use a link and his device has a slow connection. Also, anything single-use may be more vulnerable to application denial of service attacks.

  2. Expire the token from a reasonable period after it is sent, e.g. 15 minutes.

  3. After the user clicks the link, require a second factor of authentication. This could be something very simple, like their name. This mitigates the risk that a typo in the user's email will grant full access to his account to a stranger with a similar address. For added security, the second factor could be delivered out of band (e.g. via SMS), but this is obviously less convenient. If you can't come up with a second factor, you can use a CAPCTHA, or if that is too strenuous for people, simply use a landing page with a button and require the user to click it before proceeding.

  4. Employ session fixation and CSRF mitigations on the authentication page(s)

  5. Expire any tokens in flight the moment the user authenticates successfully, but not before. This will prevent bots and email clients from accidentally consuming the code.

  6. Maintain an audit log of token use and analyze regularly for suspicious patterns.


I'll add my comment question as a possible stated answer.

Block the one-off customer USER-AGENT on your server? Couple with the customer Static IP.

Assuming these are sufficiently unique, you can make it transparent.

Don't hard code the one instance, assume it will happen again and set up a reference table of USER-AGENT and IP to be blocked. That way you can simply add to the table as required.

  • 1
    I would imagine that whatever "mail scanner" is in use fakes its user agent. If it announced to every site it visited that it was a mail scanner, it would be very easy for actual malicious sites to serve a benign page to it, "fooling" the scanner.
    – gfrung4
    Jul 4, 2019 at 17:46
  • @gfrung4: While it would seem logical, you'd be surprised how often it doesn't happen. The reasons are many fold: developers didn't know or care, legal concerns about pretending to be someone else, maintenance keeping the ID updated. More often than not it's either completely absent (which is itself useable) or a static semi unique ID. Hopefully the OP will tell us. Jul 4, 2019 at 20:24
  • 2
    If the mail scanner is behind the same NAT that the customer is, this won't work. If the mail scanner runs on the customer's machine, this also won't work.
    – abligh
    Jul 5, 2019 at 6:24
  • @abligh: As long as the mail scanner has a different user-agent than the customer browser, it will work even from the same NAT. Your second point is valid but that would be a very strange and unlikely configuration. Jul 5, 2019 at 14:37
  • 1
    Blacklists are always the worst way to solve security problems
    – symcbean
    Jul 6, 2019 at 23:50

Not the answer you're looking for? Browse other questions tagged .