Broken authentication is the second-highest security risk for web applications. This usually means that session management and authentication aren'...
For further actions, you may consider blocking this person and/or reporting abuse
Sounds good on paper, but gets infuriatingly impractical very quickly:
Now I have to enter a password anyway, and deal with whatever added security my email account has. What's worse, I now have to input my email password on some random computer (compromised until proven otherwise), instead of a password for some random application I don't even care about. This isn't an improvement in any way.
A better workflow would be:
I realised this the first time I did this myself. So I send both the magic link and an OTP
So the user can enter the Pincode if he/she is in such a situation
OR
The link can just verify the login attempt. After the attempt has been verified then you log the user in on the device he/she initiated the login attempt. You can use sockets to make this happen
How do you go about implementing that last part? Where clicking the magic link on one device logs you in on another?
Not without some degree of back-end persistence, which I assume is the main reason it's not how what the article does. You'd need to create some sort of short-lived state in the back-end that gets cleared by opening a link in the email. The login-window could then just do polling, or use some more sophisticated method for waiting for the server to grant it access.
The only state is in the browser. On the server you just need to verify the token, which could be sent by the browser in the authorization header as a bearer token or in the body or in the url as a parameter or search term. (Sending in URL is an unforced error. It exposes the token, so dont do this in practice.) You should also sign with RSA keys vs secret, so you can verify the origin.
Regarding exposing the token. The magic url, which i hope there's a better term for, can point to a url on the server that returns html where the token and any user data are passed via session storage. It doesnt matter about the nonce. Sincei its now dead.
You say the state is in the browser, but there's not just one browser, but two, and they have no way of directly communicating. Or are you talking about the way it's described in the article?
I just don't open my email on some random computer. That's the whole point: if the default is having to type in the password of your some service on some random computer, suddenly having to instead type in the password to my main email account is not an improvement; it's a reason to stop using that application and look for alternatives.
Just stumped into this somewhat old post while searching one specific thingy around passwordless auth on Google, hence if I found it other users will and I think some points need to be discussed here.
While I understand the points mentioned above my question is... if you don't trust the random computer then why are you using credentials on them?
This leads to some assumptions, like you expecting Apps to trust computers that you don't trust yourself with the "user comfortability" argument.
Some common statements around cyber-security:
Following the rules above, if you had a regular email + password login and the
random computer
(or your main computer) is compromised, both your email and password will be leaked in any dump file across the internet, which hackers will use as dictionary to brute-force other Apps programmatically thus generating a somewhat up-to-date map of Apps you use with this email that match the same password, plus the email address will be sold to SPAM scums (which can lead to scams and/or the annoying task of cleaning 50 emails daily).Of course you can point to the argument of "you should never use the same password twice" but this is, in my opinion, the silliest thing after
the password must contain at least 1 uppercase, 1 lowercase, 1 number and 1 special character
while being even worse for the UX, because no one will ever remember the exact same password used here or there.We have then few good options:
Best regards
This is almost a year old now, but I randomly stumbled upon this and figured I'd address it, because it's honestly no less relevant now than it was a year ago.
Here's the point:
As a user, one should weigh cybersecurity vs. practicality when using computers. This includes things like re-using the same password for several unimportant services where the risk of having an account stolen is minimal.
I'm not gonna have a unique super-secure password for my grocery list; what's the worst that could happen? A hacker remove orange juice from my list and I have to drink water instead? Yea, not happening.
So when you offer a service like that, you should keep in mind that a user might be okay to log in to your service on, say, a public library computer, but might not be okay with logging in to their main email account on the same computer.
Asking a user to log in to their mail account on the same computer that they want to use a service of much lower cybersecurity relevance is problematic because you're now forcing them to take a much higher risk when all they wanted was to quickly make sure they had "flour" on their shopping list while their phone battery was dead.
Trying to get users to treat each and every online service like it has the same relevance to their online security is a way to get them to be neglectful of online security on all their services, including the ones that really matter.
To update this still-relevant topic, nowadays you have plenty of 2FA solutions that you can get for free (keycloak has built-in OTP thingy, one can self-host a Hanko server and so on and so forth).
Leaving this aside, I understand your points, though the places which allow you to use a computer (library, parlour...) also happen to have USB C, lightning and/or Wireless chargers which might prove more useful than a computer to log on just to check your grocery list (seems quite an unreasonable scenario if you ask me).
Assuming that users would be savvy and aware enough to have categorised apps, each group with its own properly differentiated password... is probably assuming too much. Moreover one would need to assume as well that these users will maintain these categories adequately.
Now imagine a much more plausible scenario; you have multiple bank accounts, one of them is unused since long ago, you have less than 10 bucks there just because you need to be in positive so the bank doesn't shut the account, no movements for the past 14 months, or 35 if you will. It would fall into the "not important" category, right? What can someone do? Stole you 10 bucks? meh...
This bank now decides to launch certain campaigns that raise the interests for storing money there (3.79%) way over what your current savings account offer (2%), so you obviously decide to switch one for the other.
What would an average user do? Simply transfer the funds and call it a day.
I understand that you look at the problem from your prisma and "sigh* it's obvious" runs through your head, but we're a minority, even half of the IT people I know would probably forget or not care enough to change the password!
Luckily banks have tones of obligations and some of these are the number of steps to log in, 2FA, biometrics, session duration and so on, because cybersec, software development and legislators assumed that people will use the same password for both their bank and their 9Gag account.
Being -usually- in the project development side, it's not that I will see any project as being in the "important" category of the people and it's not people what we're trying to safeguard in the first place but the data we are storing, just as a side-effect, one ends up protect people from doing the dumbest shit possible with journeys that involve 2FA in some way or another (not necessarily email) when necessary (and specially in Fintec or anything involving people's money or sensible data).
Lastly as I said before, if one gets a pair of credentials that still work is much easier to find other passwords using different techniques and knowledge. E.g. people usually change just 1 or 2 characters when updating the password, most people's password contain their birth year and son on and so forth. Add OSINT to the equation and you got the combo.
I agree.
I agree that this is a better workflow
Nice article! Leaving about whether this method is safe or not, as already in discussion by our dev members, I want to highlight one thing here.
In
/login
API (snippet below), if an email is not found, then we should not tell the user that the email is not in our system. This is a security risk by which a hacker can identify valid emails in a system.Hence,
/login
API can just respond with something generic like,You will receive an email with the link if an account is found associated with this email.
😁Excellent point to bring up! Same goes for signups. You should always say "You'll receive an email" and for existing emails, simply state that "Someone tried to sign up with us. If that was you - Log in here instead"
That way a malicious user/attacker can't enumerate the existing emails at a large scale
Yeah, I know this is the preferred "safe" response, but can be frustrating when you're "sure" that was the email (I have many) and don't get a response.
I would prefer an email be sent anyway with a message telling me that the email provided wasn't registered so at least I know the process is working.
I don't see a security problem with this approach? Though it may result in an increase of bounced emails from fat fingered entries.
The line 'const email = req.body.email' is related to what the user types in the input element.
The if statement only checks if the value of email is truthy or not. So, only checks if the user typed something on the input element.
if I was a hacker, I should know from the message that my details is not, hence no email with some link.
so to me it's still the same.
I was so hoping this would talk about how to easily integrate WebAuthN, but instead unfortunately, it's sharing more about the bad suggestion of legacy passwordless.
SMS is unsafe, email is vulnerable and provides bad UX. There's way more problems than this, but they've been listed many times before
It is no longer a best practice to force a password change after a period of time. This according to NIST, Microsoft, and the man who suggested the idea in the first place.
See Best practices for existing authentication systems, the paragraph before the conclusion.
The described solution actually introduces attack vectors; what if someone (else) has access to email / phone? They will be able to login.
Someone said "There is a barrier to access a mailbox.".. there is not! If I already have your mailbox then I can get the app "access" if an email is sent for the access... This is a main reason for 2fa and such. (the same goes for phone number).
The only real solution for passwordless (sic) authentication is either an app or a (usb)key. See for example the auth0 implementation for details. (or the MS Authenticator).
The idea of implementing an own authentication layer is outdated anyway.
Why? You do not want a crappy/outdated implementation, that you need to keep updated and secure, to expose your credential data.
Whilst the idea of implementing your own authentication may seem outdated to you, it's
1) always good to understand how the services/libraries you use work behind the scenes
2) important to understand that often you'll require custom solutions and services like Auth0 are very rigid in certain regards
Dangerous.
The attacker steals the mailbox and gets access to all applications/websites.
I think the best way is a custom stateless JWT that contains encrypted userID and timestamp and included in the request as both Cookie and a part of the request body (JSON). The server then compares JWT from Cookie and JSON and if they match -- keeps the user logged in and retrieves needed info from DB with userID.
A fine article, for a topic that is only becoming more popular.
This concept is true for the phone number, but I don't think so with email.
There is a barrier to access a mailbox.
Just a fyi, you're not actually creating the JWT with an expiration date. You're simply encoding the expiration in the payload.
You actually shouldn't be putting any sensitive data in the payload as that data can be publicly seen.
Great article 👍
Nice post, very helpful as a refresher. 😄
I thought this would be a tutorial on the Node.js implementation of SQRL.
Too bad.
@darkwiiplayer You could check this:
magic.link/
But it's too costly I think :)
I mean, if you're going to pay for anything, the extra cost of having a small database isn't really a big deal. It's not like it's hard to build such a login system on its own if you accept that you'll have to persist some data, which is what the internet has mostly been trying to get away from.
hello Melicia, I have gone through your work and it's awesome.
Just that I could not see where user email was verify from the data base, before login in automatic.
Nice job. I have a question, how are you checking the token is no longer valid after used?
Is there a good passwordless implementation? Gladly open source. Auth0-Passwordless is a pay-service and the passwordless strategy from password js has not been updated for 5 years.