Are Magic Links Outdated?
zitadel.com
zitadel.com
Sending a one-time code via email fixes this, and is in practice about as easy to use as a link on desktop.
In our app (Loomio) we default to magic/codes, but let users use passwords if they prefer.
The only caveat for implementing is that you essentially need to have a mobile app for your site, while SMS/email auth are more universal.
From a security perspective as a user, it's no different than deferring to a social provider like Google, but has the benefit in that it gives a user more control over the third party they choose to delegate control to.
You allow username/password access and that's great too. I'm a fan of giving users options, but I don't know if anyone has done studies and found that a single login option actually is better for conversion. I'd be interested in seeing some numbers around that.
I wouldn't recommend a magic link for high value accounts, but I have pretty easy access to my mailbox, from everywhere (in contrast to my password manager, which is cumbersome to use from different accounts). I can also forward the email with the link to any device where I have email.
If it is a low-value account that I use infrequently, I'm a fan. The alternative is to just use 'forgot password' to get a link that resets my password. That is pretty much the same functionality.
I guess the hard part there is that no one building software thinks their app is 'low-value'. :)
The only real difference is if the password reset forces you to change the password and logs you out everywhere, then you can at least detect the break-in more quickly with the password approach.
I know the things I'm working on are low-value and appreciate it. In fact, I genuinely dread ever working on something high-value.
Email is the master key to most of your accounts.
I’ve been mulling over ideas for this in my head for a while, about fully standardizing the magic-link-to-login approach as a full single-sign-on implementation.
Sites could craft an email with a specific header scheme that denotes what it’s trying to do, for what website, and what the magic link key is. The body of the email would still look like a regular magic link email as it does today, as a graceful fallback behavior.
The website login screen could detect if the user agent supported magic links (best way to do this detection is TBD…), the requirements being be that (a) The OS has an email account configured for the user (like via Mail.app or similar), and (b) the OS can broker the security information of the magic links to the browser so that it doesn’t need “full” access to your email, just a standardized API for the browser to get the magic link header info.
If everything checks out, the UX for the login page would be:
- User: enters email address to log in with, hits submit
- Webpage: renders a quick loading spinner
- Website: Sends a magic link email to the email address
- OS: Sees the special magic link email and notices that the browser is in focus on the same origin (using an origin policy that requires the magic link’s headers matches the same origin as the page)
- Browser: Gets magic link/token from the OS
- Browser: Submits token to website
- User sees the login succeed.
- (Optional:) The mail client puts the email itself in a trash folder or some other place so the user doesn’t even notice it (although they should be able to dig it up if they want.)
The graceful fallback if the browser/OS setup is not supported would be that the website just renders the same “check your email for a link” page it would have normally sent.
Apple has enough integration to easily implement this on iOS and macOS, it would be great to see this happen. They already implement autofill for security codes sent to SMS or email, so they already have a similar level of integration, it just needs to be made seamless and not even require user input. It could also be a totally open standard so that any OS/desktop environment/etc could implement it.
Throw some structured data into the email. Email clients can detect and do the popup that hits a callback endpoint. Clients that don't support it still get the code via regular email.
I avoid the OS-layer implementation at the expense of the user having to confirm it's them, but this also means it works cross-device, which is what I'd want for 2fa anyway.
Seems like a lot of moving pieces that only an OS vendor (who controls both the browser and the email client and could build the integration between them) could implement.
I've no idea why it is so difficult for apps to open links in the user-selected browser. Isn't it just "xdg-open https://example.com/"?
In any case, I don't need to bother about whether any "cookie sharing" works or not if I only use one browser, do I?
It's not, it's a conscious decision to open links in chrome from gmail.
That is quite insane indeed.
And on top of that, Android keeps using Chrome as embedded browser. Even if you installed another one. MSHTML all over again.
[Note there are two things: 1) stupid apps putting a generic in-app browser inside the app - that's annoying; and 2) apps using a webview with a bridge between native app and a website, injecting some stuff and properly integrating the embedded website; something impossible to do by opening a website in regular browser]
No, theres implementation differences across API levels and the "shared cookie jar" implementation is newer and had some quirks. Its been a couple years since I was deep in this so it might have changed, but that was my experience back then.
I don’t have a pw manager on my mobile device nor do I want one, getting a 35+ char into an input field on my phone is a PITA.
Do you have an example of the problems you've encountered? This is normally a turn-on-and-forget setting which is only slightly harder if you're using JavaScript to submit forms.
> I don’t have a pw manager on my mobile device nor do I want one, getting a 35+ char into an input field on my phone is a PITA.
What's your threat model for using long passwords but not using a password manager? I can understand why you might not want to store it on a cloud service even if it is encrypted but local storage is going to be more secure than entering it by hand if for no reason other than that it's harder to shoulder surf and harder to phish.
The earliest Magic Links I remember using didn't have this problem, and this was before smartphones. The Link, back then at least, was only to authenticate that you can receive emails at a certain mailbox, not to authenticate whichever browser you used to open it. Your login attempt would keep the login (not logged-in) session open wherever you attempted to login from, while waiting for the Magic Link to be clicked on in the background. Whenever the Magic Link was clicked, irrespective of where it was clicked, your original browser session would stop waiting and log you in.
This also avoids the tedium of having to copy a link or code from one device/app to another. Just click, a browser tab/window opens for a short time, and then closes automatically after doing its job; you go back to wherever you attempted to log in, and simply proceed. This also simplifies post-login flows (like visiting a specific page you tried to access before being forced to login) in that such flows don't need to be tied to the Magic Link itself.
I can quickly access email on my phone - that doesn't necessarily mean I want to log in on my phone.
I think it’s just so much nicer of an experience to not have to worry where you go check the email or which browser opens when you click the link there.
The site you used to login was clearly where you intended to be, so that should definitely be one of the authenticated sessions when you click the link.
Switched to pin code entry, less fancy but achieves all the desired UX
A wrinkle in this complaint is that in most scenarios I don’t especially want a browser tab to be able to hold onto a persistent session while it’s closed due to privacy reasons, regardless of where that session state is held (and I realize there are a number of options).
This is a problem on low memory devices - the page gets forced to refresh because the system ran out of RAM. The iPhone 13 only has 4GB of RAM, and with many apps requiring 2+GB, it is frequent a web page can't stay loaded in the background.
Most android devices have 8GB plus RAM, so shouldn't hit that issue, although it still happens on very low end devices.
Edit: In fact, nevermind. My thinking on that was flawed. I think you’re right, that should be fine, as long as the DNS is encrypted.
If your user has one of those, then their account effectively has zero security since an attacker can attempt to log in, and the web security software will click the link, and the attacker (in the originating browser) is now logged in.
While I generally agree that this behavior is correct from a usability standpoint, it's not safe. That design allows a user to do a one-click account compromise when they receive a magic link that was sent in response to the login attempt of an attacker that happened to know the user's email address.
It might be howling into the void but the conclusion I reach from this is that "Mobile email clients are a nightmare".
Generally speaking, embedded browsers in mobile apps are a terrible idea and break user expectations in multiple ways.
Meanwhile if the stupid app decides to hijack the link and use in-app browser, you can't do that. And IAB typically means you can't have app and browser in parallel and switch between them from app launcher, which would be sometimes useful. Slack does that, and it's annoying. But at least you can right click> copy URL and open it manually in preferred browser.
This is true, and as a user I want something better, but as a developer I need to build for what our users use.
I don't put "Site best viewed in Netscape Navigator", and I don't tell users they can only login on desktop.
If the user clicks the magic link from the same device that they initiated the login from, it just opens straight into the app.
If the user clicks the magic link from a different device, it confirms the token and then the browser waiting on the original device logs in. It uses a generic browser/server messaging library to achieve this, based on whichever of HTTP SSE, WebSockets and polling is available.
If the user can't do either of these for whatever reason, such as email virus scanning or whatever, the bottom of the email also contains a code which can be entered onto the waiting login form, along with some information about never giving that code out to anyone else on the phone and checking the URL.
The magic link also has an interstitial page with an automatic POST form to deal with browsers and other things pre-opening links. There are also various points along the way that it attempts to check for phishing and perform additional interventions, such as if the magic link is clicked from a different country to the login request, or if the request is coming from a suspicious location, etc.
After all this is complete, it then does 2FA using SMS. The magic link login is only needed the first time you log in on a given browser as it saves a persistent cookie, but the SMS 2FA is needed every time. We don't support persistent sessions due to legal requirements.
We are also working on adding webauthn authentication, but early testing suggests most users find it very confusing. Mobile devices tend to handle it acceptably, but Windows' implementation in particular is currently very user hostile and often users worry they are being hacked. It also doesn't replace the email/SMS-OTP flow, because if the user is logging in from a new device, we still need a way to validate that it's them before they can subsequently authenticate with webauthn. We also support SAML SSO.
Most users are not interested whatsoever in carrying around a Yubikey. Even just using SMS-OTP got a lot of push back for being inconvenient. I think FIDO2 will work better for users when there's a good way of automatically synchronising their keys across all of their devices in a vendor-neutral.
For a lot of users the link didn't open in the app the way it was supposed to. Another surprisingly large subset of users had two phones, but the app wasn't on the phone they used for email. A one-time code definitely would have been better than a link.
The crux of it is, do you sign in the "originating" device (where the magic link was sent from), or the "consuming" device (where it was clicked).
Because it's veryyy common for people to be on a website on their computer, then click the link on their phone, but still want to be logged into their computer. We opted for the "originating" device. But this has security concerns.
(you also need to worry about multiple tabs on the same browser, but cookies make this easy to deal with)
But, what if an attacker just sends a link to loads of email addresses, and one of the receivers clicks on it by accident? Their account now has been taken-over.
So, this needs to be combined with the notion of "trusted devices", and of course, not breaking what the user expects. All in all, a TON of work to get some marginal gains in some sectors, mainly B2C. IMO, B2B should always have passwords as an option. 1Pass is too widely used to ignore.
That way, you can be signing in on a desktop browser, click the email link on your phone (or a different browser sandbox), and the desktop window will be signed in.
As others have pointed out, either login when the user has both generated and clicked on the magic link from the same IP (browser, where possible), or use magic codes (as opposed to links).
These guys sell a auth/login system, it's no surprise they are anti-magic-links.
I understand the annoyances for the more tech-minded among us, myself included, but I've implemented this before and for your average user it's a pretty good system. With Universal Links/App Links you sidestep a number of the issue with email clients having their own in-app browser. Also this makes your signup/signin process the same flow (and only 1 step) which is easier for people who aren't as technically minded.
I used this method for a food festival (you buy the festival's currency to spend on food/drinks, it's just a digital version of the paper/ticket/token-systems a lot of a festivals use) and we only had 1-2 people who had issues (email took a few minutes to get to them for some reason) out of thousands.
It's all about knowing your customer base, in the future I might implement the ability to set a password but I'd be the number of people who use that option will be vanishingly small (again, based on the demographics of people using my platform).
I came to grips with the idea that I really don't care all that much if a single factor has risks as long as the other factors have orthogonal lists.
Storing them in Bitwarden is more convenient by far, but storing TOTP is a paid feature.
It slightly raises the risk in the scenario where your password vault gets hacked, but like with putting all your passwords in the same place, if you've only got 1 place to protect it becomes easier to protect it more thoroughly.
I don't understand your point. This is exactly what multi-factor authentication protects against if you don't store your MFA codes in your password manager.
standard TOTP MFA (which is what most password managers would offer in terms of MFA) uses a shared secret, which you would just dump from the same database you get the dumped passwords from.
unless you use asymmetric crypto e.g. in webauthn this doesn't benefit you at all.
If your concern is phishing, storing the code on the device (especially on a modern phone) is really moot since all forms of one-time codes are vulnerable — you should be working on how to switch to FIDO2/WebAuthn.
If your concern is a temporary exploit of the user's browser, using an out-of-process password manager is likely to prevent exfiltration of the entire password list but in practice this is already probably a disaster scenario unless you're using sites which require a strong FIDO2 challenge for sensitive operations since the attacker already has your cookies for everything you use regularly.
1. Use my Yubikey with a different phone via NFC or a different computer using USB 2. Login using my other iPhone or Mac because the WebAuthn passkey is synced via iCloud (this is in the progress of coming to Chrome & Windows)
The nice thing is that all of those are more convenient than using email in addition to being more secure.
I can't quite put my finger on why it's different from having SMS 2FA codes in my Signal inbox, but it feels like more clutter.
I have virtually unlimited space for email, but they still show up in searches, and I'm certain I'll never want to look at them again.
I'm sure I am not the only one with those issues. As said above, this would all be fine if Magic Link was an option rather than the only way to sign in.
- If magic links are the only way to sign in, authentication success rate is now directly tied to your email deliverability rate.
- Single-use tokens (immediately expiring after clicking) can be followed by spam filters, and thus immediately become invalid for the actual user trying to sign in.
- MTAs using greylisting can cause unexpected delays in email delivery.
- If a session audit trail is implemented, malware scanners following links might cause sessions from unexpected locations showing up.
etc.
Additionally, even if I do have the e-mail on my device, clicking the link on mobile often opens it up inside some alternative web-view. Thus the session is tied to my e-mail client, not my actual browser.
- instead of single use tokens, set them to expire within 60 mins
- to prevent spam/malware checkers signing in when following the links, have the magic link take you to a page with a sign in button to ‘complete’ the sign in process. And, optionally, add some JS that clicks it for you on page load. This is the same approach used for unsubscribe links.
Case in point: SportSignUp, which is a platform/app that allows you to manage your little league/basketball/soccer team, etc.
The use cases for parents are basically figuring out where games/practices are, telling coaches that they will be/not be there, checking scores, and signing up to volunteer for various tasks.
Life is complex. You have non-custodial parents, nannys, older siblings, etc helping out. The easiest path is to send the magic link to the family text group.
There are some workarounds for this but they don't seem very secure, plus they add some complexity. E.g. once the backend validates the magic link click, it logs the user in also in the browser that initiated the email send. I think a sort of a phishing attack is possible here. Also the page that initiated it should periodically refresh itself to see if the session was validated somewhere else.
I haven't been able to find any more secure or simpler solutions to this problem. Any thoughts?
I guess the link must be disabled / invalidated after first use and your auth server and client obviously must verify if a given link is still valid.
The phishing scenario is a real one, though. People have been conditioned to click Yes on everything. Coinbase's magic links implementation, for example, requires you to click the magic link in the same browser session that initiated the login. This is a bit more secure, although annoying from a UX perspective if you're in an embedded WebView like you mentioned.
The middle ground is something like instead of sending a link, send a code via email that you enter on the website, but that just removes the magic of magic links and is no different than what it was before!
Wouldn't an even better middle ground option be defaulting to magic links, with the magic link destination both logging in and notifying the user that if they user want to switch [back] to a different web browser or device they can use their email and $TIMELIMITEDCODE? (Perhaps with the notification disabled if the browser which opens the magic link shares a cookie jar with the browser session which requested the magic link, and perhaps including a "You recently tried to access using $RequestOriginatingBrowserName on $DeviceID" to hint they might want to get out of their mail client)
Offers both the magic bit and a non-magic way to escape from the sandbox that is less likely to be a vector for speculative phishing attacks.
This statement only partially covers the problem.
I once had a cofounder leave my company on bad terms. He had access to the bank accounts, I had email admin.
It took me 5 seconds to get full bank account access and lock him out with access to his email ("forgot password").
It's astounding how much of a skeleton key our inbox has become. This community doesn't need reminding, but our families do.
We ran into this at FusionAuth and had to do implement some workarounds, documented here: https://github.com/FusionAuth/fusionauth-issues/issues/629#i...
Edit: https://news.ycombinator.com/item?id=32081192 mentions this and some other issues.
Which the "Email Security" section kind of hints to as well, that it's important users have a secure email setup. What they fail to mention, is that this is important not only if you use "Magic Links" but also if you have username+password login with "Reset my password" functionality, as otherwise intruders will be able to change your password anyways.
In conclusion, the article seems to have been written with the goal of saying "Everyone is using Magic Links, how can we get them to use Zitadel (their product) instead?", rather than an honest look on how "Magic Links" can be made more secure.
Challenge accepted. Here's my best practice list. (I should put this into a blog post!)
* Prefer them for accounts that are infrequently used or low risk.
* Test for conversion or goal uplift if possible with this.
* Offer the user choices; some people will prefer username/password, some magic link, some social sign-on.
* Ensure that users understand that whatever the destination is (email, whatsapp, slack, etc), the security of their app account is now tied to the destination's security. Understand that most folks care far more about their email or other destination than they do about access to your app.
* Understand the UX tradeoffs (around mobile browser issues). Document them if possible
* Make sure everything is over HTTPS. (Duh :) ).
* Set timeouts for links appropriately and communicate that to your users. ("This link is good for X minutes." "This link expires at HH:MM.")
* Warn users that access to the link is the same as access to the account. "Don't forward this email".
I think that's everything I'd say. I would love to hear if I missed something.
It drives me nuts.
What I would like is a service like Firebase or OAuth but that I communicate with through my backend. So a user sends in username/password to my server and I relay that to a service which returns a token or something. I've had too many issues with the Firebase front-end JS that I no longer trust it to handle the whole flow.
Anyone know a service like that? Basically just an API that is specialized in auth/security that I can outsource the data to without having to store it myself.
There's also "dbconnections" endpoints where you can post raw sign-up data though if you're looking strictly for the backend piece
Early 2010s? Craigslist has been doing this since the 90s.
https://news.ycombinator.com/item?id=31892299
This is very, very concerning and makes “magic links” a security threat to any platform that utilizes them.
The big thing is I only use a 6 digit numerical code that people have to copy and paste or type into the browser which they’re authenticating. I looked at stuffing a token into a URL, but it’s not a good idea because the email client may try opening the link to preview it or it may try opening the link in the wrong app/browser, such as an in-app browser.
That may sound super insecure, but the 6 digit code is half the secret that’s needed to authenticate. The browser that the person is using to login has a much longer complex secret that must be included with the code. Additionally, this combination must be authenticated within a set number of attempts, 3 by default, within a certain timeframe, 5 minutes by default.
My motivations for creating this, instead of using something like devise with passwords, is because I have seen soooooo many non-technical people get tripped up by passwords. I know there’s sign-in with Google, MS, etc. via OAuth, but I wanted to give people a way to login to web applications without being under the watchful eye of big tech.
I’m currently using it in production for all of my Rails apps, like https://legiblenews.com/email_authentication/new
A better description of why and how it works at https://github.com/rocketshipio/nopassword
With 3 attempts allowed I only need 230k usernames, even better!
The "secret" stored in the browser doesn't protect you from this, since I'm not stealing someone's code; I'm logging in from my own browser. (Of course I'm doing this via a botnet, so you won't notice it by IP address)
Try making password creation too difficult and now password reset will be the default authentication for a lot of users anyway.
I have nothing against password-reset-as-authentication aka "magic links", when done properly. And by properly I mean not using an ultra-low entropy auth code, like the parent is proposing (6 decimal digits, aka 20 bits of entropy).
By regenerating longer token each time a 6-digit token is required and only allowing something like 3 guesses per longer token (Before regenerating and sending a new 6-digit code) you have a secure system.
But sure, let me explain it:
Step 1: acquire a list of 230 000 usernames/emails.
Step 2: for each username/email, launch a browser and request a login code. The login code is sent to the users' email address, and the super-ultra-secret token is stored in the browser.
Step 3: for each username/email, do 3 random guesses from their respective browsers.
Each guess is a Bernoulli trial with P = 10^-6. Thus the probability of at least one success is 1 - (1 - 10^-6)^(230000 * 3) = 49.8%
I hope this made it clear for you. I think the fallacy in your reasoning was assuming that only legitimate users can get the "secret" token, which is false. It is true for things like debit cards, where the token is stored on the card itself, hence the 4-digit PIN with 3 tries allowed is sufficient. In this case however a "secret" token is handed out to anyone who requests a code. It protects you from someone peeking into your mailbox and stealing your code, but it fails against brute forcing codes on a large number of users.
1. Someone (anyone) initiates the login flow
2. The user record in a DB gets enriched with
- the 6-digit OTP (sent via email)
- the "secret" (shared with the initiating browser)
- the current session failed attempts counter (default: 0, max: 3)
- the total failed attempts counter since last successful login (default: 0, max: 20)
Let's assume that you've initiated the session (hence own the "secret"), but have no access to the OTP - you will always have 3 attempts to guess the OTP before the session gets reset (a new "secret" + new OTP). So after the 3rd unsuccessful attempt you start from scratch. And at that point other means of protection might come into play based on the second counter (throttling the auth. requests on the WAF/fronting server, blacklisting IP addresses, etc.)
The number of accounts you're targeting does not matter - in fact it may help other systems mentioned catch your malicious attempts sooner.
You didn’t explain how this gives you any protection akin to a physical chip on a debit card…
Let me illuminate the problem with a real-world analogy: this system is like me walking into a bank with a list of account names, and the bank issuing me debit cards for those accounts with random PIN codes, no questions asked. I’d have 3 attempts to guess the PIN, then the ATM swallows the card. Same as in OPs login system!
Still, don’t you think banks would be silly to do this?
>So after the 3rd unsuccessful attempt you start from scratch.
You don’t start from scratch. You do 3 attempts per user, period.
>The number of accounts you're targeting does not matter
It does matter. The entropy of their six-digit OTP is small enough that pwning at least one account from a pool of users is feasible. As I’ve shown above, the number of users necessary for pwning at least one account with 50% probability is log(0.5)/log((1 - 10^-[digits])^[attempts per user]). In our case digits = 6, and attempts per user = 3, which gives us ~231000 users. Which isn’t too many for a website.
In both cases you (an admin) control how many attempts you wish to accept before sacrificing the usability over security (temporarily disabling the card and forcing you to call the bank and disabling 6-digits OTP in favour of ie. 12-digits OTP).
Your real-world analogy is, this time, too simplified :) Let me counter-argument with my example:
You are in a a possession of 1 million user emails and request OTPs for all of them (let's assume no other security measures are in place). If you hit all of the 1M records with 3 attempts of OTP - according to my simple experiment - you might hit (on avg) 3.18 accounts.
Of course, in real life, your attack would be mitigated on other (non-application) level.
Please find my ugly code for that experiment: https://pastebin.com/S2ufabhU
PS. When OTP size is increased to 7 digits - the avg account hit drops to 0.33. For 8 digits - it drops to 0.02. (please mind I'm using lousy RNG :)
PS2. What I'm trying to emphasize is that there's nothing wrong with OTP-auth like this if properly implemented with other basic anti-bruteforce techniques. You could get "better" results with simple password spraying.
1. I don’t have any problem with OTP-based magic links, if they’re implemented carefully. As you’ve just demonstrated, a 6-digit OTP with 3 retries allowed is not sufficient at scale.
2. I’ve also demonstrated that OP’s proposal to augment the 6-digit code with a “secret” token gives you no additional security. It can only protect against someone peeking over your shoulder to snatch your OTP.
3. As you’ve just demonstrated, increasing the OTP length will mitigate the problem, as it increases entropy. For peace of mind, I’d recommend 64 bits of entropy, which can be achieved with a 13-letter alphanumeric code (case insensitive), or with 5 words from a dictionary of 10 000.
ad 1 - IMO, it's still sufficient at scale with some basic infra. hardening
ad 2 - AFAIK the "secret" was never meant to protect from brute-force, but rather mitigate threats from actors controlling the email part
ad 3 - again, let's be more pragmatic - no one would use it if it required typing 13-letters OTP :) there are other ways to mitigate the potential attack you've described.
Best.
1. This def needs hardening. I currently only use it for really low stakes stuff. I need to make that clearer in the README.
2. The next level of hardening I was planning on implementing is rate limiting code requests per email address. I figure I can step up the time-outs between code requests pretty aggressively to slow down brute forcing the code. The ATM that eats the card is a great analogy.
3. Maybe I missed it in the thread, but nobody mentioned that this from of auth makes it evident to the persons being attacked that something is happening if they have a bajillion code requests in their email inbox. There’s a lot of other problems that creates for these auth scheme, like filling a users inbox beyond its quota, triggering high volume breakers for SMTP relay services like AWS SES, etc. that wouldn’t be good.
For those watching, if you’re a security researcher feel free to open a GitHub issue on that repo and I’ll address it.
As an alternative, there are many hosted services (e.g. Auth0) that are well-regarded, and I'm sure there are some self-hosted options. There seems to be at least one way to do magic links on top of Keyclock[1].
If you've served the user a link which takes them to a session where they can change their password, that session must be authenticated, by definition; you would not allow an unauthenticated visitor to change an account password!
And so, if that password change session is authenticated, then just treat that as fully fledged session. Don't force the user to go back to the login screen and use their new password.
The next logical step after not forcing the user use their newly minted password is to just remind the user their forgotten password is still in effect, and that they can change it in their account profile settings.
From there to "magic link" authentication is just some minor UI tweaking.
I've always thought that asking the user to log in with a newly set password was an incredibly poor and unnecessary user experience, which just amounted to punishing the user for having forgotten their password and to train the user to believe that password recovery is inconvenient and should be avoided.
I'm signing into a website, I get an email when I'm about to sign-in from said domain, I click the link in the email, I'm signed in.
What is this training me to do exactly?
Apparently things like this do happen, for example when people are buying or selling things on the internet. They get redirected to a pay processing site that looks just like the one from their bank, but steals their money and/or identity instead.
I click the magic link, expecting it to sign me in, but instead it takes me to a fake copy of the website which then asks (again) for login details?
This is fine, but ...
> ... which then asks (again) for login details?
This is where the trick lies. The third-party copy doesn't have to ask you for login details. As your parent states: They get redirected to a pay processing site that looks just like the one from their bank, but steals their money and/or identity instead.
The fake site doesn't have to show you details of your account. It has to look just similar enough that enough people will think it's a legit payment site and submit their payment details.
----
There's also a simpler, alternative attack I mention in a sibling comment: https://news.ycombinator.com/item?id=32081724
A simpler attack would be to for the third-party attempt a login on their end into your account, and if you happen to click on the Magic Link generated by their login attempt, you wouldn't be signing yourself in, but them.
And this third party can find out how, exactly?
Or possibly just guessing without evidence because the sending cost of junk email is so low — looking at my junk mail folders, I have reason to believe they guess.
FWIW, I've heard of this type of attack (deliberately timed) being used during house purchases, with a fake destination bank message preceding the real message by a few minutes. Does anyone know if that's real or just an urban legend?
Even in the ideal scenario where I have a proper mail client, the alternative they present is:
auto-filled password from my PW manager: 1 click
magic link: click to initiate the login session (1); click to focus my email client (2); [wait for email client to launch if not already open]; click on the email (3); click the magic link (4) click to close the superfluous second browser tab (5); click BACK to my mail client (6); click to delete the now-useless email (7); click BACK AGAIN to my browser (8).
Hate these things.
So I could log into GitHub and save the cookies in a bookmarklet.
Then every time I want to use GitHub, I click the bookmarklet and it sets the cookies, so I am logged in.
I dabbled with the idea a bit, but it seems not straight forward. Maybe due to some metadata that cookies carry. They are not just key:value pairs.
For example here on HN, when I type "document.cookie" into the console, I get back an empty string.
Email is an inherently insecure, non-trustworthy system. Considering it the "root of trust" sounds scary.
You are mistaking transport layer "security" with information security. It's a common, yet potentially grave mistake.
Secure communication depends on encryption that is "good enough" so that unauthorised decryption takes too much resources or too much time to be practical, with the only encryption secrets being held by the sender and the receiver. We usually call that approach "End-to-end encryption", or E2EE. It is also something political entities try hard to ban, for obvious reasons, if you consider them mostly being suppressive-authoritarian surveillance state actors. (yes, I am aware of the '5 dollar hackwrench' xkcd comic [1]. If your state actor uses that tactic against you, you have a whole different problem).
True E2EE solutions for email exist, but - mostly because virtually no one wanted the extra hassle - they never got adopted widely.
In a perfect world, metadata would also be encrypted - or nonexistent at all (there are implementations for that, for example PGP-encrypted messages over bitstream over TOR (I know your 'bitstream address', but all messages get broadcast, e.g. via blockchain, to everyone, and you only pick out those that match your bitstream address. Because you have only your own private PGP key, you can't read the messages to other bitstream addresses, even though you have them).
Problem I have with most password reset schemes is they put the secret token in a URL, which is visible to all by the postcard analogy.
So far, I have been careful enough, but it's only a matter of time until this bites me.
Magic links aren't targeted at the type of user you seem to be.
Most users of most products are: 1) on mobile devices, and 2) use a native email client.
They also don't have password managers, so magic links become a way to assume the security level of their personal email (which is what "forgot password" ends up doing anyway).
If the industry got itself together enough to start teaching people good internet hygiene we'd all be much better off. But instead we strip away OK security for horrible security, and inconvenience nearly everyone in the process.
I can't count the number of people I know who reuse the same password on every site or just use terrible passwords. It took me years to get my dad and girlfriend on a password manager, and they're the only family I've succeeded with.
It's the same with privacy. I could never get anyone to leave Gmail. You can't sell people on a major "inconvenience" by telling them about a hypothetical security breach. It's just not human nature.
And even worse, the only good password manager that I've used is 1Password and it isn't free.
EDIT: The idea here is that on a device where you're already logged in you generate a QR code, you photograph that code on another device, and then you confirm on the first device that it's really you who photographed the code on the other device.
Even so, the potential problem caused by email providers automatically calling links in received emails is trivially prevented by having a "Confirm login" button at the destination, as displayed in the visual example in the article. Also, using a QR would then rely on the user having yet another device at hand to log in, perform the often awkward scanning procedure instead of an ordinary couple of clicks/taps... to then finally log in on their phone and not on the original device they were aiming to (as well as making it less secure in a public surrounding against covert attackers in close proximity, but that's a bit of an edge case).
If it is just the magic link then anyone, someone shoulder-surfing as you access the site/app for instance, could scan that code and get in by following the link.
If it is being used as a single factor then even worse: anyone can get the QR code to scan without you even being present.
QR codes will work in this sort of context, but more work is needed to prove the device scanning the code is the user's device and not some random's - you can't just use a straight single request following the magic link as credentials.
Requires a setup step first that the magic link doesn't (getting the secret stored in the browser).
Also no use if the user is trying to login with that particular device.
I work as a web dev for my local students union, and we recently had to develop a system to process refunds for basically every student there (9€ ticket related).
However, our university wanted nothing to do with that process, so we couldn’t use existing student login infrastructure to verify refund claims and limit them to one per student.
Luckily, each student gets a @stud.leuphana.de mail address. So all we had to do was send them a login link – if you weren’t a student or entered an invalid address you simply never received that, so you couldn’t apply.
The system worked great and with few issues, thanks to magic links!
Another example of this is consumer apps that insist that you should login with your phone number and make you click an extra button to change to the email login option.
One major use case that comes up more frequently is onboarding an untrusted device with a trusted one. WhatsApp seems to have mastered this class of problem using the QR code. Typing in codes and clicking emailed links is nice until you feel your phone's camera instantly log you in on your laptop by scanning its screen. The obvious downside is that this is a chicken-egg situation and you have to already have one chicken (or egg) to make it work.
There are, of course, challenges with this being the only (or default) way to sign in, but the security concerns with it (e.g. weak email password) probably aren’t new!
Register:
1. I click the password field.
2. I click "use autogenerated password"
3. Sign up.
For login:
1. Click "login".
The magic link experience is comparatively awful:
1. My email address never auto-fills so I need to click the field and select the completion suggestion. This is even worse if I am using a per-site email address.
2. Click login.
3. Go to my email.
4. Most often wait a few seconds.
5. Click the link. (add extra steps if I want to open in a private window or container tabs, or tons of pain for a different device)
6. Delete the email.
7. Find the new tab.
8. Maybe drag it to the right location in the tab bar or the right window.
And that is assuming that my email providers likes your email and it doesn't get greylisted, put in spam or even outright rejected.
I like how tangible passwords are. Even with a password manager I can write them on a piece of paper, store then in a vault and enter them into a new computer. My grandmother understands this process.
The key-based systems are basically magic. Magic that works great as long as you are inside the defined parameters on supported devices. I think it will be years after the "first baked release" before we see relatively user friendly manual backup and restore. Something this is second nature in most password managers.
Yes, availability on all browsers and devices is not yet up to 100%. I hope to see a fast adoption, but agree that it could actually take some time. I use Passkeys on a daily basis for the last ~1.5 years wherever possible and won't go back anytime soon :)
Most browsers in 1996 had "save this password" functionality... it's not a new thing.
There are legitimate downsides to magic links but this isn't realistic. Do you not have to enter email on register? Where is the email confirm step for password signup? Finding the tab you just opened and dragging it... really? All of that happens on first signup as well. And the comment you are replying to is talking about a 1-2 times a year process, is a magic link really so difficult to use twice a year?
Yes, I have omitted this from both workflows.
> Where is the email confirm step for password signup?
Good point, most websites will want to confirm the email address. I didn't include that.
> Finding the tab you just opened and dragging it... really?
Yes, I like to keep my tabs organized. I'm not even a tree-sytle-tabs user but at least want to get the right window. The point is that magic links disrupt my in-browser workflow with switching between apps and opening links in new tabs.
> is a magic link really so difficult to use twice a year?
No, but it is still more difficult than a password multiple times a year. Neither of these have a yearly cost so it doesn't really matter how often you do them. I wouldn't use "only twice a year" to justify that people can come to our office in person to authenticate over a magic link.
> Yes, I have omitted this from both workflows.
You specifically complained about having to enter your email on the magic link flow:
> 1. My email address never auto-fills so I need to click the field and select the completion suggestion. This is even worse if I am using a per-site email address.
> > is a magic link really so difficult to use twice a year?
> No, but it is still more difficult than a password multiple times a year. Neither of these have a yearly cost so it doesn't really matter how often you do them. I wouldn't use "only twice a year" to justify that people can come to our office in person to authenticate over a magic link.
Yearly costs to who? The user? I guess there isn't really a cost to them other than storing/keeping the password but there is absolutely a cost to the developer and I'm not talking about the cost of storing a hashed/salted password in the DB itself. There is a cost to build and maintain a password-based system. It means implementing and maintaining a number of things like your salt, password complexity requirements, password reset flow, and more like you going to use something like HaveIBeenPwned's hash list to make sure people aren't using known passwords?
Passwords are not zero-cost and have ongoing concerns. I'm not saying magic links are always or even often the best choice, just that they do have a perfectly valid use-case.
For logins yes:
> My email address never auto-fills so I need to click the field and select the completion suggestion. This is even worse if I am using a per-site email address.
My email always autofills for regular login forms. Maybe this is a bug in my browser but either way it is an inconvenience that I face.
> implementing and maintaining a number of things like your salt, password complexity requirements, password reset flow
If you are using any halfway popular language there is a library that does all of this for you. In fact it is probably easier to use a pre-packaged library than for magic links, but I'm sure those libraries could appear if magic links become more popular.
Seriously ... if today's developers are unable or unwilling to learn about basic hashing/salting and database storage/value comparison, and consider such concepts 'costly' ... we may have passed the zenith of technological advancement, and are in a 'downfall of the Roman Empire' phase. Have some pride in your work.
> It means implementing and maintaining a number of things like your salt, password complexity requirements, password reset flow, and more like you going to use something like HaveIBeenPwned's hash list to make sure people aren't using known passwords?
Do you reinvent the wheel whenever you need to drive somewhere? these things mostly are already baked into most frameworks, and if they are not, most developers build something like this once, and reuse.
> [Magic Links] they do have a perfectly valid use-case.
Annoying customers and forcing them out of your business into the willing hands of your competition?
I have a very good reason for picking magic links, also the codebase for my project does not ruse a framework (there exist no good ones in the space I'm in) but instead of being curious you decided to be condescending. Cool.
I mean unsubscribe links are commonly two-stage (you have to click a button on the target website), but now always. Never saw a similar two-stage verification link though.
If you've somehow lost access to email, a typical pattern is that you can login to your account, update the username and receive a validation email at the new address to confirm its validity.
My company is an ISP, and most of our customers are not very "good" at using technology. Any yet, they do sometimes want to log into our dashboard for one reason or another, and it tends to be a lot of trouble.
We've found that:
- Many people do not have an email. Some people don't have a phone number. Many people have only one or the other, but not both.
- People typo their emails... a LOT. I initially had some very simple validation for email addresses, until I started getting droves of emails that were one character off. I'm at this very moment working on a feature to alert users if they type "gmail.co", "gmail.con" or "gnail.com", which are all very common (and two of which are completely valid domain names by the way!).
- Some people get confused by "creating a new account" or dealing with multiple accounts in general. They'll say "my email login didn't work." Well, to me it's obvious that they have a different password for different accounts, but to them it's not.
- Building on that, they are not great at password resets. The "send a password reset to email" thing is confusing to them, because from their perspective their email is the account. Am I resetting my email password?? They don't like it so they don't want to do it.
- Since we are an ISP providing customers with WiFi, there is also confusion between the WiFi password and the dashboard password. I've had people successfully reset their dashboard password, expecting it to also set their WiFi password.
- Literacy can also be less than ideal. I once reset a customer's WiFi password over the phone, and the new password contained an exclamation point. She didn't know what an exclamation point was. I got her to do SHIFT-1 eventually, but it took a while. (I found out later that nobody else sees an exclamation point as an "upside-down i", which is what I've always seen it as. The proper way to describe it to someone who doesn't know is "line with a dot underneath".) Now my password generator only uses A-Za-z0-9 (but not 0 or O).
So, I have been learning the hard way that not every person in the world is an avid Hacker News reader who knows what accounts and password hashes are and how everything works. And yet, these people deserve to be empowered by technology just like the rest of us.
The thing is, many of these folks are able to use software just fine, it's just that they have trouble getting logged in. It really is the logging in that trips everything up.
So I've been thinking lately that I want to fix this for my company, but I'm unsure what to try.
I had the thought of trying Webauthn, but that seems unusable for me as per this comment I wrote a few weeks ago[0]. If I could solve the problem in that comment, I think a lot of my customers would use "Login with TouchID", "Login with FaceID", etc.
Anyway, my point is that no, I do not think magic links are outdated. We use a lot of magic links. Need to update your credit card? We'll text you a link. Want to reschedule your install? We'll text you a link. This is the best way we've found to actually get our software into the users' hands.
For customers they seem like a super convenient thing, I was just implementing them in my app. Yes magic links have problems and it's probably making me lean more towards the "emailing a code" option now, some of those problems outlined aren't easy to ignore.
The app I'm working on, users would login probably once or twice a year. I just can't imagine they want to deal with passwords, especially because my app is very niche, they'd use it once a year for one thing only. What I can imagine them having to do is constantly use the "forgot my password" feature anyway.
For conversion easy logins are really important.Anyone have any better ideas than magic links, passwords or one time codes in email?
> Anyone have any better ideas than magic links, passwords or one time codes in email?
Passwords. Password managers are not a new concept, they have been around for decades by now, have deep browser integration (either because they often are part of the browser, or in the case of Apple, the OS), and are easily understood by users.
Out of thousands of people who used the system I only had 1-2 people who had issues. One was using their work email (why do people do this?) and I think it was being filtered and the other was using Yahoo but for some reason the emails were slow to deliver, 2-3 minutes (far from the only Yahoo user, only one that had issues).
Not really.
- Email deliverability is a serious issue - some well-known providers (Apple and Microsoft) can delay email up to five minutes because they're scanning it, and that's assuming that it didn't went to spam. Compared to 2FA login, that's an eternity.
- Also, speaking of scanning emails, some do "click" them to check that it's not a harmful page (Microsoft, Google Workspace if admin enabled it, Barracuda which is common on enterprise), rendering the link invalid.
- Not everyone keeps their email logged in (or uses a different app/client to keep them logged in), which results in worse experience.
- Most mobile email clients (Mail on Apple, Gmail, Outlook) by default launch a different window, meaning you're logging into the mail client and not the browser.