## [17.0.0] - 2024-03-08

### Changes

-   Enable smooth switching between `useDynamicAccessTokenSigningKey` settings by allowing refresh calls to change the signing key type of a session
-   Added a core call cache that should reduce traffic to your SuperTokens core instances
-   Refactored sign in/up API codes to reduce code duplication
-   Added MFA related information to dashboard APIs
-   Added a cache to reduce the number of requests made to the core. This can be disabled using the `disableCoreCallCache: true`, in the config.
-   Added new `overwriteSessionDuringSignInUp` configuration option to the Session recipe
-   Added new function: `checkCode` to Passwordless and ThirdPartyPasswordless recipes
-   Added new function: `verifyCredentials` to EmailPassword and ThirdPartyEmailPassword recipes
-   Added the `MultiFactorAuth` and `TOTP` recipes. To start using them you'll need compatible versions:
    -   Core>=8.0.0
    -   supertokens-node>=17.0.0
    -   supertokens-website>=18.0.0
    -   supertokens-web-js>=0.10.0
    -   supertokens-auth-react>=0.39.0

### Breaking changes

-   Now only supporting CDI 5.0. Compatible with core version >= 8.0
-   Account linking now takes the active session into account.
-   Account linking now also happens in sign in function calls (instead of sign ups and sign in API calls)
-   Fixed the typing of the `userContext`:
    -   All functions now take `Record<string, any>` instead of `any` as `userContext`. This means that primitives (strings, numbers) are no longer allowed as `userContext`.
    -   All functions overrides that take a `userContext` parameter now get a well typed `userContext` parameter ensuring that the right object is passed to the original implementation calls
-   Calling sign in/up APIs with a session will now skip creating a new session by default. This is overrideable through by passing `overwriteSessionDuringSignInUp: true` to the Session recipe config.
-   Added new support codes to sign in/up APIs. This means that there are new possible values coming from the default implementation for the `reason` strings of `SIGN_IN_NOT_ALLOWED`, `SIGN_UP_NOT_ALLOWED` and `SIGN_IN_UP_NOT_ALLOWED` responses.
-   `Session` recipe:
    -   The sign out API new returns a 401 instead of 200 in case the input access token has expired or is missing.
-   `AccountLinking` recipe:
    -   Changed the signature of the following functions, each taking a new (optional) `session` parameter:
        -   `createPrimaryUserIdOrLinkAccounts`
        -   `isSignUpAllowed`
        -   `isSignInAllowed`
        -   `isEmailChangeAllowed`
    -   Changed the signature of the `shouldDoAutomaticAccountLinking` callback: it now takes a new (optional) session parameter.
-   `EmailPassword`:
    -   Changed the signature of the following overrideable functions:
        -   `signUp`
            -   Takes a new (optional) `session` parameter
            -   Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"`
        -   `signIn`
            -   Takes a new (optional) `session` parameter
            -   Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"`
    -   Changed the signature of overrideable APIs, adding a new (optional) session parameter:
        -   `signInPOST`
        -   `signUpPOST`
    -   Changed the signature of functions:
        -   `signUp`
            -   Takes a new (optional) `session` parameter
            -   Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"`
        -   `signIn`
            -   Takes a new (optional) `session` parameter
            -   Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"
-   `Multitenancy`:
    -   Changed the signature of the following functions:
        -   `createOrUpdateTenant`: Added optional `firstFactors` and `requiredSecondaryFactors` parameters.
        -   `getTenant`: Added `firstFactors` and `requiredSecondaryFactors` to the return type
        -   `listAllTenants`: Added `firstFactors` and `requiredSecondaryFactors` to the returned tenants
    -   Changed the signature of the following overrideable functions:
        -   `createOrUpdateTenant`: Now gets optional `firstFactors` and `requiredSecondaryFactors` in the input.
        -   `getTenant`: Added `firstFactors` and `requiredSecondaryFactors` to the return type
        -   `listAllTenants`: Added `firstFactors` and `requiredSecondaryFactors` to the returned tenants
    -   Changed the signature of the overrideable apis:
        -   `loginMethodsGET`: Now returns `firstFactors`
-   `Passwordless`:
    -   `revokeCode` (and the related overrideable func) can now be called with either `preAuthSessionId` or `codeId` instead of only `codeId`.
    -   Added new email and sms type for MFA
    -   Changed the signature of the following functions:
        -   `signInUp`, `createCode`: Takes a new (optional) `session` parameter
        -   `consumeCode`:
            -   Takes a new (optional) `session` parameter
            -   Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"`
            -   It now also returns `consumedDevice` if the code was successfully consumed
    -   Changed the signature of the following overrideable functions:
        -   `createCode`: Takes a new (optional) `session` parameter
        -   `consumeCode`:
            -   Takes a new (optional) `session` parameter
            -   Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"`
            -   It now also returns `consumedDevice` if the code was successfully consumed
    -   Changed the signature of overrideable APIs, adding a new (optional) session parameter:
        -   `createCodePOST`
        -   `resendCodePOST`
        -   `consumeCodePOST`
-   Session claims:
    -   The `build` function and the `fetchValue` callback of session claims now take a new `currentPayload` param.
        -   This affects built-in claims: `EmailVerificationClaim`, `UserRoleClaim`, `PermissionClaim`, `AllowedDomainsClaim`.
        -   This will affect all custom claims as well built on our base classes.
-   `ThirdParty`:
    -   Changed the signature of the following functions:
        -   `manuallyCreateOrUpdateUser`:
            -   Takes a new (optional) `session` parameter
            -   Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"`
    -   Changed the signature of the following overrideable functions:
        -   `signInUp`:
            -   Takes a new (optional) `session` parameter
            -   Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"`
        -   `manuallyCreateOrUpdateUser`
            -   Takes a new (optional) `session` parameter
            -   Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"`
    -   Changed the signature of overrideable APIs, adding a new (optional) session parameter:
        -   `signInUpPOST`
-   `ThirdPartyEmailPassword`:
    -   Added new function: `emailPasswordVerifyCredentials`
    -   Changed the signature of the following functions:
        -   `thirdPartyManuallyCreateOrUpdateUser`:
            -   Takes a new (optional) `session` parameter
            -   Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"`
        -   `emailPasswordSignUp`
            -   Takes a new (optional) `session` parameter
            -   Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"`
    -   Changed the signature of the following overrideable functions:
        -   `thirdPartySignInUp`:
            -   Takes a new (optional) `session` parameter
            -   Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"`
        -   `thirdPartyManuallyCreateOrUpdateUser`
            -   Takes a new (optional) `session` parameter
            -   Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"`
        -   `emailPasswordSignUp`
            -   Takes a new (optional) `session` parameter
            -   Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"`
    -   Changed the signature of overrideable APIs, adding a new (optional) session parameter:
        -   `emailPasswordSignInPOST`
        -   `emailPasswordSignUpPOST`
        -   `thirdPartySignInUpPOST`
-   `ThirdPartyPasswordless`:
    -   `revokeCode` (and the related overrideable func) can now be called with either `preAuthSessionId` or `codeId` instead of only `codeId`.
    -   Changed the signature of the following functions:
        -   `thirdPartyManuallyCreateOrUpdateUser`:
            -   Takes a new (optional) `session` parameter
            -   Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"`
        -   `passwordlessSignInUp`, `createCode`: Takes a new (optional) `session` parameter
        -   `consumeCode`:
            -   Takes a new (optional) `session` parameter
            -   Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"`
            -   It now also returns `consumedDevice` if the code was successfully consumed
    -   Changed the signature of the following overrideable functions:
        -   `thirdPartySignInUp`:
            -   Takes a new (optional) `session` parameter
            -   Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"`
        -   `thirdPartyManuallyCreateOrUpdateUser`
            -   Takes a new (optional) `session` parameter
            -   Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"`
        -   `createCode`: Takes a new (optional) `session` parameter
        -   `consumeCode`:
            -   Takes a new (optional) `session` parameter
            -   Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"`
            -   It now also returns `consumedDevice` if the code was successfully consumed
    -   Changed the signature of overrideable APIs, adding a new (optional) session parameter:
        -   `thirdPartySignInUpPOST`
        -   `createCodePOST`
        -   `resendCodePOST`
        -   `consumeCodePOST`

#### Migration guide

##### shouldDoAutomaticAccountLinking signature change

If you use the `userContext` or `tenantId` parameters passed to `shouldDoAutomaticAccountLinking`, please update your implementation to account for the new parameter.

Before:

```ts
AccountLinking.init({
    shouldDoAutomaticAccountLinking: async (newAccountInfo, user, tenantId, userContext) => {
        return {
            shouldAutomaticallyLink: true,
            shouldRequireVerification: true,
        };
    },
});
```

After:

```ts
AccountLinking.init({
    shouldDoAutomaticAccountLinking: async (newAccountInfo, user, session, tenantId, userContext) => {
        return {
            shouldAutomaticallyLink: true,
            shouldRequireVerification: true,
        };
    },
});
```

##### Optional `session` parameter added to public functions

We've added a new optional `session` parameter to many function calls. In all cases, these have been added as the last parameter before `userContext`, so this should only affect you if you are using that. You only need to pass a session as a parameter if you are using account linking and want to try and link the user signing in/up to the session user.
You can get the necessary session object using `verifySession` in an API call.

Here we use the example of `EmailPassword.signIn` but this fits other functions with changed signatures.

Before:

```ts
const signInResp = await EmailPassword.signIn("public", "asdf@asdf.asfd", "testpw", { myContextVar: true });
```

After:

```ts
const signInResp = await EmailPassword.signIn("public", "asdf@asdf.asfd", "testpw", undefined, { myContextVar: true });
```

##### `fetchValue` signature change

If you use the `userContext` parameter passed to `fetchValue`, please update your implementation to account for the new parameter.

Before:

```ts
const boolClaim = new BooleanClaim({
    key: "asdf",
    fetchValue: (userId, recipeUserId, tenantId, userContext) => {
        return userContext.claimValue;
    },
});
```

After:

```ts
const boolClaim = new BooleanClaim({
    key: "asdf",
    fetchValue: (userId, recipeUserId, tenantId, currentPayload, userContext) => {
        return userContext.claimValue;
    },
});
```

##### `build` signature change

If you were using the `build` function for custom or built-in session claims, you should update the call signature to also pass the new parameter.

Before:

```ts
Session.init({
    override: {
        functions: (originalImplementation) => {
            return {
                ...originalImplementation,
                createNewSession: async function (input) {
                    input.accessTokenPayload = {
                        ...input.accessTokenPayload,
                        ...(await UserRoleClaim.build(
                            input.userId,
                            input.recipeUserId,
                            input.tenantId,
                            input.userContext
                        )),
                    };

                    return originalImplementation.createNewSession(input);
                },
            };
        },
    },
});
```

After:

```ts
Session.init({
    override: {
        functions: (originalImplementation) => {
            return {
                ...originalImplementation,
                createNewSession: async function (input) {
                    input.accessTokenPayload = {
                        ...input.accessTokenPayload,
                        ...(await UserRoleClaim.build(
                            input.userId,
                            input.recipeUserId,
                            input.tenantId,
                            input.accessTokenPayload,
                            input.userContext
                        )),
                    };

                    return originalImplementation.createNewSession(input);
                },
            };
        },
    },
});
```

##### Post sign-in/up actions

Since now sign in/up APIs and functions can be called with a session (e.g.: during MFA flows), you may need to add an extra check to your overrides to account for that:

Before:

```ts
// While this example uses Passwordless, all recipes require a very similar change
Passwordless.init({
    contactMethod: "EMAIL", // This example will work with any contactMethod
    flowType: "USER_INPUT_CODE_AND_MAGIC_LINK", // This example will work with any flowType

    override: {
        functions: (originalImplementation) => {
            return {
                ...originalImplementation,
                consumeCode: async (input) => {

                    // First we call the original implementation of consumeCode.
                    let response = await originalImplementation.consumeCode(input);

                    // Post sign up response, we check if it was successful
                    if (response.status === "OK") {
                        if (response.createdNewRecipeUser && response.user.loginMethods.length === 1) {
                            // TODO: post sign up logic
                        } else {
                            // TODO: post sign in logic
                        }
                    }
                    return response;
                }
            }
        }
    }
}),
```

After:

```ts
// While this example uses Passwordless, all recipes require a very similar change
Passwordless.init({
    contactMethod: "EMAIL", // This example will work with any contactMethod
    flowType: "USER_INPUT_CODE_AND_MAGIC_LINK", // This example will work with any flowType

    override: {
        functions: (originalImplementation) => {
            return {
                ...originalImplementation,
                consumeCode: async (input) => {

                    // First we call the original implementation of consumeCode.
                    let response = await originalImplementation.consumeCode(input);

                    // Post sign up response, we check if it was successful
                    if (response.status === "OK") {
                        if (input.session === undefined) {
                            if (response.createdNewRecipeUser && response.user.loginMethods.length === 1) {
                                // TODO: post sign up logic
                            } else {
                                // TODO: post sign in logic
                            }
                        }
                    }
                    return response;
                }
            }
        }
    }
}),
```

##### Sign-in/up linking to the session user

Sign in/up APIs and functions will now attempt to link the authenticating user to the session user if a session is available (depending on AccountLinking settings). You can disable this and get the old behaviour by:

Before:

```ts
// While this example uses Passwordless, all recipes require a very similar change
Passwordless.init({
    contactMethod: "EMAIL", // This example will work with any contactMethod
    flowType: "USER_INPUT_CODE_AND_MAGIC_LINK", // This example will work with any flowType
}),
```

After:

```ts
// While this example uses Passwordless, all recipes require a very similar change
Passwordless.init({
    contactMethod: "EMAIL", // This example will work with any contactMethod
    flowType: "USER_INPUT_CODE_AND_MAGIC_LINK", // This example will work with any flowType

    override: {
        functions: (originalImplementation) => {
            return {
                ...originalImplementation,
                consumeCode: async (input) => {
                    input.session = undefined;
                    return originalImplementation.consumeCode(input);
                }
            }
        }
    }
}),
```

