kratos icon indicating copy to clipboard operation
kratos copied to clipboard

Replace magic links with TOTP OOB codes

Open aeneasr opened this issue 4 years ago • 18 comments

Is your feature request related to a problem? Please describe.

As we've seen in several issues #1202 #1142 the current link strategy is flawed because email clients with antivirus open the link and invalidate the token.

Describe the solution you'd like

Instead of relying on links we should use recovery / verification codes (TOTP) which have enough entropy to avoid distributed brute force attacks meaning at least a 8 char alphanumeric password.

This strategy would deprecate and eventually fully replace the current link strategy.

Describe alternatives you've considered

Resolving this issue in the link strategy is difficult because we need workarounds like UA detection. Antiviruses probably spoof this UA to avoid detection, making it a cat-and-mouse game.

aeneasr avatar Jun 21 '21 09:06 aeneasr

Other references I've found:

  • https://github.com/opencollective/opencollective-frontend/pull/5476 - using heuristic based approach which eventually leads to the cat/mouse race of adjusting defenses (on the antivirus) and adjusting evasions (on our end). IMO a flawed approach as also discussed in #1142

  • https://auth0.com/docs/connections/passwordless/guides/email-magic-link with limitations such as:

    With magic link transactions, both the initial request and its response must take place in the same browser or the transaction will fail. This is particularly relevant for iOS users, who cannot change their default web browser. For example, the user might make the initial request using the Chrome browser, but when the user opens the magic link in their email, iOS automatically opens it in Safari (the default browser). If this happens, the transaction will fail.

    Interestingly enough, it appears that Auth0 has the same issues as observed here and they have not been fixed as of today:

    • https://community.auth0.com/t/link-protect-software-breaks-passwordless-auth/60395
    • https://community.auth0.com/t/passwordless-login-breaks-for-many-users-on-corporate-e-mail-domains/56821/3
    • https://community.auth0.com/t/wrong-email-or-verification-code-on-magic-link-click/21073 (broken session link)
  • https://fusionauth.io/community/forum/topic/732/magic-link-expiration-when-email-previews-link

  • https://github.com/FusionAuth/fusionauth-issues/issues/629#issuecomment-832778247

So in general I think the approach outlined here is superior, even if the user experience is a bit worse (copy/pasting the code). However, this allows us to have the code work cross-device and also in native mobile apps.

aeneasr avatar Jun 21 '21 09:06 aeneasr

Is there any drawback of having the link in the email contain the recovery code in the query? This way the UI can prefill the input if it wants to. The code can still be used outside of that use case and manually copied/typed. We even don't need "native" Kratos support (and can't even prevent that practice), as the email template may choose to add the code to the URL. We should instead add best-practice guidance to the docs.

zepatrik avatar Jun 21 '21 10:06 zepatrik

The problem would be that people could accidentally copy/paste the URL with the code which would allow someone to take over your account.

aeneasr avatar Jun 22 '21 07:06 aeneasr

Then we should definitely point that out in the docs and advise against doing that in the email templates.

zepatrik avatar Jun 22 '21 12:06 zepatrik

We want phone number + otp login as quickly as possible, and can contribute if there is any design or implementation clarity exist. Otherwise we would go ahead modifying the code in according to our requirement, and later plan to use whenever this feature available from kratos

Any thoughts?

ysaakpr avatar Aug 07 '21 06:08 ysaakpr

So for OTP you would need to implement such a strategy analogous to e.g. the password strategy.

You could probably re-use some things from https://github.com/ory/kratos/tree/master/selfservice/strategy/link for this.

Regarding SMS, you would need to extend https://github.com/ory/kratos/tree/master/courier to support SMS using either a well-known service provider (e.g. twilio) or some abstraction (e.g. HTTP RPC call).

I hope this helps. Before you start implementing, I think it would be great to write down your ideas and discuss them as that will save you a lot of time and thought :)

aeneasr avatar Aug 09 '21 16:08 aeneasr

Is there a way to mark an email as verified using the admin API? We're building our own (temporary) workaround since a significant portion of our customer base is running into trouble here.

pradyuman avatar Aug 23 '21 18:08 pradyuman

Unfortunately there is currently no such way using an API endpoint but the feature (setting verification as an admin) is definitely something we want. If you're up for contributions, that would be a good issue! But before starting implementation, please discuss your API proposal in an issue first :)

aeneasr avatar Aug 23 '21 19:08 aeneasr

Imo, API endpoint should have higher priority over the out-of-the-box flow solution since it gives you an ability to create your own flow at least.

NikPaushkin avatar Sep 05 '21 10:09 NikPaushkin

Feel free to come up with a plan for contributing such a feature!

aeneasr avatar Sep 05 '21 11:09 aeneasr

I was also surprised to notice that it is enough just to open a verification link to be verified. But I am also now surprised to read this issue. I mean, why reimplement now everything when the solution is simple: just instead of verifying the account on opening, show a button which user has to click to verify the account? So the link opening is GET, you do not verify the account. If you get POST on the link, you verify the account. You can put CSRF in the mix if you want, and this is it.

I think that having additional/other strategies for verification and recovery could be nice, but I think we should first make a simple fix now for this and iterate later. So simple fix is:

  • GET on verification link does not verify, but redirects to the app, which can then extract the token from the redirect and display the form which does:
  • POST on verification, which does verify

mitar avatar Dec 07 '21 10:12 mitar

I haven't updated the original issue, the idea is to do exactly that for link strategies! So 100% agree.

Still, "codes" are much better because they work across devices and can work with native apps as well, whereas links always open in the browser.

aeneasr avatar Dec 07 '21 14:12 aeneasr

Awesome. I agree.

Still, "codes" are much better because they work across devices and can work with native apps as well, whereas links always open in the browser.

Yes, once there is "redirect to app to show button to click" for link strategy, it is easy to extend that with "show the input form for the code" for code strategy. But first step is to have the app involved at all.

Does triage to the next release for this (0.9.0) still holds?

mitar avatar Dec 07 '21 17:12 mitar

Does triage to the next release for this (0.9.0) still holds?

Hopefully 😬

aeneasr avatar Dec 07 '21 17:12 aeneasr

Any update/progress on this?

sebmellen avatar Aug 31 '22 15:08 sebmellen

@sebmellen yes, still working on it. But just cleaning up a few test cases for now. See #2645 for more details.

jonas-jonas avatar Aug 31 '22 15:08 jonas-jonas

@jonas-jonas I have a question about your PR. Will it be possible to combine the magic link with the code in one email? This way users without email scanning software could simply click on a link, while others could fall back on the code.

kszafran avatar Sep 20 '22 11:09 kszafran

This is not planned, no.

The issue would still be that there is a link in the email and the virus scanner would still open the link, thus completing the recovery flow. So even if this user would then go ahead and enter the code, the recovery flow itself is already completed. So the user would still not have a way of completing the recovery, e.g. re-setting their password.

jonas-jonas avatar Sep 20 '22 11:09 jonas-jonas