-
Notifications
You must be signed in to change notification settings - Fork 80
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
feat: move account linking related MFA things into account linking recipe #788
Conversation
lib/ts/authUtils.ts
Outdated
// This is different from linking based on account info, but the presence of a session shows that the user has access to both accounts, | ||
// and intends to link these two accounts. | ||
const sessionUserHasVerifiedAccountInfo = sessionUser.loginMethods.some( | ||
(lm) => lm.email === accountInfo.email && lm.phoneNumber === accountInfo.phoneNumber && lm.verified |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should not use ===
, we should use hasSameEmailAs
, and hasSamePhoneNumberAs
lib/ts/authUtils.ts
Outdated
}); | ||
} | ||
|
||
// TODO: verify this |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO
lib/ts/authUtils.ts
Outdated
// TODO: this'll make us consider EP signups as first factor if `shouldRequireVerification` is true and the user doesn't have the same email address | ||
// TODO: an alternative would be to throw if the verification status is wrong but shouldAutomaticallyLink is true. | ||
wantToLinkSessionUser = | ||
shouldLink.shouldAutomaticallyLink && | ||
(!shouldLink.shouldRequireVerification || isVerified || sessionUserHasVerifiedAccountInfo); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO
lib/ts/authUtils.ts
Outdated
let validRes = await isValidFirstFactor(tenantId, id, userContext); | ||
|
||
if (validRes.status === "TENANT_NOT_FOUND_ERROR") { | ||
throw new Error("Tenant not found"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if a session exists, we should throw unauthorised, else a normal JS error is fine
tenantId, | ||
user, | ||
// If nether should become a primary user, we can't link them together, so we can return the response user. | ||
return user; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we have to try and link the input user to some user here. It's probably already there somewhere above, but need to double check
return user; | ||
} | ||
} else { | ||
if (await this.shouldBecomePrimaryUser(user, tenantId, session, userContext)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this else branch should never come here.
session, | ||
}); | ||
if (preAuthChecks.status === "SIGN_IN_UP_NOT_ALLOWED") { | ||
throw new Error("This should never happen: post-auth sign in/up checks should not fail for sign up"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
throw new Error("This should never happen: post-auth sign in/up checks should not fail for sign up"); | |
throw new Error("This should never happen: pre-auth sign in/up checks should not fail for sign in"); |
lib/ts/authUtils.ts
Outdated
session?: SessionContainerInterface; | ||
userContext: UserContext; | ||
}): Promise< | ||
{ status: "OK"; validFactorIds: string[]; isFirstFactor: boolean } | { status: "SIGN_IN_UP_NOT_ALLOWED" } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
{ status: "OK"; validFactorIds: string[]; isFirstFactor: boolean } | { status: "SIGN_IN_UP_NOT_ALLOWED" } | |
{ status: "OK"; validFactorIds: string[]; isFirstFactor: boolean } | { status: "SIGN_UP_NOT_ALLOWED" } |
lib/ts/authUtils.ts
Outdated
); | ||
|
||
// create a new session keeping the payloads from the input session | ||
respSession = await Session.createNewSession( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not really comfortable with doing this.. it feels weird. What do you think about these instead:
- If we reach a case where we have to link the session user to the secondary factor user, we instead return a support code; OR
- We just logout the user from their current session and so they have to sign in again.
b7f14ed
to
b0e3f86
Compare
b0e3f86
to
a6cb81d
Compare
…reateRecipeUserIfNotExists to consume code
lib/ts/authUtils.ts
Outdated
// This means that the session user got primary since we loaded the session user info above | ||
sessionUser = await getUser(makeSessionUserPrimaryRes.primaryUserId, userContext); | ||
|
||
if (sessionUser === undefined) { | ||
throw new SessionError({ | ||
type: SessionError.UNAUTHORISED, | ||
message: "Session user not found", | ||
}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually, this means that the session got linked to another primary user, which means the primary user id has changed, so we should just logout the user?
lib/ts/authUtils.ts
Outdated
} else { | ||
// All other statuses signify that we can't make the session user primary | ||
// Which means we can't continue | ||
return { status: "NON_PRIMARY_SESSION_USER" }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should translate to a different support code compared to the case below. So we might want to make this a different status here, or add some other prop to this output indicating the actual reason
lib/ts/authUtils.ts
Outdated
// It should not happen in general, but it is possible that we end up with an unlinked user after this even though originally we considered this | ||
// an MFA sign in. | ||
// There are a couple of race-conditions associated with this functions, but it handles retries internally. | ||
const linkingResult = await accountLinkingInstance.createPrimaryUserIdOrLinkByAccountInfo({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const linkingResult = await accountLinkingInstance.createPrimaryUserIdOrLinkByAccountInfo({ | |
const linkingResult = await accountLinkingInstance.createPrimaryUserIdOrLinkByAccountInfoOrLinkToSessionIfProvided({ |
@@ -34,6 +35,7 @@ export default class Wrapper { | |||
static async createPrimaryUserIdOrLinkAccounts( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this function shouldn't link to the session user even if a session is passed to it (so same behaviour as in the master branch)
lib/ts/authUtils.ts
Outdated
(lm) => lm.recipeUserId === session.getRecipeUserId() | ||
); | ||
if (postLinkUserLinkedToSessionUser && mfaInstance !== undefined) { | ||
// if the authenticating user is linked to the current user (it means that the factor got set up or completed), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// if the authenticating user is linked to the current user (it means that the factor got set up or completed), | |
// if the authenticating user is linked to the current session user (it means that the factor got set up or completed), |
lib/ts/authUtils.ts
Outdated
const postLinkUserLinkedToSessionUser = linkingResult.user.loginMethods.some( | ||
(lm) => lm.recipeUserId === session.getRecipeUserId() | ||
); | ||
if (postLinkUserLinkedToSessionUser && mfaInstance !== undefined) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (postLinkUserLinkedToSessionUser && mfaInstance !== undefined) { | |
if (postLinkUserLinkedToSessionUser) { if (mfaInstance !== undefined) {... |
lib/ts/authUtils.ts
Outdated
// then we do not want to include a link in the email. | ||
for (const id of factorIds) { | ||
try { | ||
if (!factorsAlreadySetUp.includes(id)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (!factorsAlreadySetUp.includes(id)) { | |
if (isSignUp) {...} else { /* assert that id is in factorsAlreadySetUp */} |
lib/ts/authUtils.ts
Outdated
try { | ||
if (!factorsAlreadySetUp.includes(id)) { | ||
await MultiFactorAuth.assertAllowedToSetupFactorElseThrowInvalidClaimError( | ||
session!, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should take the authenticating user into account here and when we decide value of wantToLinkSessionUser
lib/ts/authUtils.ts
Outdated
} | ||
|
||
logDebugMessage("preAuthChecks checking auth types"); | ||
// First we check if the app intends to link the user from the signin/up response or not, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"from the signin/up response" -> what does this mean?
lib/ts/authUtils.ts
Outdated
return { status: "OK", sessionUser }; | ||
} | ||
|
||
async function checkAuthType( // TODO: better name |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO: better name. Consider calling it preAuthChecksHelper
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That doesn't really help tell what it does. For now I've renamed it to checkAuthTypeAndLinkingStatus
but we can discuss this over a call
lib/ts/authUtils.ts
Outdated
// This means that the session user got primary since we loaded the session user info above | ||
sessionUser = await getUser(makeSessionUserPrimaryRes.primaryUserId, userContext); | ||
|
||
if (sessionUser === undefined) { | ||
throw new SessionError({ | ||
type: SessionError.UNAUTHORISED, | ||
message: "Session user not found", | ||
}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can just throw unauthorised here cause the user Id of the session has changed here anyway, so the session is invalid?
lib/ts/authUtils.ts
Outdated
logDebugMessage(`checkAuthType loading session user`); | ||
// We have to load the session user in order to get the account linking info | ||
const sessionUserResult = await getPrimarySessionUser(session, tenantId, userContext); | ||
if (sessionUserResult.status !== "OK") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a status of NON_PRIMARY_SESSION_USER_OTHER_PRIMARY_USER
should not mean isFirstFactor, but it should instead result in a support code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I guess we can do that since that also implies that the app tried to make it a primary user.
This'll slightly change how we used to work even in the case where the app doesn't want to link to the session user. I think we are OK with that as well, but that's basically why I went with first factor sign in in this case.
if ( | ||
primaryUserThatCanBeLinkedToTheInputUser !== undefined && | ||
sessionUser.id !== primaryUserThatCanBeLinkedToTheInputUser.id | ||
) { | ||
return { status: "LINKING_TO_SESSION_USER_FAILED" }; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we need to do this check? When we call linkAccounts, it will fail anyway.
const usersToLink = await this.getUsersThatCanBeLinkedToRecipeUser({ | ||
tenantId, | ||
user: inputUser, | ||
userContext, | ||
}); | ||
const primaryUserThatCanBeLinkedToTheInputUser = usersToLink.primaryUser; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not needed (see comment in place where primaryUserThatCanBeLinkedToTheInputUser is used)
// If we get here, we know that the session user is primary. | ||
// if both of them are primary, they cannot be linked together. | ||
// we also check this outside of this function. | ||
if (inputUser.isPrimaryUser) { | ||
return { status: "LINKING_TO_SESSION_USER_FAILED" }; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we need to do this check? Calling linkAccounts will anyway make this fail..
| { status: "OK"; user: User } | ||
| { status: "LINKING_TO_SESSION_USER_FAILED" } | ||
| { status: "NON_PRIMARY_SESSION_USER" } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please reuse existing account linking status codes
!sessionUserLinkingRequiresVerification || authLoginMethod.verified || sessionUserHasVerifiedAccountInfo; | ||
|
||
if (!canLinkBasedOnVerification) { | ||
return { status: "LINKING_TO_SESSION_USER_FAILED" }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this will go as a support code to the frontend right? We should capture the exact reason here.
lib/ts/authUtils.ts
Outdated
accountInfo, | ||
tenantId, | ||
isSignUp, | ||
isVerified, | ||
inputUser, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rename inputUser and accountInfo
lib/ts/authUtils.ts
Outdated
} | ||
logDebugMessage(`checkAuthTypeAndLinkingStatus loading session user`); | ||
// We have to load the session user in order to get the account linking info | ||
const sessionUserResult = await AccountLinking.getInstance().getPrimarySessionUser( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move getPrimarySessionUser into this file. It can continue to be its own function.
|
||
getPrimarySessionUser = async function ( | ||
session: SessionContainerInterface, | ||
tenantId: string, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we need tenantId cause session already contains all tenant id
return { primaryUser, oldestUser }; | ||
}; | ||
|
||
getPrimarySessionUser = async function ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add comment here explaining what this function is doing exactly. It's not obvious from the name
return { primaryUser, oldestUser }; | ||
}; | ||
|
||
getPrimarySessionUser = async function ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getPrimarySessionUser = async function ( | |
tryAndMakeSessionUserIntoAPrimaryUser = async function ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
go into authUtils.ts
lib/ts/authUtils.ts
Outdated
getAuthenticatingUserAndAddToCurrentTenantIfRequired: async ({ | ||
recipeId, | ||
accountInfo, | ||
tenantId: currentTenantId, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need for tenantid since session already has it
lib/ts/authUtils.ts
Outdated
userContext, | ||
}: { | ||
recipeId: string; | ||
accountInfo: AccountInfo; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
update the type of this to make sure that only one of the info (email, phone number or third party) is passed and not multiple
logDebugMessage( | ||
`getAuthenticatingUserAndAddToCurrentTenantIfRequired session user is non-primary so returning early without checking other tenants` | ||
); | ||
return undefined; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Worth mentioning why returning undefined here is ok
lib/ts/authUtils.ts
Outdated
return undefined; | ||
} | ||
|
||
const matchingLoginMethods = sessionUser.loginMethods.filter( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const matchingLoginMethods = sessionUser.loginMethods.filter( | |
const matchingLoginMethodsFromSessionUser = sessionUser.loginMethods.filter( |
authenticatingUser = { | ||
user: sessionUser, | ||
loginMethod: matchingLoginMethods.find((lm) => lm.tenantIds.includes(currentTenantId))!, | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should return early?
…d input types & comments
let linkedToUser = await AccountLinking.getInstance().createPrimaryUserIdOrLinkAccounts({ | ||
tenantId, | ||
user: createUserResponse.user, | ||
userContext, | ||
}); | ||
if (linkedToUser.id !== existingUser.id) { | ||
const linkRes = await AuthUtils.linkToSessionIfProvidedElseCreatePrimaryUserIdOrLinkByAccountInfo( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should not take into account the input session
// We call signUp whenever possible, since people overriding functions will expect this to be called for normal sign up flows | ||
// and use this to execute post sign up hooks | ||
signUpResponse = await options.recipeImplementation.signUp({ | ||
tenantId, | ||
email, | ||
password, | ||
session, | ||
userContext, | ||
}); | ||
} else { | ||
signUpResponse = await options.recipeImplementation.createNewRecipeUser({ | ||
tenantId, | ||
email, | ||
password, | ||
userContext, | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can just use signUp here instead of using createNewRecipeUser
lib/ts/recipe/passwordless/types.ts
Outdated
@@ -151,28 +157,49 @@ export type RecipeInterface = { | |||
userInputCode: string; | |||
deviceId: string; | |||
preAuthSessionId: string; | |||
createRecipeUserIfNotExists: boolean; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is not required
lib/ts/recipe/passwordless/types.ts
Outdated
status: "LINKING_TO_SESSION_USER_FAILED"; | ||
reason: | ||
| "EMAIL_VERIFICATION_REQUIRED" | ||
| "RECIPE_USER_ID_ALREADY_LINKED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR" | ||
| "ACCOUNT_INFO_ALREADY_ASSOCIATED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"; | ||
} | ||
| { | ||
status: "NON_PRIMARY_SESSION_USER"; | ||
reason: "ACCOUNT_INFO_ALREADY_ASSOCIATED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
make this into one block
} | ||
const checkCredentialsOnTenant = async (tenantId: string) => { | ||
return ( | ||
(await options.recipeImplementation.signIn({ email, password, session, tenantId, userContext })) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
create a new recipe function called checkCredentials
lib/ts/recipe/passwordless/types.ts
Outdated
userInputCode: string; | ||
deviceId: string; | ||
preAuthSessionId: string; | ||
createRecipeUserIfNotExists: boolean; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this boolean should not be here. It should always be false.
lib/ts/recipe/passwordless/types.ts
Outdated
| { | ||
linkCode: string; | ||
preAuthSessionId: string; | ||
createRecipeUserIfNotExists: boolean; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this boolean should not be here. It should always be false.
lib/ts/recipe/passwordless/types.ts
Outdated
phoneNumber?: string; | ||
}; | ||
createdNewRecipeUser?: boolean; | ||
user?: User; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
user?: User; |
lib/ts/recipe/passwordless/types.ts
Outdated
email?: string; | ||
phoneNumber?: string; | ||
}; | ||
createdNewRecipeUser?: boolean; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
createdNewRecipeUser?: boolean; |
lib/ts/recipe/passwordless/types.ts
Outdated
}; | ||
createdNewRecipeUser?: boolean; | ||
user?: User; | ||
recipeUserId?: RecipeUserId; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
recipeUserId?: RecipeUserId; |
lib/ts/recipe/passwordless/types.ts
Outdated
@@ -209,6 +243,44 @@ export type RecipeInterface = { | |||
} | |||
>; | |||
|
|||
verifyAndDeleteCode: ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
verifyAndDeleteCode: ( | |
verifyCode: ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pass a non optional flag called deleteCode
(so this will require a core change).
We expose a verifyAndDeleteCode
function in the index file, which calls verifyCode with deleteCode: true all the time.
* feat(mfa): initial types (#708) * feat: add (partial) initial types for MFA * feat: expand the MFA recipe interface * feat: add export point for mfa * feat: update based on review discussions * feat: add extra params to MFARequirements callbacks to help customizations * feat: implement review feedback * feat: implement review comments * feat: implement review comments * feat: stricter type for first factor/mfa requirement * feat: remove distinction between built-in and custom factors (#729) * fix: MFA type updates (#737) * fix: type fix and account linking functions * fix: cdi version update * fix: more type updates * fix: tests * fix: TOTP recipe (#739) * fix: type fix and account linking functions * fix: cdi version update * fix: more type updates * fix: tests * fix: totp recipe * fix: totp types * fix: update types * fix: totp apis * fix: user identifier info * fix: recipe tests * fix: test * fix: pr comments * fix: tests * fix: PR comment * fix: MFA implementation (#743) * fix: type fix and account linking functions * fix: cdi version update * fix: more type updates * fix: tests * fix: totp recipe * fix: totp types * fix: update types * fix: totp apis * fix: user identifier info * fix: recipe tests * fix: test * fix: basic mfa impl * fix: pr comments * fix: tests * fix: factors setup from other recipe * fix: getFactorsSetupForUser impl * fix: getMFARequirementsForAuth impl * fix: isAllowedToSetupFactor impl * fix: addToDefaultRequiredFactorsForUser and getDefaultRequiredFactorsForUser impl * fix: typo * fix: build next array * fix: remove error file * fix: factorSetupForUser refactor * fix: next array * fix: api impl * fix: typo * fix: isValidFirstFactorForTenant * fix: impl * fix: updated impl * feat: fix and update mfa imlp to make all e2e tests pass * fix: adds overwriteSessionDuringSignIn config in session * fix: error messages in claims * fix: cleanup * fix: new errors for sign in up APIs * fix: add error in totp * fix: marked MFA TODOs * fix: new param in createNewSession * fix: impl cleanup * fix: remove MFA_ERROR * fix: cdi version * fix: test fix * fix: update/fix mfa impl to match e2e tests * fix: pr comments * fix: session user deleted error * fix: adding cache to getUserById * fix: get user cache * caching in querier * fix: mfa impl * fix: email selection * fix: mfa claims * fix: remove unnecessary file * fix: pr comment * fix: PR comments * fix: session handling * fix: review comments * fix: defaultRequiredFactorsForUser is now appwide * fix: using accountlinking instead of mfa for primary user and link accounts * fix: overwrite session flag refactor * fix: race conditions in createOrUpdateSessionForMultifactorAuthAfterFactorCompletion * fix: race conditions in createOrUpdateSessionForMultifactorAuthAfterFactorCompletion * fix: recipe functions refactor * fix: contact support case * fix: unnecessary file * fix: test * refactor: added shouldRefetch + fetchValue building the next array into MFAclaim (#758) * fix: usercontext type * fix: test * fix: test * feat: add access token payload param to claim.build * feat: expose addToDefaultRequiredFactorsForUser and remove tenantId param * fix: remaining TODOs * fix: auto init tests related to mfa * fix: recipe function tests * fix: create new session refactor * fix: recipe interface refactor * fix: userContext type fix * fix: test * fix: test * fix: session * fix: user context and support codes * fix: type fixes after merge * fix: test * fix: pr comments * fix: pr comment * fix: test * fix: available factors * fix: updated user object * fix: shouldAttemptAccountLinkingIfAllowed * fix: missed types and test fixes * fix: mfa fixes and tests * fix: more tests --------- Co-authored-by: Mihaly Lengyel <mihaly@lengyel.tech> * fix: contact support case when existing user signs in * fix: shouldAttemptAccountLinkingIfAllowed * fix: tackling some corner cases with account linking and user sign up * fix: isSignUpAllowed condition * fix: branded type explanation * fix: revert verifyEmailForRecipeUserIfLinkedAccountsAreVerified * fix: fixing shouldAttemptAccountLinkingIfAllowed typing * fix: recipe id check in emailpassword * fix: comment on not checking for tenantId * fix: remove implicit tenantInfo * fix: remove implicit tenantInfo * fix: duplicate factorIds * fix: not required params in validateForMultifactorAuthBeforeFactorCompletion * fix: input type of validateForMultifactorAuthBeforeFactorCompletion * changes impl of getMFARequirementsForAuth to remove oldest factor id * fix: rename defaultRequiredFactors to requiredSecondaryFactors for user * fix: update multitenancy core api * fix: add remove required secondary factors for user * fix: exposing known factor idsstnbp * fix: move to recipe impl * fix: not automatically assuming otp as setup * fix: update mfa info response * fix: changed mfa/info to PUT * fix: user refetch in emailpassword * fix: updated comments * fix: constant name * fix: factor flow impl in emailpassword and passwordless * fix: factor flow for thirdparty * fix: totp verification * fix: remove createNewOrKeepExistingSession * fix: improve createOrUpdateSessionForMultifactorAuthAfterFactorCompletion * fix: phoneNumber check * fix: sign in/up status refactor * fix: sign in/up status * fix: tests * fix: tests * feat: return email addresses for pwless factors based on the discussed priority order * fix: firstFactor validation and loginmethods * fix: userContext types and test * fix: misc changes * fix: emails for factor * fix: param rename * fix: msg update * fix: shouldAttemptAccountLinkingIfAllowed in thirdparty * fix: updated race conditions recursions * fix: removed tenantId checks for mfa * fix: recursion for support cases * fix: revert recursion fix to return 011 * fix: support code flows * fix: recursion point * fix: rename allOf to allOfInAnyOrder * fix: support codes * fix: copyright update * fix: copyright update * fix: implicit check * fix: support codes * fix: mfa flow refactor (#771) mfa flow refactor and support codes * fix: typo * fix: comments * fix: next array (#770) mfa info endpoint changes * fix: support code messages * fix: rename isAllowedToSetup and return claim error * fix: call checkAllowedToSetupFactorElseThrowInvalidClaimError in createCode and createDevice * fix: fixed status * fix: createNewSession param type * fix: mfa validation only on sign up in createCode * fix: factor check in create code * fix: factor check in create code * fix: remove mfa check in createCode * fix: removed unused status * fix: thirdparty api refactor * fix: passwordless api refactor and thirdparty api refactor fixes * fix: emailpassword api refactor and fixes in pless and tparty apis * fix: fixes after refactor * fix: clean up is valid first factor * fix: pr comments * fix: pr comments * fix: refactor * fix: refactor * fix: internal function for get user metadata for MFA * fix: pr comment * fix: race conditions * fix: refactor all factors * fix: comments * fix: assertAllowedToSetupFactorElseThrowInvalidClaimError in verify device * fix: tests * fix: add comment * fix: refactor resync api stuff * fix: refactor missing claims * fix: dedup code in mfa claim * fix: pr comments for emailpassword * fix: pr comments for emailpassword * fix: pr comments * fix: pr comments for email password * fix: pr comments for passwordless * fix: pr comments for thirdparty * fix: pr comments * fix: move recurse outside * fix: move assert sign in is allowed * fixes and changes * thirdparty recipe change * fix: cyclic dependency * fix: test * fix: claim value type * fix: pr comments from ep to pless * fix: remove internal functions from usermetadata * fix: context in session class * fix: session required in signout * fix: remove implicit check * fix: doUnionOfAccountInfo false for consistency * fix: pr comments from ep in pless * fix: remove shouldAttemptAccountLinkingIfAllowed in passwordless * fix: make isValidFirstFactor more readble with comments * fix: remove tenantId from getFactorsSetupForuser * fix: PR comments * fix: refactor totp * fix: post init callbacks to constructor * fix: totp PR comments * fix: error messages, test and fetch failure check * fix: tests * fix: tests * fix: PR comments * fix: Pr comments * fix: missed await + test fix * fix: missed await * fix: pr comments * fix: not use splice * fix: user metadata refactor * fix: mfa refactor * fix: self review * fix: clean up and comments * fix: comment * fix: refactor factorIds * fix: refactor factorIds * fix: handle unknown user id error in totp * fix: updated signout * fix: removed extra code * fix: session and tenantId in createCode * fix: first factor computation * fix: comment * fix: createRecipeUser in pless * fix: factor completion in thirdparty signInUp * fix: updated fake email * fix: should attempt account linking in third party * fix: throw unauthorised for tenant not found * fix: signout api * fix: cyclic dependency * fix: shouldAttemptAccountLinkingIfAllowed * fix: check claims error and throw others * fix: remove unnecessary session undefined check * fix: session in create code and resend code POST * fix: tenant not found * fix: mfa claim updation in util function * fix: revert to original :( * fix: revert to original :( * fix: cleanup * fix: pless createRecipeUser type * fix: pless revert * fix: querier caching to include headers * feat: use dynamic signing key switching (#782) * feat: enable a smooth switch between useDynamicAccessTokenSigningKey true and false * Merging feat/mfa/base into feat/useDynamicSigningKey_switching * fix: update prop name * feat: move account linking related MFA things into account linking recipe (#788) * feat: move account linking related MFA things into account linking recipe * test: update test to match new linking logic * feat(mfa)!: simplifying account linking flows * feat(mfa): updating impl of other recipe sign in/up endpoints + add createRecipeUserIfNotExists to consume code * feat: implement updated linking flow + fix tests * chore: remove unnecessary code * fix: fix typo/missing update * refactor: implementing review comments * refactor: implementing review comments * fix: add retry logic to createPrimaryUserIdOrLinkAccounts index func * fix: use hasSameEmailAs instead of === * refactor: improve getAuthenticatingUserAndAddToCurrentTenantIfRequired input types & comments * fix: remove wrong emailverification check from tryLinkAccounts * refactor: removed unnecessary status + added explanation comments * refactor: implement review comments * refactor: implement review comments + move functions * fix: fix accidentally flipped condition * fix: tidy up typos * fix: update func impl after moving * fix: cleaning up and updating tests * feat: refactoring for latest review comments * test: add mock for verifyCode * fix: cleanup and test fixes * chore: update error code reason strings * feat: remove factorIds from createCode input * fix: properly compare recipeUserIds as strings * feat: add signInVerifiesLoginMethod and minor cleanup/fixes * test: add new tests + update cases for new account linking logic/interface * fix: login methods (#794) * fix: login methods fix * fix: cleanup * fix: cleanup * fix: pr comments * fix: pr comment * fix: better test names * fix: comparision * feat: self-review fixes * chore: update changelog * feat: self-review fixes * feat: remove shouldAttemptAccountLinkingIfAllowed * feat: add verifyCredentials to ep and tpep recipes * feat: self-review fixes and latest discussions * fix: return userType instead of the user class consistently in the index files * feat: properly expose verifyCredentials and verifyCode * fix: add some missing tests and a related fix * feat: add call count tests and improve call counts * refactor: not trying linking if shouldDoAutomaticAccountLinking wasn't defined by the app * feat: implement review feedback * chore: add version number and compatibility section into changelog * feat: update mfa interface to optimize for less core calls * feat: make the core call cache reset globally if a call was made without usercontext * feat: ensure the email verification api can update the session if necessary * feat: verify the user in consume code if possible before trying to make it primary * feat: update verifyCredentials types to re-use it in signIn * feat: add disableCoreCallCache * refactor: remove resolved comment * chore: update changelog * feat: move the skipSessionUserUpdateInCore check before we check EV status * feat: fix tests & update for latest core * docs: fix jsdocs for pwless * docs: add explanation comment * feat: cache the result of checkCode in pwless consume code api * feat: add new param to revokeCode * feat: update changelog + consistency --------- Co-authored-by: Mihály Lengyel <mihaly@lengyel.tech> Co-authored-by: Rishabh Poddar <rishabh.poddar@gmail.com>
Summary of change
(A few sentences about this PR)
Related issues
Test Plan
(Write your test plan here. If you changed any code, please provide us with clear instructions on how you verified your changes work. Bonus points for screenshots and videos!)
Documentation changes
(If relevant, please create a PR in our docs repo, or create a checklist here highlighting the necessary changes)
Checklist for important updates
coreDriverInterfaceSupported.json
file has been updated (if needed)lib/ts/version.ts
frontendDriverInterfaceSupported.json
file has been updated (if needed)package.json
package-lock.json
lib/ts/version.ts
npm run build-pretty
recipe/thirdparty/providers/configUtils.ts
file,createProvider
function.git tag
) in the formatvX.Y.Z
, and then find the latest branch (git branch --all
) whoseX.Y
is greater than the latest released tag.add-ts-no-check.js
file to include thatsomeFunc: function () {..}
).Remaining TODOs for this PR