Closed invertium closed 7 months 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.
@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.
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).
In case it's useful, I built a small utility lib to handle auth links awhile back; it's been performing well:
Notion does this as well.
This opensource django project does this as well, even more features are unlocked when you enter user data
@marquicus did you include the link you meant to? I'm not sure I see the relevance of your suggestion to this conversation.
@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
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
this is definitely an interesting feature, has it fallen through the cracks though? @migueltorrescosta any feedback from maintainers if PRs would be evaluated?
Not yet 🥲
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?
@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).
@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.
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.
I would like to asses how this can be added to allauth. With respect to emailing codes, I see the following related features:
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
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
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.
With respect to passwordless login, I would like inventorize what the requirements are. Discussion points:
How does this affect signup? Do you still need to enter a password, or is the password field completely left out for both login and signup.
If this feature is turned on, do the password change and reset flows serve any purpose, or, should those be removed altogether?
If the password field (and related flows) are not removed, how is this best presented in the UI? A separate "Send me a magic login link" action?
Any input is welcome!
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
@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".
@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.
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
@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.
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...
@DanielSwain The above implementation is independent from allauth.mfa
.
I've only had a brief look so far... but absolute legend 👌 It looks perfect!
allowed_chars = string.ascii_uppercase.replace("I", "").replace("O", "")
maybe we should include numbers too but drop 0
and 1
? Extremely minor, but would add more possible combinations (not that brute forcing is possible with LOGIN_BY_EMAIL_MAX_ATTEMPTS
at something sensible).ABC DEF
is easier than ABCDEF
. Can the code be sent like this and the space be optional on entry? (We've overridden the MFA forms to allow the code to have a space (it's cleaned out) in it too as some apps like Authy show it like this).This looks great to me. Really excited for this!
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:
ACCOUNT_USERNAME_REQUIRED
setting provides for not having to enter a username, but I don't think there is a way to prevent a user from having to enter a password other than creating a custom signup form and signup view. Is that correct?ACCOUNT_AUTHENTICATION_METHOD
could, perhaps, be ignoredMy 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.
@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:
TODO:
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?
@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.
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)?
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:
ACCOUNT_RATE_LIMITS = {"confirm_login_by_email": "3/3m/key"}
Here, key
either needs to be the session key. But as mentioned, the rate limit is a more general mechanism, it allows you to specify 3/3m/key,20/m/ip
as well. But that wouldn't make any sense. It would also make it unclear what the max. time is the procedure is allowed to take -- is that 3m, or 1m ? So, that means you would need to disallow such configuration... but it basically shows that we're using something for which it was not intended. The code login is no rate limit in the sense that you can have 3 attempts each 3m as 3/3m/key
would suggest... you can have 3 attempts. And, if you don't do so within 3m the window of opportunity is gone.
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.
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.
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.
Thanks! For us, we have no interest in dropping passwords altogether. I will see if I can find a time to try this out.
Closing -- #3725 is merged.
This is amazing work! Thank you, @pennersr .
Logging in with a magic link like on slack or here.