Implement Two-Factor Authentication (2FA) (#13141)

Implementation is very simple

Established authentication dynamic is intercepted at
getAuthTokensFromLoginToken. If 2FA is required, a pattern similar to
EmailVerification is executed. That is, getAuthTokensFromLoginToken
mutation fails with either of the following errors:

1. TWO_FACTOR_AUTHENTICATION_VERIFICATION_REQUIRED
2. TWO_FACTOR_AUTHENTICATION_PROVISION_REQUIRED

UI knows how to respond accordingly.

2FA provisioning occurs at the 2FA resolver.
2FA verification, currently only OTP, is handled by auth.resolver's
getAuthTokensFromOTP

---------

Co-authored-by: Charles Bochet <charlesBochet@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions <github-actions@twenty.com>
Co-authored-by: Jean-Baptiste Ronssin <65334819+jbronssin@users.noreply.github.com>
Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
Co-authored-by: Félix Malfait <felix@twenty.com>
This commit is contained in:
oliver
2025-07-23 06:42:01 -06:00
committed by GitHub
parent dd5ae66449
commit 4d3124f840
106 changed files with 5103 additions and 103 deletions

View File

@ -39730,6 +39730,16 @@ __metadata:
languageName: node
linkType: hard
"input-otp@npm:^1.4.2":
version: 1.4.2
resolution: "input-otp@npm:1.4.2"
peerDependencies:
react: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc
checksum: 10c0/d3a3216a75ed832993f3f2852edd7a85c5bae30ea6d251182119120488bbf9fed7cfdd91819bcee6daff57b3cfcbca94fd16d6a7c92cee4d806c0d4fa6ff1128
languageName: node
linkType: hard
"inquirer@npm:8.2.4":
version: 8.2.4
resolution: "inquirer@npm:8.2.4"
@ -50738,6 +50748,13 @@ __metadata:
languageName: node
linkType: hard
"qr.js@npm:0.0.0":
version: 0.0.0
resolution: "qr.js@npm:0.0.0"
checksum: 10c0/1c6a4c7a58d04e52ec2fee99e39b680fdc5b2a510a981df42c36b716a8eac6634d130fc4d65af8f030f2a07dbf5fa046b97cdfa7456c250ebb50a73916efdcb5
languageName: node
linkType: hard
"qs@npm:6.11.0":
version: 6.11.0
resolution: "qs@npm:6.11.0"
@ -51358,6 +51375,18 @@ __metadata:
languageName: node
linkType: hard
"react-qr-code@npm:^2.0.18":
version: 2.0.18
resolution: "react-qr-code@npm:2.0.18"
dependencies:
prop-types: "npm:^15.8.1"
qr.js: "npm:0.0.0"
peerDependencies:
react: "*"
checksum: 10c0/4e13b795cbb10f1dcf0e39d682bb59851e4c84010ba2be7225b2ad9d5c1ffea52d2d38f884ee26235b7002b8ca99e83b805f55e877663c39d67496764d975cf1
languageName: node
linkType: hard
"react-query@npm:^3.34.19":
version: 3.39.3
resolution: "react-query@npm:3.39.3"
@ -57026,7 +57055,9 @@ __metadata:
eslint-plugin-unicorn: "npm:^51.0.1"
eslint-plugin-unused-imports: "npm:^3.0.0"
file-saver: "npm:^2.0.5"
input-otp: "npm:^1.4.2"
optionator: "npm:^0.9.1"
react-qr-code: "npm:^2.0.18"
rollup-plugin-visualizer: "npm:^5.14.0"
transliteration: "npm:^2.3.5"
twenty-shared: "workspace:*"