pennersr / django-allauth

Integrated set of Django applications addressing authentication, registration, account management as well as 3rd party (social) account authentication.
https://allauth.org
MIT License
9.56k stars 3.04k forks source link

Login using code (was: Magic Link Login) #1472

Closed invertium closed 7 months ago

invertium commented 8 years ago

Logging in with a magic link like on slack or here.

pennersr commented 8 years ago

I am wondering if there are examples out there where this type of login is actually being used without having a mobile app involved? E.g. the slack link mentions: "On mobile, Slack can email you a magic sign-in link ✨ to make signing in easy.", and the auth0 is also about mobile apps.

borfast commented 7 years ago

@pennersr, Medium uses links via email to login users. You either sign in with Facebook, Twitter or Google (using oAuth), or they send you an email with a login link. In other words, you never have a Medium password.

invertium commented 7 years ago

Facebook does this as well, when forgetting your password. It also enables creating an account for the user and letting him set the password after. No need to set a dummy "default" password (like first name).

lukeburden commented 6 years ago

In case it's useful, I built a small utility lib to handle auth links awhile back; it's been performing well:

charleshan commented 5 years ago

Notion does this as well. image

marquicus commented 5 years ago

This opensource django project does this as well, even more features are unlocked when you enter user data

https://healthchecks.io/

lukeburden commented 5 years ago

@marquicus did you include the link you meant to? I'm not sure I see the relevance of your suggestion to this conversation.

marquicus commented 5 years ago

@lukeburden https://github.com/healthchecks/healthchecks/ was just an example to penners old question (sorry for my very too late suggestion but I think it's a relevant project who works with magic links).

I've used django-sesame before and handles magic links very good but you need to modify some forms that I think allauth could control as well, I hope this can be more clear

migueltorrescosta commented 1 year ago

Reviving interest in this feature. I am not super familiar with django-allauth personally, but I'd be happy to make a PR to add support to this auth method if the repo owners would be happy to include this functionality

HaddadJoe commented 1 year ago

this is definitely an interesting feature, has it fallen through the cracks though? @migueltorrescosta any feedback from maintainers if PRs would be evaluated?

migueltorrescosta commented 1 year ago

Not yet 🥲

tohid4n commented 1 year ago

Hey, I am using Django MagicLink with Django allauth (for Social auth like Google) Do I get any problems, cause, Django allauth uses passwords and Magiclink uses a link?

pfouque commented 10 months ago

@pennersr Are you willing to accept a contribution about that? With the recent addition of "Re-authentication" feature, magic link solutions on top of AllAuth are becoming tricky since some users can connect but not re-authenticate (because they have no password or mfa).

pennersr commented 10 months ago

@pfouque Definitely, but we need to see how this functionality relates to what is discussed/prototyped over at https://github.com/pennersr/django-allauth/issues/3550. So we need a proper proposal first.

DanielSwain commented 8 months ago

There's a very interesting discussion on the Security Now podcast about how magic-link login makes so much sense. Steve commented: The problem for our future is that email loop login makes a horrible kind of sense for any website that gets to choose whether or not they want the liability of storing the hashes of their users' potentially crappy passwords. It's easy to imagine websites deciding that they'd prefer to ask their users to obtain a per-login token from their own email.

The paragraphs before the above-highlighted statement provide the background. Steve was responding to a user who had stated: By requiring an email to log in, the host company hoists account breach liability off of their own shoulders onto the email providers.

I, too, would like to see this feature implemented in allauth.

pennersr commented 7 months ago

I would like to asses how this can be added to allauth. With respect to emailing codes, I see the following related features:

Email as a second factor

You enter your email address and password, and as a result you end up on a page where you need to input a code which has been sent to you by mail.

https://github.com/pennersr/django-allauth/issues/3550

Verify by code

Currently, email verification requires you to click on a link sent to you by mail. Instead of that (or on top of that), it could become possible to verify an email address by code. So, after signing up, or after adding an email when already logged in, you are presented with a form where you need to input a code that is sent to you by mail.

https://github.com/pennersr/django-allauth/issues/2061

Passwordless ("magic link") login

In order to login, you input your email address. No password is needed. Then, you are presented with a form where you need to input a code that is sent to you by mail.

https://github.com/pennersr/django-allauth/issues/1472

pennersr commented 7 months ago

With respect to passwordless login, I would like inventorize what the requirements are. Discussion points:

Any input is welcome!

violuke commented 7 months ago

Firstly, thank you @pennersr for everything you've done with this package, especially the recent MFA and SAML support.

In our use case, we would like this to simply be an alternative login option. You can still login manually with email/password or via a social account, but there's a third option where you can get an email with a magic link. This would be useful to allow login if you've not got access to your password, but don't want to reset it (e.g. you have it saved in a password manager on your normal device, but you're on a different device now).

What would also be great for us and is similar would be for you to be emailed a (for example) 6 digit code that you can use as a "temporary password". This would only be valid for a very short time, say 5 minutes, and so in my example use case of being on a different device, you wouldn't need to be logged into your email account on this other device either (say you are logging in on a laptop, but you have email address on your phone). I'd probably "expire" this code immediately if it's entered incorrectly just once and a fresh email can be sent.

In both versions (emailed magic link and magic code), you would still have to complete MFA if it's enabled on your account.

Thank you

pennersr commented 7 months ago

@violuke Thanks for the input. With respect to the 6 digit code, that is actually the more secure way of dealing with this feature versus adding a link, as there is no link in an email that can be intercepted, nor are people getting used to the bad habit of clicking on mails in links. I also see that Slack only offers the 6 digit code these days. So "magic code" definitely is preferred over "magic link".

DanielSwain commented 7 months ago

@pennersr, you wrote:

Email as a second factor

You enter your email address and password, and as a result you end up on a page where you need to input a code which has been sent to you by mail.

I am interested in having capability for the user to enter only their email address (no password) and then receive a code that is only good for a very short (but configurable) period of time. If 2FA has been set up, then that would also be a part of the required authentication actions. Following on with what Steve Gibson was talking about, he mentioned that if you have password reset capability set up on a website, then requiring a password as part of an email-token-based workflow is superfluous because if someone has access to a user's email, then they could always just use the password reset page and change the password. The important thing as far as guaranteeing security is that a user is the only one who can access their own email account.

Also, I agree that the magic link workflow is not desirable.

violuke commented 7 months ago

Thanks @pennersr, all very good points. Personally, I'd happily forget about the "Magic link" and just go with a one time code in the email 👌 that would be a fantastic feature

DanielSwain commented 7 months ago

@pennersr One other thought on having login via an emailed code (and this probably goes without saying), but I am hoping that this functionality would be built directly into django-allauth and would not require allauth's mfa. I recently implemented 2FA in a project and chose django-two-factor-auth instead of allauth mfa because it includes support for texting or calling with sign-in codes and allauth mfa didn't. Also, django-two-factor-auth is maintained by JazzBand and so should be stable.

pennersr commented 7 months ago

For those interested in this functionality, can you have a look at the feat-login-by-email branch (https://github.com/pennersr/django-allauth/tree/feat-login-by-email) ? It contains a fully functional implementation. It still needs the usual polish though, documentation and test cases...

pennersr commented 7 months ago

@DanielSwain The above implementation is independent from allauth.mfa.

pennersr commented 7 months ago

image image image

violuke commented 7 months ago

I've only had a brief look so far... but absolute legend 👌 It looks perfect!

This looks great to me. Really excited for this!

DanielSwain commented 7 months ago

A couple of thoughts here: The ACCOUNT_LOGIN_BY_EMAIL_ENABLED setting that you have created appears to establish emailed-code login only as an alternative method, not as the exclusive method for signing in. If I set up a site for signing in via an emailed code, then I would want that to be the ONLY method of signing in. The benefit of implementing account sign-in via emailed token while excluding the username/password signup method is that users never have to manage a password, and developers don't have to be concerned about users having weak passwords or passwords that they've used on other sites. Some implications of allowing login ONLY by emailed code would be:

My second thought relates to ACCOUNT_LOGIN_BY_EMAIL_MAX_ATTEMPTS. Why is this setting needed in addition to ACCOUNT_RATE_LIMITS?

@pennersr Thanks for all you've done on this so far and for your consideration of the ideas presented. Also, I'm wondering if the name of this issue should be changed from "Magic Link Login" (or at least be modified) to something else.

pennersr commented 7 months ago

@violuke:

maybe we should include numbers too

Given the login-attempts-limit it is already not feasible to brute force the code. So I don't really see a reason to increase the visual complexity by mixing characters and numbers.

the format ABC DEF

Yes, some sites also use a nice JS input widget that forces the space in the middle while inputting. Though, that is really out of scope for allauth, and can be achieved by altering the templates. So then the question remains, given that we do not have a proper widget, is it still better to use "ABC DEF" in the mail? It is indeed more readable, but copy pasting the code won't work anymore (you cannot double click as it would only select "ABC". Also, we would need to make the choice between "ABC DEF" and "ABC-DEF", and that choice would also have to match a potential widget. So, all in all, I do think we need to add a (customizable) clean function that strips spaces et al, but as for display choices, I think we better leave that up to the ones overriding the templates?

@DanielSwain:

as the exclusive method for signing in.

Must admit, I would personalyl advise against that method, as it comes with some security tradeoffs. For example, I could make your life difficult trying to get into your account by overwhelming the system with code requests. You wouldn't be able to login when this method is the exclusive one, with password you still can.

Having said that, it is really not that difficult to add this, do I am wondering if there is sufficient demand for this? Could we perhaps collect a few good examples of (well known) sites that go this route?

Rate limits

Rate limits are rather indirect. For example, employees within a company may all share one and the same IP, so trying to rate limit by IP often needs fine tuning. Now, for this feature we need to prevent 2 things:

pennersr commented 7 months ago

TODO:

DanielSwain commented 7 months ago

Must admit, I would personally advise against that method, as it comes with some security tradeoffs. For example, I could make your life difficult trying to get into your account by overwhelming the system with code requests. You wouldn't be able to login when this method is the exclusive one, with password you still can.

When rate-limiting is applied via ACCOUNT_RATE_LIMITS, wouldn't the same possibility of being locked out (for a certain time) exist for the standard login method which requires input of username and/or email plus password? And couldn't we somewhat mitigate what you are talking about on the Login using code page by employing a captcha?

Also, shouldn't rate-limiting be handled in one place (the ACCOUNT_RATE_LIMITS setting) rather than having a separate setting for Login using code? Is the separate ACCOUNT_LOGIN_BY_EMAIL_MAX_ATTEMPTS setting necessary if ACCOUNT_RATE_LIMITS is being used?

pennersr commented 7 months ago

@DanielSwain:

wouldn't the same possibility of being locked out (for a certain time) exist for the standard login

The standard login does not send an email, logging in using a code does. Hence, the latter typically has to be subjected to way more strict rate limits compared to the former, otherwise your email server is at risk of being blacklisted.

Also, shouldn't rate-limiting be handled in one place

But this isn't a rate limit. A rate limit represents a number of actions per time unit, per some key (e.g. IP). Now, that mechanism could be reused, but then what would the time unit be? That should then equal the ACCOUNT_LOGIN_BY_EMAIL_TIMEOUT ... Also, the key would then need to become equal to request.session.session_key or so... all in all, not sure if forcefully the rate limit mechanism for this makes sense.

DanielSwain commented 7 months ago

Isn't ACCOUNT_LOGIN_BY_EMAIL_TIMEOUT just the number of seconds within which the code can be used to sign in? That is different than rate-limiting the number of times an email is sent after an email address is submitted to retrieve a code. I do see what you mean about needing to cap the number of emails sent because of the potential of having the server blacklisted, but wouldn't that same reasoning apply to the password reset page (or for that matter any other page that triggers the sending of an email)? You already have rate-limiting for "reset_password" within ACCOUNT_RATE_LIMITS, and I see that several other of the keys within ACCOUNT_RATE_LIMITS apply to sending out of an email. Would it make sense to define, within ACCOUNT_RATE_LIMITS, a "reset_by_code" key (or "reset_by_emailed_code" if you want to distinguish between emailed codes versus SMS'ed codes)?

pennersr commented 7 months ago

We're having 2 topics here that we need to separate:

1) The security concern that only offering login-using-code makes it easier to prevent other users from signing in.

2) Whether or not the timeout and max. attempts should be separate settings or a rate limit.

As for 1):

but wouldn't that same reasoning apply to the password reset page

Yes, but not being able to reset your password is not as severe as not being able to login. Imagine being an admin, and you cannot login into your own site because somebody is targetting your login-using-code page with your email address.

Ad 2): For logging in using a code, we need two things:

I see that several other of the keys within ACCOUNT_RATE_LIMITS apply to sending out of an email.

For codes, there are 2 limits involved. One, is the sending of the actual email -- that one is present as part of ACCOUNT_RATE_LIMITS just like the password reset mail. The other, actually inputting the code, is not for above mentioned reasons.

DanielSwain commented 7 months ago

Here are a couple of things I came across in django-otp while working on another problem this evening that might (or might not) be of use in your thinking as you implement Login using code:

An interesting comment within the EmailDevice declaration [bracketed text added by me]:

Note that if you allow users to reset their passwords by email, this [emailed codes] may provide little additional account security.

Also, this explanation of how throttling is implemented for HOTP and TOTP devices.

Your indulgence of, and your replies to, my comments are much appreciated.

pennersr commented 7 months ago

PR #3725 is up for review, which completes the magic code login functionality. If there are suggestions to improve overall rate limit handling, let's discuss that in a separate ticket. As for dropping passwords altogether and exclusively logging in using codes, it's better to take one step at a time. First, let's get some mileage and get this feature in, while we can have further discussions in a separate new feature request as well.

violuke commented 7 months ago

Thanks! For us, we have no interest in dropping passwords altogether. I will see if I can find a time to try this out.

pennersr commented 7 months ago

Closing -- #3725 is merged.

Flimm commented 4 months ago

This is amazing work! Thank you, @pennersr .