Devise: Magic link sign-in flow (password-free logins) [Feature Request]

Created on 15 Dec 2017  ·  12Comments  ·  Source: heartcombo/devise

Magic Links are becoming an increasingly popular approach to logging in, thanks in part to Slack.

In a Magic Link login flow, a user is emailed (or texted!) a link to automatically log into their account by email, removing the need to remember a complex password. From a UX standpoint, the experience excellent. Adding support for Magic Links through Devise would give Ruby on Rails in general a powerful leg up over other frameworks and authentication libraries.

A secure solution / proposal for how it could be added:

Since Devise already has comprehensive support for unlocking an account via an unlock_token or a password_reset_token, an eleventh module -- a standalone Magic Link module -- with controller + views similar to the _Recoverable_ and _Lockable_ modules could just be added without complecting devise's existing modules or codebase too much.

Thoughts?!

Most helpful comment

I took a stab at a gem for this feature. Feedback or PR's would be greatly appreciated! https://github.com/dvanderbeek/magic-link

All 12 comments

Screenshot of Slack's magic-login flow:

screen shot 2017-12-14 at 3 18 12 pm
screen shot 2017-12-14 at 3 18 20 pm
screen shot 2017-12-14 at 3 18 30 pm

While the 'magic link' mechanism is great from a UX point of view, I have yet to see an implementation that is not trading security for ease of use. With that said, I'm hesitant to see this implemented in the devise core, since devise takes security very seriously and is expected to do so.
The magic link is actually very similar to the 'insecure sign in' after confirmation that at one time existed in devise and was removed, for good reason.
If implementations wish to override devise's mechanics to allow this behavior, so be it -- to have this be something in core that comes with the connotation of being secure is my main disagreement.

@cross-p6 What is it about a magic sign-in link/token that makes it insecure compared to a password reset link?

At one point, pre 3.1 iirc, confirmation tokens (and password resets too?) allowed the user to login. This was seen as a security and risk since it would mean that simply having a confirmation token would allow a user to circumvent the auth process. For a full write up, see http://blog.plataformatec.com.br/2013/08/devise-3-1-now-with-more-secure-defaults/

@cross-p6 Thank you for sharing this. However, I don't believe what you posted invalidates this approach for handling magic links.

From the devise write up you linked to:

Automatically signing the user in could also be harmful in the e-mail reconfirmation workflow.

The write-up then explains how confirmation tokens could become a security issue (my emphasis added):

Imagine that a user decides to change his e-mail address and, while doing so, he makes a typo on the new e-mail address. An e-mail will be sent to another address which,* with the token in hands, would be able to sign in into that account.

If the user corrects the e-mail straight away, no harm will be done. But if not, someone else could sign into that account and the user would not know that it happened.

For this reason, Devise 3.1 no longer signs the user automatically in after confirmation. You can temporarily bring the old behavior back after upgrading by setting the following in your config/initializers/devise.rb

From this write up... we can see the security concerns are not that automatic logins via email are inherently dangerous... but rather, that automatic login links via email are dangerous if sent while in the context of a user changing their email address. The danger being that the user could mistakenly give someone else access to their account in a confirm-your-email confirmation email if they made a typo while in the process of changing their account's email address.

For confirmation links sent right after changing an email address, this is a valid security concern, and no doubt one that Devise was right to patch up. But it's not a security concern relevant for a magic login link, which are sent when the connection between a user and their email address is unambiguous (especially if a user has confirmed their email address).

In such cases, magic links would be no more dangerous than Devise's default out-of-the-box configuration for password resets, where it's assumed that anyone who can prove ownership of an email address, and ownership of a token recently-generated for that email, is someone we can trust.

Thank you for the feature request but we don't plan to add any new feature to devise in the feasible future. I recommend you to try to implement this feature as a devise plugin. If it gets popular we can think in integrating in devise.

+1

I took a stab at a gem for this feature. Feedback or PR's would be greatly appreciated! https://github.com/dvanderbeek/magic-link

@dvanderbeek Very cool! I just posted about this on Reddit in hope to get some additional attention on it. When the gem's documentation is fleshed out a bit this would definitely be worth posting to Hacker News also.

How can i mplemented >>>?

@dvanderbeek David, I think your implementation was a bit too early. The concept has been around for a while but it seems it's currently gaining in popularity. It's very surprising to find that it's still not there as a standard devise extension. I'll take a look at your implementation! There are gems now that bring 'passwordless' to Rails but they are standalone but I guess there is a serious case for an integrated solution because I assume there are more applications that would like to provide the user with options (with password or without) for example.

I also took a whack at this for an app I'm building: https://github.com/abevoelker/devise-passwordless

Feedback and contributions welcome!

I need to add tests before bumping to 1.0 but I've tested it manually quite a bit in the Rails 6, Devise 4.7 app I'm working in.

I'm not super pleased with generating two controllers to do the work, but the reason is because it's not easy to re-use the existing Devise SessionsController to patch in a new "show" action needed to receive the magic links, because I don't see a way to hook into Devise's route mapping load process to add the action (several monkey patching attempts failed).

Alternatively, making a whole new controller that duplicates everything SessionsController does, just to allow adding the new "show" action to it, both breaks expected paths in existing view templates (session_path, new_session_path, destroy_session_path etc.) and seems like a recipe for future breakage in trying to keep the duplicated logic in sync with SessionsController.

Maybe someone more familiar with Devise could come up with a better solution (PRs welcome), but what I did is -

  • Subclass the SessionsController for the given resource, and only override #create in order to send the magic link email instead of attempting actual sign-in. All other SessionsController goodness remains unchanged so registration, signing out, etc. works as expected with existing path names
  • Create a new MagicLinksController for the given resource, which has a #show action that receives the magic links and handles sign-in
Was this page helpful?
0 / 5 - 0 ratings