Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
109 commits
Select commit Hold shift + click to select a range
ea6850f
feat: add useMultifactorAuthenticationStatus hook
JakubKorytko Jan 26, 2026
06d2fef
feat: add useNativeBiometrics hook
JakubKorytko Jan 26, 2026
f179dd1
feat: add the proper MFA context implementation
JakubKorytko Jan 26, 2026
a9f1de4
tests: add useMultifactorAuthenticationStatus hook
JakubKorytko Jan 19, 2026
bde7bee
tests: add useNativeBiometrics hook
JakubKorytko Jan 26, 2026
9f8e4ad
tests: add the proper MFA context implementation
JakubKorytko Jan 26, 2026
64bd826
Merge branch 'main' into korytko/ecuk/3ds/implement-native-hooks
dariusz-biela Jan 26, 2026
8d3b7a1
fix: PR comments pt. 1
JakubKorytko Jan 27, 2026
12aa529
Merge branch 'main' into korytko/ecuk/3ds/implement-native-hooks
JakubKorytko Jan 27, 2026
24ced88
refractor: remove status helpers
JakubKorytko Jan 27, 2026
57515ab
refractor: remove factors origin
JakubKorytko Jan 27, 2026
bab79b4
refractor: remove unused factor values
JakubKorytko Jan 27, 2026
48f4a66
feat: add authenticationMethod to MFA requests
JakubKorytko Jan 27, 2026
7fd6899
fix: address PR comments
JakubKorytko Jan 27, 2026
a8d59cc
Merge branch 'main' into korytko/ecuk/3ds/implement-native-hooks
dariusz-biela Jan 28, 2026
3ca4f3c
refactor: simplify MultifactorAuthentication with state-based flow
dariusz-biela Jan 28, 2026
dd86918
Revert "refactor: simplify MultifactorAuthentication with state-based…
JakubKorytko Jan 28, 2026
f60b216
refactor: simplify useNativeBiometrics
JakubKorytko Jan 28, 2026
02dba99
Merge branch 'main' into korytko/ecuk/3ds/implement-native-hooks
JakubKorytko Jan 28, 2026
d082e14
refractor: prepare the structure for the new Context
JakubKorytko Jan 28, 2026
f04398e
refractor: implement new MFA context
JakubKorytko Jan 28, 2026
c01ef23
refractor: clean-up
JakubKorytko Jan 28, 2026
ca8add2
fix: failing test
JakubKorytko Jan 28, 2026
a19519c
feat: add route guards for MultifactorAuthentication flow
dariusz-biela Jan 28, 2026
0dc7eec
refactor: derive isAnyDeviceRegistered from Onyx instead of API call
dariusz-biela Jan 28, 2026
37da30c
refactor: extract MFA provider composition to separate file
dariusz-biela Jan 28, 2026
ce5babf
refactor: remove duplicate validateCode check in MFA flow
dariusz-biela Jan 28, 2026
7bb7107
feat: add optimistic Onyx update for MFA registration
dariusz-biela Jan 28, 2026
bc3f5e1
fix: use string type for validateCode to preserve leading zeros
dariusz-biela Jan 29, 2026
99b1d30
fix: stringify signedChallenge for MFA API and preemptively delete ke…
dariusz-biela Jan 29, 2026
8de575b
feat: add authenticationMethod state to MFA flow for outcome page tra…
dariusz-biela Jan 29, 2026
50ff538
refactor: split requestAuthenticationChallenge into separate registra…
dariusz-biela Jan 29, 2026
d72aed9
refactor: remove route guards from MultifactorAuthentication flow
dariusz-biela Jan 29, 2026
891a53d
refactor: remove redundant scenario check in MFA process function
dariusz-biela Jan 30, 2026
74ac730
refactor: rename boolean variables to follow naming convention
dariusz-biela Jan 30, 2026
2ba5949
fix: add scenario guard in MFA process function for TypeScript
dariusz-biela Jan 30, 2026
12e0508
refactor: remove unused chainedPrivateKeyStatus from authorize function
dariusz-biela Jan 30, 2026
d7341ac
fix: move comment to correct position before processScenario call
dariusz-biela Jan 30, 2026
8a7b795
refactor: move signedChallenge/authenticationMethod validation to aut…
dariusz-biela Jan 30, 2026
585c2d8
refactor: replace useState/useEffect with useMemo and async functions
dariusz-biela Jan 30, 2026
e433935
refactor: extract isHttpSuccess utility function
dariusz-biela Jan 30, 2026
1629c16
refactor: use CONST for enable-biometrics prompt value
dariusz-biela Jan 30, 2026
6da5888
refactor: use CONST.MULTIFACTOR_AUTHENTICATION.ED25519_TYPE for biome…
dariusz-biela Jan 30, 2026
8b4a3ea
Merge branch 'main' into korytko/ecuk/3ds/implement-native-hooks
JakubKorytko Jan 30, 2026
af5032c
fix: failing checks & PR comments
JakubKorytko Jan 30, 2026
66c9ef4
refractor: use reducer for MFA state
JakubKorytko Jan 30, 2026
294e746
feat: add better auth screens
JakubKorytko Jan 30, 2026
5a0e541
chore: adds translations
dariusz-biela Jan 30, 2026
2ecefcd
refactor: use single INIT action to reset MFA state
dariusz-biela Jan 30, 2026
039d20f
fix: use forceReplace for MFA navigation to prevent screen stacking
dariusz-biela Jan 30, 2026
da7e0a0
fix: add loading state for MFA registration challenge request
dariusz-biela Jan 30, 2026
b0820bb
fix: stabilize animation and text position in MFA prompt screen
dariusz-biela Jan 30, 2026
bd028c7
Merge branch 'main' into korytko/ecuk/3ds/implement-native-hooks
dariusz-biela Jan 30, 2026
5a45e91
refactor: migrate revokeMultifactorAuthenticationCredentials to new f…
dariusz-biela Jan 30, 2026
7901fba
refactor: remove /factor/ from magic-code route path
dariusz-biela Jan 30, 2026
2d8b64b
refactor: inline continuable reason check with descriptive comment
dariusz-biela Jan 30, 2026
0bd5a09
Revert "refactor: inline continuable reason check with descriptive co…
dariusz-biela Jan 30, 2026
4ccc3ce
fix: pause MFA flow on continuable errors instead of auto-restarting
dariusz-biela Jan 30, 2026
f3d46bd
refactor: inline continuable reason check with descriptive comment
dariusz-biela Jan 30, 2026
5d90bb2
refactor: remove redundant device support check in soft prompt logic
dariusz-biela Jan 30, 2026
7d573a7
refactor: remove redundant registrationChallenge.challenge check
dariusz-biela Jan 30, 2026
2bedba8
fix: update Spanish translations for authentication prompts
dariusz-biela Jan 30, 2026
50a74a3
refactor: simplify authorization check by removing unnecessary variable
dariusz-biela Jan 30, 2026
397cad4
refactor: rename biometrics hook properties for clarity
dariusz-biela Jan 30, 2026
311497d
docs: add comment explaining why re-registration may be needed
dariusz-biela Jan 30, 2026
08bd416
docs: explain why resetKeys only clears local credentials
dariusz-biela Jan 30, 2026
b21dd16
fix: only set error for non-recoverable authorization failures
dariusz-biela Jan 30, 2026
ff3ae66
Remove unused CONTINUABLE_REASONS and address style feedback
chuckdries Jan 30, 2026
a5ae8db
Remove doesDeviceSupportBiometrics from useNativeBiometrics register …
chuckdries Jan 30, 2026
9239c65
Inline HANDLED_REASONS in ValidateCodePage
chuckdries Jan 30, 2026
6b466dc
Remove unused mock
chuckdries Jan 30, 2026
8cc5479
Merge pull request #291 from Expensify/chuckdries/ecuk/3ds/implement-…
dariusz-biela Jan 31, 2026
9ffe8bf
Merge branch 'main' into korytko/ecuk/3ds/implement-native-hooks
JakubKorytko Feb 2, 2026
9afb414
fix: PR comments + PR checks
JakubKorytko Feb 2, 2026
7c6037c
fix: PR comments pt. 2
JakubKorytko Feb 2, 2026
9129ba3
fix: offline state in MFA
JakubKorytko Feb 2, 2026
bd8411f
fix: outcome page authentication method
JakubKorytko Feb 2, 2026
d6fbc94
chore: Add TODO comment linking to refactoring issue for MFA context
dariusz-biela Feb 2, 2026
41d2467
Merge branch 'main' into korytko/ecuk/3ds/implement-native-hooks
JakubKorytko Feb 3, 2026
700a5f3
Fix findMessageInSource to handle messages with http statuses at the …
chuckdries Feb 2, 2026
2181e86
fix: address PR comments pt. 3
JakubKorytko Feb 3, 2026
803fa0e
fix: offline state on registration page
JakubKorytko Feb 3, 2026
13e2568
refactor: hardcode nativePromptTitle
JakubKorytko Feb 3, 2026
908e82a
fix: make prompt page button large
JakubKorytko Feb 3, 2026
491b921
fix: polishing
JakubKorytko Feb 3, 2026
b6bec7a
refactor: remove executeScenario from promptPage
JakubKorytko Feb 3, 2026
dbaa15b
Merge branch 'main' into korytko/ecuk/3ds/implement-native-hooks
JakubKorytko Feb 3, 2026
41b48ca
chore: add issue link to the comment
JakubKorytko Feb 3, 2026
742e8b0
fix: small PR comments fixes
JakubKorytko Feb 3, 2026
d024f98
fix: PR comments
JakubKorytko Feb 4, 2026
79b55cf
Merge branch 'main' into korytko/ecuk/3ds/implement-native-hooks
JakubKorytko Feb 4, 2026
0422b9c
fix: remove MULTIFACTOR_AUTHENTICATION_PROTECTED_ROUTES
JakubKorytko Feb 4, 2026
13fa43b
fix: isOffline in BiometricsTestPage
JakubKorytko Feb 4, 2026
a8cf28f
fix: revert bad changes
JakubKorytko Feb 4, 2026
ee673a9
fix: no-eligible-methods on web
JakubKorytko Feb 4, 2026
5e7a96a
Merge branch 'main' into korytko/ecuk/3ds/implement-native-hooks
JakubKorytko Feb 5, 2026
e113b42
feat: add unsupported device screen
JakubKorytko Feb 5, 2026
3900f95
fix: remove 'right now' from MFA mobile app text
JakubKorytko Feb 5, 2026
2387b8f
Merge branch 'main' into korytko/ecuk/3ds/implement-native-hooks
JakubKorytko Feb 5, 2026
3fb8dd7
fix: update unsupportedDevice text
JakubKorytko Feb 5, 2026
9f11501
fix: add rock patch with temporaryUploadArtifactName
LukasMod Feb 5, 2026
2e99431
Merge branch 'main' into korytko/ecuk/3ds/implement-native-hooks
JakubKorytko Feb 5, 2026
ad6111a
parrot: languages
JakubKorytko Feb 5, 2026
46b970c
Revert "fix: add rock patch with temporaryUploadArtifactName"
JakubKorytko Feb 5, 2026
1c4324b
cp: callstack-internal:fix/rock-adhoc-custom-ref
JakubKorytko Feb 5, 2026
11abf5f
Add missing forceReplace in process
chuckdries Feb 6, 2026
01b92f2
Fix prettier
chuckdries Feb 6, 2026
ab847b1
Show soft prompt to users who have valid keys but have not accepted t…
chuckdries Feb 6, 2026
4dd4f6e
Add MFA screens to EXCLUDE_FROM_LAST_VISITED_PATH
chuckdries Feb 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .github/workflows/testBuild.yml
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ jobs:

- name: Rock Remote Build - Android
id: rock-remote-build-android
uses: callstackincubator/android@0bbc1b7c2e1a8be1ecb4d6c744c211869823fd65
uses: callstackincubator/android@2177ac62cabe662aa49a2bc6f3154070705dd8f5
env:
GITHUB_TOKEN: ${{ github.token }}
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
Expand All @@ -320,6 +320,7 @@ jobs:
keystore-path: '../tools/buildtools/upload-key.keystore'
comment-bot: false
rock-build-extra-params: '--extra-params -PreactNativeArchitectures=arm64-v8a,x86_64'
custom-ref: ${{ needs.prep.outputs.APP_REF }}

- name: Set artifact URL output
id: set-artifact-url
Expand Down Expand Up @@ -414,7 +415,7 @@ jobs:

- name: Rock Remote Build - iOS
id: rock-remote-build-ios
uses: callstackincubator/ios@8dcef6cc275e0cf3299f5a97cde5ebd635c887d7
uses: callstackincubator/ios@d638bd25c764655baeeced3232c692f1698cf72b
env:
GITHUB_TOKEN: ${{ github.token }}
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
Expand Down Expand Up @@ -442,6 +443,7 @@ jobs:
}
]
comment-bot: false
custom-ref: ${{ needs.prep.outputs.APP_REF }}

- name: Set artifact URL output
id: set-artifact-url
Expand Down
6 changes: 1 addition & 5 deletions src/CONST/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5567,10 +5567,6 @@ const CONST = {
DISABLED: 'DISABLED',
DISABLE: 'DISABLE',
},
MULTIFACTOR_AUTHENTICATION_OUTCOME_TYPE: {
SUCCESS: 'success',
FAILURE: 'failure',
},
MERGE_ACCOUNT_RESULTS: {
SUCCESS: 'success',
ERR_2FA: 'err_2fa',
Expand Down Expand Up @@ -7470,7 +7466,7 @@ const CONST = {
CASH_BACK: 'earnedCashback',
},

EXCLUDE_FROM_LAST_VISITED_PATH: [SCREENS.NOT_FOUND, SCREENS.SAML_SIGN_IN, SCREENS.VALIDATE_LOGIN, SCREENS.MIGRATED_USER_WELCOME_MODAL.ROOT, SCREENS.MONEY_REQUEST.STEP_SCAN] as string[],
EXCLUDE_FROM_LAST_VISITED_PATH: [SCREENS.NOT_FOUND, SCREENS.SAML_SIGN_IN, SCREENS.VALIDATE_LOGIN, SCREENS.MIGRATED_USER_WELCOME_MODAL.ROOT, SCREENS.MONEY_REQUEST.STEP_SCAN, ...Object.values(SCREENS.MULTIFACTOR_AUTHENTICATION)] as string[],

CANCELLATION_TYPE: {
MANUAL: 'manual',
Expand Down
9 changes: 9 additions & 0 deletions src/ONYXKEYS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ const ONYXKEYS = {
/** A unique ID for the device */
DEVICE_ID: 'deviceID',

/** Holds information about device-specific biometrics which:
* - does need to be persisted
* - does not need to be kept in secure storage
* - does not persist across uninstallations
* (secure storage persists across uninstallation)
*/
DEVICE_BIOMETRICS: 'deviceBiometrics',

/** Boolean flag set whenever the sidebar has loaded */
IS_SIDEBAR_LOADED: 'isSidebarLoaded',

Expand Down Expand Up @@ -1417,6 +1425,7 @@ type OnyxValuesMapping = {
[ONYXKEYS.IS_OPEN_CONFIRM_NAVIGATE_EXPENSIFY_CLASSIC_MODAL_OPEN]: boolean;
[ONYXKEYS.PERSONAL_POLICY_ID]: string;
[ONYXKEYS.TRANSACTION_IDS_HIGHLIGHT_ON_SEARCH_ROUTE]: Record<string, Record<string, boolean>>;
[ONYXKEYS.DEVICE_BIOMETRICS]: OnyxTypes.DeviceBiometrics;
};

type OnyxDerivedValuesMapping = {
Expand Down
18 changes: 6 additions & 12 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/
import type {TupleToUnion, ValueOf} from 'type-fest';
import type {UpperCaseCharacters} from 'type-fest/source/internal';
import type {AllMultifactorAuthenticationOutcomeType, MultifactorAuthenticationPromptType} from './components/MultifactorAuthentication/config/types';
import type {SearchFilterKey, SearchQueryString, UserFriendlyKey} from './components/Search/types';
import type CONST from './CONST';
import type {IOUAction, IOUType, OdometerImageType} from './CONST';
Expand Down Expand Up @@ -84,11 +85,6 @@ const DYNAMIC_ROUTES = {
},
} as const satisfies DynamicRoutes;

const MULTIFACTOR_AUTHENTICATION_PROTECTED_ROUTES = {
FACTOR: 'multifactor-authentication/factor',
PROMPT: 'multifactor-authentication/prompt',
} as const;

const ROUTES = {
...PUBLIC_SCREENS_ROUTES,
// This route renders the list of reports.
Expand Down Expand Up @@ -3870,19 +3866,17 @@ const ROUTES = {
getRoute: (domainAccountID: number) => `domain/${domainAccountID}/members/invite` as const,
},

MULTIFACTOR_AUTHENTICATION_MAGIC_CODE: `${MULTIFACTOR_AUTHENTICATION_PROTECTED_ROUTES.FACTOR}/magic-code`,
MULTIFACTOR_AUTHENTICATION_MAGIC_CODE: `multifactor-authentication/magic-code`,
MULTIFACTOR_AUTHENTICATION_BIOMETRICS_TEST: 'multifactor-authentication/scenario/biometrics-test',

// The exact outcome & prompt type will be added as a part of Multifactor Authentication config in another PR,
// for now a string is accepted to avoid blocking this PR.
MULTIFACTOR_AUTHENTICATION_OUTCOME: {
route: 'multifactor-authentication/outcome/:outcomeType',
getRoute: (outcomeType: ValueOf<typeof CONST.MULTIFACTOR_AUTHENTICATION_OUTCOME_TYPE>) => `multifactor-authentication/outcome/${outcomeType}` as const,
getRoute: (outcomeType: AllMultifactorAuthenticationOutcomeType) => `multifactor-authentication/outcome/${outcomeType}` as const,
},

MULTIFACTOR_AUTHENTICATION_PROMPT: {
route: `${MULTIFACTOR_AUTHENTICATION_PROTECTED_ROUTES.PROMPT}/:promptType`,
getRoute: (promptType: string) => `${MULTIFACTOR_AUTHENTICATION_PROTECTED_ROUTES.PROMPT}/${promptType}` as const,
route: `multifactor-authentication/prompt/:promptType`,
getRoute: (promptType: MultifactorAuthenticationPromptType) => `multifactor-authentication/prompt/${promptType}` as const,
},

MULTIFACTOR_AUTHENTICATION_NOT_FOUND: 'multifactor-authentication/not-found',
Expand All @@ -3903,7 +3897,7 @@ const SHARED_ROUTE_PARAMS: Partial<Record<Screen, string[]>> = {
[SCREENS.WORKSPACE.INITIAL]: ['backTo'],
} as const;

export {PUBLIC_SCREENS_ROUTES, SHARED_ROUTE_PARAMS, VERIFY_ACCOUNT, MULTIFACTOR_AUTHENTICATION_PROTECTED_ROUTES, DYNAMIC_ROUTES};
export {PUBLIC_SCREENS_ROUTES, SHARED_ROUTE_PARAMS, VERIFY_ACCOUNT, DYNAMIC_ROUTES};
export default ROUTES;

type ReportAttachmentsRoute = typeof ROUTES.REPORT_ATTACHMENTS.route;
Expand Down
Loading
Loading