-
Notifications
You must be signed in to change notification settings - Fork 2.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
2FA #7003
Comments
@Bonapara can I work on this? I think I might need more time to get this right as this would need backend changes, but I would like to give it a try. |
@Bonapara |
I'm starting on this. TOTP incoming! |
Thanks @hozza! |
/oss.gg 3000 |
Thanks for opening an issue! It's live on oss.gg! |
/assign |
Assigned to @DeepaPrasanna! Please open a draft PR linking this issue within 48h |
/assign |
Assigned to @sudarshana133! Please open a draft PR linking this issue within 48h |
/unassign |
Issue unassigned. |
/assign |
Assigned to @dshinde96! Please open a draft PR linking this issue within 48h |
/assign |
This issue is already assigned to another person. Please find more issues here. |
/assign |
@dshinde96, Just a little reminder: Please open a draft PR linking this issue within 12 hours. If we can't detect a PR in 12h, you will be unassigned automatically. |
@Bonapara what do you think about this project? Will it be suitable here? https://www.better-auth.com/ |
@BOHEUS we would most likely use https://www.passportjs.org/packages/passport-totp/ since we use Passport for other auth concerns already |
Is this open for contribution? |
@DeepaPrasanna yes contribution most welcome!!! Thanks a lot |
Thank you! I would love to work on it |
Thanks a lot @DeepaPrasanna! Please ping me if you have any question (here on on Discord) |
Hey this has been dormant for a while now, I would like to work on it if it's cool (and not deprioritized). I had some questions then:
|
Hey @sid0-0, thanks! I believe @nicolasrouanne might work on it (discussed with him via Discord, not sure yet) We have an 2FA settings should be stored in the I'm not an expert in 2FA but I believe that the code is computed independently by the app without server connection so you don't need to generate/store totp in DB. Hope the passport package takes care of that! |
Hey @sid0-0 and @FelixMalfait, yes I will look into it early next week, but I'm open for suggestions and joint work if you want @sid0-0 . I'll draft out the general engineering directions in this issue before creating a PR; I will start from the backend obviously. |
Here are my thoughts about the general direction I'm thinking of using Note 2FA is tightly coupled with storing "authorized" client sessions, and not asking for 2FA upon every login attempt. This would mean storing and displaying "authorized" clients (e.g. a Webbrowser fingerprint). Although displaying these clients is optional. We need to store:
A // manually created
const secret = 'KVKFKRCPNZQUYMLXOVYDSQKJKZDTSRLD';
// it can also be generated by `otplib`
import { authenticator } from 'otplib';
const secret = authenticator.generateSecret(); I think storing We would then probably need:
Will elaborate later. What do you think @FelixMalfait? Sources: |
Good point, I agree, the lib seems quite light https://github.com/jaredhanson/passport-totp/blob/master/lib/strategy.js so even if we wanted to use it, copy/pasting would make more sense for a lib that hasn't been used for more than 8 years.
I get your point but this is really a tradeoff between simplicity and enterprise requirements. With SSO and subdomains we went a path where we are tending to isolate concerns between workspaces. So you could login to a workspace with Google and then an other workspace could require you to login via SSO only. We used to log you in automatically in the "workspace switcher" but now we don't anymore and you have to re-login separately for each domain.
Yes I think it's the right behavior. We have quite a long TTL for the Refresh Token so that shouldn't be a problem.
What about doing something similar to the |
Hey @nicolasrouanne Would love to work on it. I was taking an approach very similar to as you described. Here is a sample PR in my fork with the changes for reference. The biggest difference is that in this I am generating a secret and URI on UI itself as I don't see any real benefit to generating it on server, reason being server will need to share a QR image or the secret itself for user to scan anyway. Also did not want to add a library for 1 simple random generation function (if Passport can generate one, no reason to not use it). QR generation and scanning is tested working. Validation should be with some library on backend anyway though. I was mainly blocked on adding new APIs and mutation requests and I have altered table in local but not sure how the migration works in prod. Also adding OTP verification on login can be a subtask I believe, since this is a feature with multiple potential use cases, so I haven't done anything on that. |
@FelixMalfait Thanks a lot for the detailed feedback and guidance.
Where to store the setting?I'm still confused about storing the setting in the However you know the project architecture, much better than I do, so I will try and implement it this way Computing the
|
I get your point. If we were to rebuild the architecture today we might store password at a userWorkspace level yes. One argument against it asking for a password is a nice protection to access "workspace discovery" (i.e. redirect you to the right workspace if you have one or maybe show a screen with the list of workspaces you're part of). If we were to put password at a userWorkspace level then it would probably be impossible to redirect a user to his workspace if he doesn't have the url (or we could but then maybe it's a higher security risk we're introducing?). The rational for putting things at a userWorkspace level is to give freedom to the workspace admin to affect those parameter. For example in Google Workspace an admin can reset a password, disable the 2FA etc. That way if someone in our team has lost their phone we don't have to contact Google's support but can act independently. If that setting is managed at a user-level then a workspace admin shouldn't be allowed to touch it. A workspace admin cannot reset a user's password but this is less of an issue because this is the first step (2FA only comes after) and therefore can be performed without being logged in / independently.
Agree with your point. You could almost argue that it should be a table for all 2FA methods and only one defined as "active". But I'm afraid this will increase the size of your PR which is probably already big. If we were to go with a table we could keep the same generateSecret method but use the id of the 2FA method instead of the id of the user.
What you describe here seems very similar to the loginToken concept we have. We already try to unify all flows with a loginToken. When you come from Google or Microsoft or Password, we first issue a short-lived loginToken and then only you can exchange that against an access+refreshToken pair |
OK, it seems a lot clearer now, thanks. Some key takeaways (trying to keep it short):
But I don't see much more in that table. |
great points @nicolasrouanne! |
# Description Closes twentyhq#7003 Implements 2FA with TOTP. >[!WARNING] > This is a draft PR, with only partial changes, made as a mean of discussion about twentyhq#7003 (it's easier to reason about real code) ## Behaviour - a `totpSecret` is stored for each user - use [`otplib`](https://github.com/yeojz/otplib/tree/master) to create a QR code and to validate an `otp` against an `totpSecret` (great [demo website](https://otplib.yeojz.dev/) by `otplib`) - OTP is asked upon each login attempt ## Source Inspired by: - [RFC 6238](https://datatracker.ietf.org/doc/html/rfc6238) - Cal.com's implementation of 2FA, namely - [raising a 401](https://github.com/calcom/cal.com/blob/c21ba636d2bec4ed55775f0b058f70fdc371c410/packages/features/auth/lib/next-auth-options.ts#L188-L190) when missing OTP and 2FA is enabled, with a [specific error code](https://github.com/calcom/cal.com/blob/c21ba636d2bec4ed55775f0b058f70fdc371c410/packages/features/auth/lib/ErrorCode.ts#L9) - [catching the 401](https://github.com/calcom/cal.com/blob/c21ba636d2bec4ed55775f0b058f70fdc371c410/apps/web/modules/auth/login-view.tsx#L160) in the frontend and [displaying](https://github.com/calcom/cal.com/blob/c21ba636d2bec4ed55775f0b058f70fdc371c410/apps/web/modules/auth/login-view.tsx#L276) the OTP input ## Remaining - [ ] encrypt `totpSecret` at rest using a symetric algorithm --------- Co-authored-by: Félix Malfait <[email protected]> Co-authored-by: Félix Malfait <[email protected]>
Desired behavior
We want to introduce 2FA to secure user sign-ins.
1. No 2FA configured
2. Configure your 2FA
When clicking on the card, you will be brought to the 2FA configuration page
Then save
3. 2FA configured
4. Deactivate 2FA or re-configure
Sign-in
Figma
Settings
https://www.figma.com/design/xt8O9mFeLl46C5InWwoMrN/Twenty?node-id=34845-125317&node-type=frame&t=emUxzrvX6zNaHyLZ-11
Onboarding
https://www.figma.com/design/xt8O9mFeLl46C5InWwoMrN/Twenty?node-id=39767-36921&node-type=frame&t=2jy2Es54Z3i9hDfJ-11
The text was updated successfully, but these errors were encountered: