## [15.0.0] - 2023-07-19

### Added

-   Added Multitenancy Recipe & always initialized by default.
-   Adds Multitenancy support to all the recipes
-   Added new Social login providers - LinkedIn
-   Added new Multi-tenant SSO providers - Okta, Active Directory, Boxy SAML
-   All APIs handled by Supertokens middleware can have an optional `tenantId` prefixed in the path. e.g. <basePath>/<tenantId>/signinup
-   Following recipe functions have been added:
    -   `EmailPassword.createResetPasswordLink`
    -   `EmailPassword.sendResetPasswordEmail`
    -   `EmailVerification.createEmailVerificationLink`
    -   `EmailVerification.sendEmailVerificationEmail`
    -   `ThirdParty.getProvider`
    -   `ThirdPartyEmailPassword.thirdPartyGetProvider`
    -   `ThirdPartyEmailPassword.createResetPasswordLink`
    -   `ThirdPartyEmailPassword.sendResetPasswordEmail`
    -   `ThirdPartyPasswordless.thirdPartyGetProvider`
    -   `ThirdPartyPasswordless.createResetPasswordLink`
    -   `ThirdPartyPasswordless.sendResetPasswordEmail`

### Breaking changes

-   Only supporting FDI 1.17
-   Core must be upgraded to 6.0
-   `getUsersOldestFirst` & `getUsersNewestFirst` has mandatory parameter `tenantId`. Pass `'public'` if not using multitenancy.
-   Added mandatory field `tenantId` to `EmailDeliveryInterface` and `SmsDeliveryInterface`. Pass `'public'` if not using multitenancy.
-   Removed deprecated config `createAndSendCustomEmail` and `createAndSendCustomTextMessage`.
-   EmailPassword recipe changes:
    -   Added mandatory `tenantId` field to `TypeEmailPasswordPasswordResetEmailDeliveryInput`
    -   Removed `resetPasswordUsingTokenFeature` from `TypeInput`
    -   Added `tenantId` param to `validate` function in `TypeInputFormField`
    -   Added mandatory `tenantId` as first parameter to the following recipe index functions:
        -   `signUp`
        -   `signIn`
        -   `getUserByEmail`
        -   `createResetPasswordToken`
        -   `resetPasswordUsingToken`
    -   Added mandatory `tenantId` in the input for the following recipe interface functions. If any of these functions are overridden, they need to be updated accordingly:
        -   `signUp`
        -   `signIn`
        -   `getUserByEmail`
        -   `createResetPasswordToken`
        -   `resetPasswordUsingToken`
        -   `updateEmailOrPassword`
    -   Added mandatory `tenantId` in the input for the following API interface functions. If any of these functions are overridden, they need to be updated accordingly:
        -   `emailExistsGET`
        -   `generatePasswordResetTokenPOST`
        -   `passwordResetPOST`
        -   `signInPOST`
        -   `signUpPOST`
-   EmailVerification recipe changes:
    -   Added mandatory `tenantId` field to `TypeEmailVerificationEmailDeliveryInput`
    -   Added mandatory `tenantId` as first parameter to the following recipe index functions:
        -   `createEmailVerificationToken`
        -   `verifyEmailUsingToken`
        -   `revokeEmailVerificationTokens`
    -   Added mandatory `tenantId` in the input for the following recipe interface functions. If any of these functions are overridden, they need to be updated accordingly:
        -   `createEmailVerificationToken`
        -   `verifyEmailUsingToken`
        -   `revokeEmailVerificationTokens`
    -   Added mandatory `tenantId` in the input for the following API interface functions. If any of these functions are overridden, they need to be updated accordingly:
        -   `verifyEmailPOST`
-   Passwordless recipe changes:
    -   Added `tenantId` param to `validateEmailAddress`, `validatePhoneNumber` and `getCustomUserInputCode` functions in `TypeInput`
    -   Added mandatory `tenantId` field to `TypePasswordlessEmailDeliveryInput` and `TypePasswordlessSmsDeliveryInput`
    -   Added mandatory `tenantId` in the input to the following recipe index functions:
        -   `createCode`
        -   `createNewCodeForDevice`
        -   `getUserByEmail`
        -   `getUserByPhoneNumber`
        -   `updateUser`
        -   `revokeCode`
        -   `listCodesByEmail`
        -   `listCodesByPhoneNumber`
        -   `listCodesByDeviceId`
        -   `listCodesByPreAuthSessionId`
        -   `signInUp`
    -   Added mandatory `tenantId` in the input for the following recipe interface functions. If any of these functions are overridden, they need to be updated accordingly:
        -   `createCode`
        -   `createNewCodeForDevice`
        -   `consumeCode`
        -   `getUserByEmail`
        -   `getUserByPhoneNumber`
        -   `revokeAllCodes`
        -   `revokeCode`
        -   `listCodesByEmail`
        -   `listCodesByPhoneNumber`
        -   `listCodesByDeviceId`
        -   `listCodesByPreAuthSessionId`
    -   Added mandatory `tenantId` in the input for the following API interface functions. If any of these functions are overridden, they need to be updated accordingly:
        -   `createCodePOST`
        -   `resendCodePOST`
        -   `consumeCodePOST`
        -   `emailExistsGET`
        -   `phoneNumberExistsGET`
-   ThirdParty recipe changes
    -   The providers array in `signInUpFeature` accepts `[]ProviderInput` instead of `[]TypeProvider`. TypeProvider interface is re-written. Refer migration section for more info.
    -   Removed `signInUp` and added `manuallyCreateOrUpdateUser` instead in the recipe index functions.
    -   Added `manuallyCreateOrUpdateUser` to recipe interface which is being called by the function mentioned above.
        -   `manuallyCreateOrUpdateUser` recipe interface function should not be overridden as it is not going to be called by the SDK in the sign in/up flow.
        -   `signInUp` recipe interface functions is not removed and is being used by the sign in/up flow.
    -   Added mandatory `tenantId` as first parameter to the following recipe index functions:
        -   `getUsersByEmail`
        -   `getUserByThirdPartyInfo`
    -   Added mandatory `tenantId` in the input for the following recipe interface functions. If any of these functions are overridden, they need to be updated accordingly:
        -   `getUsersByEmail`
        -   `getUserByThirdPartyInfo`
        -   `signInUp`
    -   Added mandatory `tenantId` in the input for the following API interface functions. If any of these functions are overridden, they need to be updated accordingly:
        -   `authorisationUrlGET`
        -   `signInUpPOST`
    -   Updated `signInUp` recipe interface function in thirdparty with new parameters:
        -   `oAuthTokens` - contains all the tokens (access_token, id_token, etc.) as returned by the provider
        -   `rawUserInfoFromProvider` - contains all the user profile info as returned by the provider
    -   Updated `authorisationUrlGET` API
        -   Changed: Doesn't accept `clientId` anymore and accepts `clientType` instead to determine the matching config
        -   Added: optional `pkceCodeVerifier` in the response, to support PKCE
    -   Updated `signInUpPOST` API
        -   Removed: `clientId`, `redirectURI`, `authCodeResponse` and `code` from the input
        -   Instead,
            -   accepts `clientType` to determine the matching config
            -   One of redirectURIInfo (for code flow) or oAuthTokens (for token flow) is required
    -   Updated `appleRedirectHandlerPOST`
        -   to accept all the form fields instead of just the code
        -   to use redirect URI encoded in the `state` parameter instead of using the websiteDomain config.
        -   to use HTTP 303 instead of javascript based redirection.
-   Session recipe changes
    -   Added mandatory `tenantId` as first parameter to the following recipe index functions:
        -   `createNewSession`
        -   `createNewSessionWithoutRequestResponse`
        -   `validateClaimsInJWTPayload`
    -   Added mandatory `tenantId` in the input for the following recipe interface functions. If any of these functions are overridden, they need to be updated accordingly:
        -   `createNewSession`
        -   `getGlobalClaimValidators`
    -   Added `tenantId` and `revokeAcrossAllTenants` params to `revokeAllSessionsForUser` in the recipe interface.
    -   Added `tenantId` and `fetchAcrossAllTenants` params to `getAllSessionHandlesForUser` in the recipe interface.
    -   Added `getTenantId` function to `SessionContainerInterface`
    -   Added `tenantId` to `fetchValue` function in `PrimitiveClaim`, `PrimitiveArrayClaim`.
-   UserRoles recipe changes
    -   Added mandatory `tenantId` as first parameter to the following recipe index functions:
        -   `addRoleToUser`
        -   `removeUserRole`
        -   `getRolesForUser`
        -   `getUsersThatHaveRole`
    -   Added mandatory `tenantId` in the input for the following recipe interface functions. If any of these functions are overridden, they need to be updated accordingly:
        -   `addRoleToUser`
        -   `removeUserRole`
        -   `getRolesForUser`
        -   `getRolesForUser`
-   Similar changes in combination recipes (thirdpartyemailpassword and thirdpartypasswordless) have been made
-   Even if thirdpartyemailpassword and thirdpartpasswordless recipes do not have a providers array as an input, they will still expose the third party recipe routes to the frontend.
-   Returns 400 status code in emailpassword APIs if the input email or password are not of type string.

### Changes

-   Recipe function changes:
    -   Added optional `tenantIdForPasswordPolicy` param to `EmailPassword.updateEmailOrPassword`, `ThirdPartyEmailPassword.updateEmailOrPassword`
    -   Added optional param `tenantId` to `Session.revokeAllSessionsForUser`. If tenantId is undefined, sessions are revoked across all tenants
    -   Added optional param `tenantId` to `Session.getAllSessionHandlesForUser`. If tenantId is undefined, sessions handles across all tenants are returned
-   Adds optional param `tenantId` to `getUserCount` which returns total count across all tenants if not passed.
-   Adds protected prop `tId` to the accessToken payload
-   Adds `includesAny` claim validator to `PrimitiveArrayClaim`

### Fixes

-   Fixed an issue where certain Dashboard API routes would return a 404 for Hapi

### Migration

-   To call any recipe function that has `tenantId` added to it, pass `'public`'

    Before:

    ```ts
    EmailPassword.signUp("test@example.com", "password");
    ```

    After:

    ```ts
    EmailPassword.signUp("public", "test@example.com", "password");
    ```

-   Input for provider array change as follows:

    Before:

    ```ts
    let googleProvider = thirdParty.Google({
        clientID: "...",
        clientSecret: "...",
    });
    ```

    After:

    ```ts
    let googleProvider = {
        config: {
            thirdPartyId: "google",
            clients: [{ clientId: "...", clientSecret: "..." }],
        },
    };
    ```

-   Single instance with multiple clients of each provider instead of multiple instances of them. Also use `clientType` to differentiate them. `clientType` passed from the frontend will be used to determine the right config. `isDefault` option has been removed and `clientType` is expected to be passed when there are more than one client. If there is only one client, `clientType` is optional and will be used by default.

    Before:

    ```ts
    let providers = [
        thirdParty.Google({
            isDefault: true,
            clientID: "clientid1",
            clientSecret: "...",
        }),
        thirdParty.Google({
            clientID: "clientid2",
            clientSecret: "...",
        }),
    ];
    ```

    After:

    ```ts
    let providers = [
        {
            config: {
                thirdPartyId: "google",
                clients: [
                    { clientType: "web", clientId: "clientid1", clientSecret: "..." },
                    { clientType: "mobile", clientId: "clientid2", clientSecret: "..." },
                ],
            },
        },
    ];
    ```

-   Change in the implementation of custom providers

    -   All config is part of `ProviderInput`
    -   To provide implementation for `getProfileInfo`
        -   either use `userInfoEndpoint`, `userInfoEndpointQueryParams` and `userInfoMap` to fetch the user info from the provider
        -   or specify custom implementation in an override for `getUserInfo` (override example in the next section)

    Before:

    ```ts
    let customProvider = {
        id: "custom",
        get: (redirectURI, authCodeFromRequest) => {
            return {
                accessTokenAPI: {
                    url: "...",
                    params: {},
                },
                authorisationRedirect: {
                    url: "...",
                    params: {},
                },
                getClientId: () => {
                    return "...";
                },
                getProfileInfo: async (accessTokenAPIResponse) => {
                    return {
                        id: "...",
                        email: {
                            id: "...",
                            isVerified: true,
                        },
                    };
                },
            };
        },
    };
    ```

    After:

    ```ts
    let customProvider = {
        config: {
            thirdPartyId: "custom",
            clients: [
                {
                    clientId: "...",
                    clientSecret: "...",
                },
            ],
            authorizationEndpoint: "...",
            authorizationEndpointQueryParams: {},
            tokenEndpoint: "...",
            tokenEndpointBodyParams: {},
            userInfoEndpoint: "...",
            userInfoEndpointQueryParams: {},
            userInfoMap: {
                fromUserInfoAPI: {
                    userId: "id",
                    email: "email",
                    emailVerified: "email_verified",
                },
            },
        },
    };
    ```

    Also, if the custom provider supports openid, it can automatically discover the endpoints

    ```ts
    let customProvider = {
        config: {
            thirdPartyId: "custom",
            clients: [
                {
                    clientId: "...",
                    clientSecret: "...",
                },
            ],
            oidcDiscoveryEndpoint: "...",
            userInfoMap: {
                fromUserInfoAPI: {
                    userId: "id",
                    email: "email",
                    emailVerified: "email_verified",
                },
            },
        },
    };
    ```

    Note: The SDK will fetch the oauth2 endpoints from the provider's OIDC discovery endpoint. No need to `/.well-known/openid-configuration` to the `oidcDiscoveryEndpoint` config. For eg. if `oidcDiscoveryEndpoint` is set to `"https://accounts.google.com/"`, the SDK will fetch the endpoints from `"https://accounts.google.com/.well-known/openid-configuration"`

-   Any of the functions in the TypeProvider can be overridden for custom implementation

    -   Overrides can do the following:
        -   update params, headers dynamically for the authorization redirect url or in the exchange of code to tokens
        -   add custom logic to exchange code to tokens
        -   add custom logic to get the user info

    ```ts
    let customProvider = {
        config: {
            thirdPartyId: "custom",
            clients: [
                {
                    clientId: "...",
                    clientSecret: "...",
                },
            ],
            oidcDiscoveryEndpoint: "...",
            userInfoMap: {
                fromUserInfoAPI: {
                    userId: "id",
                    email: "email",
                    emailVerified: "email_verified",
                },
            },
        },
        override: (originalImplementation) => {
            return {
                ...originalImplementation,
                getAuthorisationRedirectURL: async (input) => {
                    let result = await originalImplementation.getAuthorisationRedirectURL(input);
                    // ...
                    return result;
                },

                exchangeAuthCodeForOAuthTokens: async (input) => {
                    let result = await originalImplementation.exchangeAuthCodeForOAuthTokens(input);
                    // ...
                    return result;
                },

                getUserInfo: async (input) => {
                    let result = await originalImplementation.getUserInfo(input);
                    // ...
                    return result;
                },
            };
        },
    };
    ```

-   To get access token and raw user info from the provider, override the signInUp function

    ```ts
    ThirdParty.init({
        override: {
            functions: (oI) => {
                return {
                    ...oI,
                    signInUp: async (input) => {
                        let result = await oI.signInUp(input);
                        // result.oAuthTokens.access_token
                        // result.oAuthTokens.id_token
                        // result.rawUserInfoFromProvider.fromUserInfoAPI
                        // result.rawUserInfoFromProvider.fromIdTokenPayload
                        return result;
                    },
                };
            },
        },
    });
    ```

-   Request body of thirdparty signinup API has changed

    -   If using auth code:

        Before:

        ```json
        {
            "thirdPartyId": "...",
            "clientId": "...",
            "redirectURI": "...", // optional
            "code": "..."
        }
        ```

        After:

        ```json
        {
            "thirdPartyId": "...",
            "clientType": "...",
            "redirectURIInfo": {
                "redirectURIOnProviderDashboard": "...", // required
                "redirectURIQueryParams": {
                    "code": "...",
                    "state": "..."
                    // ... all callback query params
                },
                "pkceCodeVerifier": "..." // optional, use this if using PKCE flow
            }
        }
        ```

    -   If using tokens:

        Before:

        ```json
        {
            "thirdPartyId": "...",
            "clientId": "...",
            "redirectURI": "...",
            "authCodeResponse": {
                "access_token": "...", // required
                "id_token": "..."
            }
        }
        ```

        After:

        ```json
        {
            "thirdPartyId": "...",
            "clientType": "...",
            "oAuthTokens": {
                "access_token": "...", // now optional
                "id_token": "..."
                // rest of the oAuthTokens as returned by the provider
            }
        }
        ```

### SDK and core compatibility

-   Compatible with Core>=6.0.0 (CDI 4.0)
-   Compatible with frontend SDKs:
    -   supertokens-auth-react@0.34.0
    -   supertokens-web-js@0.7.0
    -   supertokens-website@17.0.2

