DEV Community

Cover image for Password-less auth in Rails

Password-less auth in Rails

Pete Hawkins on October 06, 2021

One of the weakest points in your system can easily be end users credentials. It’s easy to forget that most people don’t enable 2FA, use a password...
Collapse
 
fdidron profile image
Florian Didron

Hi Pete, very interesting approach !

One thing I would tweak though is I would keep the same auth flow for existing and new users. In the case of new users I would force them to enter their extra info after auth.

The rationale here is that I wouldn't want anyone guessing if an email is already signed up to my system.

Collapse
 
clavinjune profile image
Clavin June

Hi Pete! Great post you published there.

I like the idea that maintaining password is hard, that even people are monetizing it by building a password manager.

But, instead of otp that sent to the email, wdyt of Using MFA directly? so the input would be email+MFA.

What I think is, that would save us developer, a mail service cost.

Collapse
 
koas profile image
Koas

Hi Pete! Thanks for the article, it was a really interesting read!

May I ask you a question? Since when using this approach the user has no password at all, how could you protect some critical settings of the app? For example, in my app if you want to change the MFA method, delete sessions opened in other browsers or close your account you must enter your password to be sure it's you the one requesting the action.

But if the user has no password, how could we achieve this? The only way I can think of would be sending an email to the user with a link to confirm the action, but that seems a bit risky to me.

How do you think this could be done? Thanks!

Collapse
 
phawk profile image
Pete Hawkins

Koas, that’s a great thought! For maximum security I haven’t thought of how to also do MFA with this approach. I guess you could also use an authenticator app or SMS alongside the OTPs through email. It just seems strange typing two 6 digit codes in, but I guess that’s fine.

I would send them another OTP via email and show a modal that makes them enter it. Since the salt is different every time OTP is used, there's nothing wrong imo with sending more of these codes to the email address.

I'd be interested in knowing why you think sending an email seems risky? Given that a password can be reset through email, surely traditional passwords carry the same risk?

Collapse
 
koas profile image
Koas

Hi! Thanks for your reply! The modal asking for the OTP is a nice solution, much easier than what I thought.

About the "risky" part: I use the idea of entering your password to change critical settings to avoid this situation:

  • I'm working at my PC, and leave for the bathroom. I have my app session open.

  • The bad guy reaches me PC and access my app settings, removing my MFA setup or even closing my account.

This is of course a really edge case, but I usually am quite paranoid, so I want to do my best to avoid this. If my password is required to change some critical settings then the bad guy can't do it.

If the OTP is sent to me via email and, still considering this edge case, I have my email client open then the bad guy can easily get the code and do nasty things.

This is why I consider the email method a bit "risky". It wouldn't protect our account if the bad guy gains access to our computer while we're away. Please note the quotes, I know this is really an extreme case, but you never can be too cautious regarding security.

I know you may think "If the bad guy has access to my computer surely he'll be able to log out, request a new password via the "Forgot your password?" and then do all the bad things". That is absolutely true, but this is where the login and password change Telegram notifications come to our rescue:

  • When someone enters your account you can be notified via Telegram (the web app bot sends you a message). The same happens when your password changes.

  • If you are in the loo of course you have your phone with you (xD), so you get the message and instantly know something's wrong. The bot has an "Under attack" command that closes any open session on any device, changes your password to a random one and sends it to you. Now the bad guy can't access your account with the restored password, and must begin the "Forgot your password" process again (which you can respond in the same way).

Of course, these notifications can be turned off and you can choose not to connect to the Telegram app bot, but for security paranoids like me these measures add an extra layer of security to the app.

As I'm writing this (rubber duck mode enabled) I'm thinking thay maybe a nice way to avoid the bad guy resetting your password would be asking for the MFA code (if enabled) before restoring it. That would prevent anyone that can access our email to reset our password unless they had access to our phone too.

Sorry for the long message! I'd like to know what do you think of this method, am I pushing it too far? Do you think it's worth it? Any other ideas on this subject would be greatly appreciated!

Thread Thread
 
koas profile image
Koas

A quick answer to myself:

There would be no need to ask for the MFA code when resetting the password: if MFA is enabled the bad guy won't be able to access the account even with the correct password.

Thread Thread
 
phawk profile image
Pete Hawkins

This is interesting, and perhaps a little bit extreme for the use case and type of user I'm using it for, but I do have an idea that’s kinda like MFA and would potentially solve this for you.

If you made the user create a 4 digit pin code when signing up. This pin code is then what's requested when you go to take these sensitive actions within the app. The UX of it would be quite nice as well, it would be a lot faster to type in a 4 digit pin from memory than to lookup a password or get a code from email.

I'm not quite sure how you would handle resetting your pin if you forget it though.

Hope that helps!

Thread Thread
 
koas profile image
Koas

The pin code is a great idea, that's what my bank uses for signing operations inside their app. You have username and password to access your account, where you can see your balance and movements but if you want to do something sensitive like transfer funds to another account you have to enter some digits of an 8 digit pin (for example, digits 1, 5, 6 and 8, changes every time).

Thanks for your replies!

Collapse
 
tioneb12 profile image
Tioneb12 • Edited

Hello Pete, Great post you published there

I have some old people, and they have some problems to connect to their account.

If the email take a long time to arrive in their emails box, they generate a new one, then another and another new code (by the auth page).

A solution it's to add a redirect_to if session[:email].present? in the AuthController :

def show
   @email = session[:email]
    render "auth/verify" if session[:email].present?
  end
Enter fullscreen mode Exit fullscreen mode

Is it a good idea ?

But I think, it will better, if a auth_code is always valid don't generate a new code but resend the same.

How can I do that ?

Collapse
 
phawk profile image
Pete Hawkins

Hey @tioneb12

You would need to make changes to the UserLogin#start_auth method, that it either takes in a salt, or generates one. Currently it generates a new salt every time start_auth is called. So you'd want to first check for the existance of the salt in the session. Also after a successful login, you probably want to clear the salt.

Hope that helps!
Pete

Collapse
 
phawk profile image
Pete Hawkins

I hope this proves useful to anyone thinking of password-less authentication. If it gets much attention I might consider wrapping it up in a gem to make the install process even easier.

I would love to discuss all aspects of this further, so if you have any UX, security or general thoughts please ask me anything!

Collapse
 
spgregory profile image
Shane Gregory

Wouldn't emailing a link with a JWT token encoded with a private certificate be more secure?

Collapse
 
phawk profile image
Pete Hawkins

That’s interesting Shane, I would say if you also ensured there was a unique salt stored in the browser session, then yes. Although this poses a UX concern, what if the end user requests the magic link on their desktop, but opens the email and taps 'login' on their phone? Then this approach doesn’t work, or you need to get rid of the salt, which IMO adds another layer of security, ensuring you can only login from the browser that requested the login.

The only thing you are getting from the JWT approach is a longer token. Both approaches assume email is a secure protocol, but then so does every app that implements password resets.

I don’t think either approach is necessarily bad or weak, but would like to be challenged on that!

Collapse
 
vdelitz profile image
vdelitz

hey man, just read your article on passwordless auth in rails and learned a lot - thanks so much! In the beginning you mention, that you don't like to rely on third parties for authentication (which I can understand). What would be a situation or requirement where you would still consider to use a third-party for authentication?