supertokens-node
Version:
NodeJS driver for SuperTokens core
1,117 lines (878 loc) • 148 kB
Markdown
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html)
## Unreleased
## [24.0.0] - 2025-12-02
- Adds support for SAML
## [23.1.0] - 2025-11-27
- Fix the OAuth2Provider `tokenExchange` error message when the refresh token is expired
- Updates custom framework to following correct CollectingResponse flow order (to ensure that subsequent calls to the `sendJSONResponse` doesn't overwrite the response).
- Updated/expanded plugin support.
- Reworked internals to avoid dynamic requires and circular dependencies
## [23.0.1] - 2025-07-31
- Updated FDI support to 4.2
- Added `recipeUserId` in the WebAuthn list credentials response
- Added `recipeUserId` as required field for registering new WebAuthn credentials endpoint
- Fix WebAuthn credential listing and removal to work even when the WebAuthn user is not the primary user and when there are multiple WebAuthn users linked
- Prevent removal of WebAuthn credentials unless all session claims are satisfied
- Change how sessions are fetched before listing, removing and adding WebAuthn credentials
## [23.0.0] - 2025-07-21
### Breaking changes
- The `getConsentRequest`, `acceptConsentRequest`, `rejectConsentRequest`, `acceptLoginRequest`, `rejectLoginRequest` and `introspectToken` can now possibly return an `ErrorOAuth2`.
- The `/oauth/introspect` can now possibly return an `ErrorAuth2`.
- Removed default defaultMaxAge from all built-in claims/validators. You can optionally set them when adding the validators. This should help with unexpected API calls during session verification.
- Added register credential endpoint for the WebAuthn recipe
### Refactors/Internal changes
- Refactors querier to use dynamic request body and response body types inference.
- Refactor internal network calls made with querier to use the new dynamic types.
- The `User` class now has a `fromApi` function to normalize the user object returned from the API.
- Added experimental support for plugins. Please note that the experimental nature of this feature means that we might break the interface in non-major version updates.
- Refactor the AccountLinking recipe to be automatically initialized on SuperTokens init instead during the first call
- Upgrade typedoc and the reference docs
- Add a method for verifying if a recipe is initialized or not
## [22.1.1] - 2025-06-20
- Migrates backend-sdk-testing test to use a containerized core
- Migrates from CircleCI to Github Actions
- Adds workflow to test supertokens-website
- Updates `frontendIntegration` servers
- Fixes broken workflows (Example Tests, AWS Edge function compatibility)
- Sets up workflow to run auth-react tests
- Updates test-servers to work with updated tests
- Refactors internal logic of parsing cookies to check accessToken and optimizes it to avoid parsing unrelated cookies.
- Fixes an issue with fetch not supporting `cache: no-cache` in Cloudflare Workers.
## [22.1.0] - 2025-04-04
- Adds support for using `code_challenge_method` from OIDC provider response to determine whether to use PKCE or not.
- Fixes issue with ThirdParty provider info on dashboard
## [22.0.1] - 2025-03-26
- Added Dashboard support for WebAuthn
## [22.0.0] - 2025-03-19
### Breaking changes
- Makes URL path normalization case sensitive
- Updates `normalise_url_path_or_throw_error` to be case sensitive
- URL paths will not be converted to lower-case, and will be kept as-is.
- Updated CDI supported version from `5.2` to `5.3`
- Changed `AccountInfo` to `AccountInfoInput` in various methods for better type safety. This is required in order to allow querying by a single WebAuthn `credentialId`, while the WebAuthn login method contains an array of `credentialId`
### Added WebAuthn (Passkeys) Support
- Added WebAuthn recipe with authentication support:
- Registration, sign-in, and credential verification flows
- Account recovery functionality
- Added new API endpoints for WebAuthn operations:
- GET `/api/webauthn/email/exists` - Check if email exists in system
- POST `/api/webauthn/options/register` - Handle registration options
- POST `/api/webauthn/options/signin` - Handle sign-in options
- POST `/api/webauthn/signin` - Handle WebAuthn sign-in
- POST `/api/webauthn/signup` - Handle WebAuthn sign-up
- POST `/api/user/webauthn/reset` - Handle account recovery
- POST `/api/user/webauthn/reset/token` - Generate recovery tokens
- Added WebAuthn support to account linking functionality:
- Support for linking users based on WebAuthn `credentialId`
- Updated `AccountInfo` type to `AccountInfoInput` with WebAuthn fields
- Added `hasSameWebauthnInfoAs` method for credential comparison
- Updated FDI support to `4.1`
## [21.1.1] - 2025-03-18
- Fixes an issue where the response body was not being cloned when using cache
- Fixes type of `cookies` to `string[]` instead of `string` in:
- Return type of `authorization` in `RecipeInterface` in `oauth2provider` recipe
- Return type of `authGET` in `APIInterface` in `oauth2provider` recipe
- Return type of `loginGET` in `APIInterface` in `oauth2provider` recipe
## [21.1.0] - 2024-11-19
- Adds `getCookieNameForTokenType` config option to allow customizing the cookie name for a token type.
- Adds `getResponseHeaderNameForTokenType` config option to allow customizing the response header name for a token type.
- Please note, that using this will require further customizations on the frontend
- Fixes an issue where `removeDevice` API allowed removing verified TOTP devices without the user completing MFA.
## [21.0.0] - 2024-10-07
- Added OAuth2Provider recipe
- Added a way to run CI on unmerged PRs
- Added support for FDIs: 3.1 and 4.0. Required by: auth-react >=0.48.0 and web-js>=0.14.0
- The `networkInterceptor` now also gets a new `params` prop in the request config.
- Adds `customFramework` util functions to minimize code required in custom frameworks like remix, astro etc.
- Replicates `fastify` types based on requirement for the SDK instead of using the original module.
- Improved type definitions for `TypeProvider`
### Breaking change
- Changes type of value in formField object to be `unknown` instead of `string` to add support for accepting any type of value in form fields.
- Only supporting CDI 5.2, Compatible with Core version >= 9.3
- Removed the `overwriteSessionDuringSignInUp` option.
- Added a new `shouldTryLinkingWithSessionUser` to sign in/up related APIs (and the related recipe functions)
- This will default to false on the API
- This will be set to true in function calls if you pass a session, otherwise it is set to false
- By setting this to true you can enable MFA flows (trying to connect to the session user)
- If set to false, the sign-in/up will be considered a first-factor
- Changed APIs:
- `EmailPassword.signInPOST`
- `EmailPassword.signUpPOST`
- `ThirdParty.signInUpPOST`
- `Passwordless.createCodePOST`
- `Passwordless.consumeCodePOST`
- `Passwordless.resendCodePOST`
- Changed functions:
- `EmailPassword.signIn`
- `EmailPassword.signUp`
- `ThirdParty.signInUp`
- `ThirdPary.manuallyCreateOrUpdateUser`
- `Passwordless.createCode`
- `Passwordless.consumeCode`
- We no longer try to load the session if `shouldTryLinkingWithSessionUser` is set to false.
- Changed the return type of `getOpenIdConfiguration` and `getOpenIdDiscoveryConfigurationGET`, and added the following props:
- authorization_endpoint
- token_endpoint
- userinfo_endpoint
- revocation_endpoint
- token_introspection_endpoint
- end_session_endpoint
- subject_types_supported
- id_token_signing_alg_values_supported
- response_types_supported
- Exposing the OpenId recipe separately and remove it from the Session recipe
- This means that we removed `override.openIdFeature` from the Session recipe configuration
- Removed `getJWKS` from the OpenId recipe, as it is already exposed by the JWT recipe
- We now automatically initialize the OpenId and JWT recipes even if you do not use the Session recipe
- `getAppDirRequestHandler` for `nextjs` will no longer accept a Response object.
### Migration
#### Separating the OpenId recipe from Session recipe
If you used to use the `openIdFeature` in the Session recipe, you should now use the OpenId recipe directly instead:
Before:
```tsx
import SuperTokens from "supertokens-node";
import Session from "supertokens-node/recipe/session";
SuperTokens.init({
appInfo: {
apiDomain: "...",
appName: "...",
websiteDomain: "...",
},
recipeList: [
Session.init({
override: {
openIdFeature: {
jwtFeature: {
functions: originalImplementation => ({
...originalImplementation,
getJWKS: async (input) => {
console.log("getJWKS called");
return originalImplementation.getJWKS(input);
},
})
},
functions: originalImplementation => ({
...originalImplementation,
getOpenIdDiscoveryConfiguration: async (input) => ({
issuer: "your issuer",
jwks_uri: "https://your.api.domain/auth/jwt/jwks.json",
status: "OK"
}),
})
}
}
});
],
});
```
After:
```tsx
import SuperTokens from "supertokens-node";
import Session from "supertokens-node/recipe/session";
import OpenId from "supertokens-node/recipe/openid";
import JWT from "supertokens-node/recipe/jwt";
SuperTokens.init({
appInfo: {
apiDomain: "...",
appName: "...",
websiteDomain: "...",
},
recipeList: [
Session.init(),
JWT.init({
override: {
functions: originalImplementation => ({
...originalImplementation,
getJWKS: async (input) => {
console.log("getJWKS called");
return originalImplementation.getJWKS(input);
},
})
}
}),
OpenId.init({
override: {
functions: originalImplementation => ({
...originalImplementation,
getOpenIdDiscoveryConfiguration: async (input) => ({
issuer: "your issuer",
jwks_uri: "https://your.api.domain/auth/jwt/jwks.json",
status: "OK"
}),
})
}
});
],
});
```
#### Using updated `getAppDirRequestHandler` for next.js
Before:
```ts
import { getAppDirRequestHandler } from "supertokens-node/nextjs";
import { NextResponse } from "next/server";
const handleCall = getAppDirRequestHandler(NextResponse);
```
After:
```ts
import { getAppDirRequestHandler } from "supertokens-node/nextjs";
const handleCall = getAppDirRequestHandler();
```
## [20.1.5] - 2024-10-09
- Fixes an issue where users were not able to reset their password if a user with the same email address was created before account linking was enabled.
- Fixes and re-works some security checks connected to password reset.
## [20.1.4] - 2024-10-07
- Fixes an issue where revoking sessions for a specific tenant didn't work well
- Fixes an issue where the automatic session revocation after linking didn't work across all tenants
## [20.1.3] - 2024-09-30
- Replaces `psl` with `tldts` to avoid `punycode` deprecation warning.
## [20.1.2] - 2024-09-14
- Fixes formFields to accept non string types as well.
## [20.1.1] - 2024-09-10
- Fixes an issue with Okta / Active Directory providers where we check for additional config if `oidcDiscoveryEndpoint` is not defined. It would not be necessary in the cases where other endpoints are already provided.
## [20.1.0] - 2024-09-09
- Add edge compatibility for custom frameworks and Next.JS
## [20.0.5] - 2024-09-02
- Optional form fields are now truly optional, can be omitted from the payload.
## [20.0.4] - 2024-08-30
- Improves thirdParty debug logging to help with debugging issues with JSON parsing.
## [20.0.3] - 2024-08-22
- Fixes issue with dashboard APIs `createOrUpdateThirdPartyConfig` and `deleteThirdPartyConfig` which did not take `includeInNonPublicTenantsByDefault` into account for non-public tenants.
- Updates test server to support dashboard tests.
## [20.0.2] - 2024-08-08
- Fixes an issue where `shouldDoAutomaticAccountLinking` was called without a primary user when linking in some cases.
## [20.0.1] - 2024-08-05
- Fixes an issue with `removeFromPayloadByMerge_internal` for `MultiFactorAuthClaim` where it was not retaining other claims while removing the claim from the payload.
- Updates testing with backend-sdk-testing repo to run against all supported FDI versions.
## [20.0.0] - 2024-07-24
### Changes
- Updates `createOrUpdateThirdPartyConfig` and `getThirdPartyConfig` dashboard APIs to handle boxy SAML inputs.
- Fixes an issue where `isEmailChangeAllowed` was not checking across all tenants
### Breaking changes
- For a non-public tenant, when there are no providers added in the core, the SDK used to fallback to the providers added in the ThirdParty.init. Now, the SDK will not fallback to the providers added in the ThirdParty.init by default. If you require a thirdparty provider to be available for non-public tenants, you can make it available by setting `includeInNonPublicTenantsByDefault` for each of the providers. See the migration section below to see how to do this. Note that this only affects non-public tenants when there are no providers added in core.
### Migration
To make all the providers added in the ThirdParty.init available for non-public tenants by default,
Before:
```ts
ThirdParty.init({
signInAndUpFeature: {
providers: [
{
config: {
thirdPartyId: "google",
// ... rest of the config
},
},
{
config: {
thirdPartyId: "github",
// ... rest of the config
},
},
],
},
});
```
After:
```ts
ThirdParty.init({
signInAndUpFeature: {
providers: [
{
config: {
thirdPartyId: "google",
// ... rest of the config
},
// Add the following line to make this provider available in non-public tenants by default
includeInNonPublicTenantsByDefault: true,
},
{
config: {
thirdPartyId: "github",
// ... rest of the config
},
// Add the following line to make this provider available in non-public tenants by default
includeInNonPublicTenantsByDefault: true,
},
],
},
});
```
## [19.0.1] - 2024-07-18
- Fixes issue in fetching `thirdPartyConfig` for dashboard when OIDC discovery endpoint is added in core.
## [19.0.0] - 2024-07-10
### Breaking changes
- Defined the entry points of the library using the "exports" field in package.json to make ESM imports more comfortable. This can cause some issues for applications using directory imports from the `lib/build` directory. In those cases we recommend adding `index.js` to the import path.
- `isEmailChangeAllowed` now returns false for unverified addresses if input user is a primary user and there exists another user with the same email address and linking requires verification
- Generating a password reset token is now denied if all of the following is true:
- a linked email password user exists
- the email address is not verified
- the user has another email address or phone number associated with it
- Account linking based on emails now require the email to be verified in both users if `shouldRequireVerification` is set to `true` instead of only requiring it for the recipe user.
- The access token cookie expiry has been changed from 100 years to 1 year due to some browsers capping the maximum expiry at 400 days. No action is needed on your part.
- Recipe functions that update the email address of users now call `isEmailChangeAllowed` to check if the email update should be allowed or not.
- This only has an effect if account linking is turned on.
- This is aimed to help you avoid security issues.
- `isEmailChangeAllowed` is now called in functions:
- `updateUser` (Passwordless recipe)
- `updateEmailOrPassword` (EmailPassword recipe)
- `manuallyCreateOrUpdateUser` (ThirdParty recipe)
- Removes the default `maxAgeInSeconds` value (previously 300 seconds) in EmailVerification Claim. If the claim value is true and `maxAgeInSeconds` is not provided, it will not be refetched.
- In the multitenancy recipe,
- Removes `emailPasswordEnabled`, `passwordlessEnabled`, `thirdPartyEnabled` inputs from `createOrUpdateTenant` functions.
- Recipe implementation uses v2 APIs for creating, fetching and listing tenants. Refer CDI spec for more information.
- SDK will no longer add `.well-known/openid-configuration` to the `oidcDiscoveryEndpoint` config in thirdParty providers. If you have specified any custom `oidcDiscoveryEndpoint` in the ThirdParty.init or added to the core, please make sure to update them to include `.well-known/openid-configuration`.
### Changes
- Adds Multitenancy and Multifactor auth related APIs for dashboard:
- GET `/api/tenants`
- GET `/api/tenant`
- POST `/api/tenant`
- DELETE `/api/tenant`
- PUT `/api/tenant/first-factor`
- PUT `/api/tenant/required-secondary-factor`
- PUT `/api/tenant/core-config`
- GET `/api/thirdparty/config`
- PUT `/api/thirdparty/config`
- DELETE `/api/thirdparty/config`
- `passwordResetPOST`:
- now verifies the email address in all cases if the EmailVerification recipe is initialized
- now tries to link accounts based on account info if AccountLinking is enabled
- Extracted some tests into a separate [backend-sdk-testing](https://github.com/supertokens/backend-sdk-testing/) repo, to reuse tests between our backend SDKs
- Sends `websiteDomain` and `apiDomain` to core for telemetry.
- `boxyURL` is no more mandatory input in `additionalConfig` while adding boxy-saml provider in thirdParty.
- Fixes issue with OIDC discover when the input url already contains `.well-known/openid-configuration`.
- Removes the default `maxAgeInSeconds` value in EmailVerification Claim when the claim value is true. Now, the SDK won't refetch the claim value if `maxAgeInSeconds` is not provided and claim value is true.
- Adds `jwksRefreshIntervalSec` config to `session.init` to set the default JWKS cache duration. The default is 4 hours.
### Migration
#### Create or update tenant
If you were using Multitenancy.createOrUpdateTenant, you should remove the `emailPasswordEnabled`, `passwordlessEnabled`, `thirdPartyEnabled` inputs from the function call, and just use the `firstFactors` and `requiredSecondaryFactors` as applicable.
Here are some examples:
1. Using Emailpassword and ThirdParty login methods
Before:
```ts
Multitenancy.createOrUpdateTenant("tenantId", {
emailPasswordEnabled: true,
thirdPartyEnabled: true,
});
```
After:
```ts
Multitenancy.createOrUpdateTenant("tenantId", {
firstFactors: ["emailpassword", "thirdparty"],
});
```
2. Using Passwordless and ThirdParty login methods. Note that for passwordless, you need to specify all the passwordless factorIds you wish to use.
Before:
```ts
Multitenancy.createOrUpdateTenant("tenantId", {
passwordlessEnabled: true,
thirdPartyEnabled: true,
});
```
After:
```ts
Multitenancy.createOrUpdateTenant("tenantId", {
firstFactors: ["otp-email", "otp-phone", "link-email", "link-phone", "thirdparty"],
});
```
3. Using EmailPassword, ThirdParty for first factor and phone OTP, TOTP for secondary factors
Before:
```ts
Multitenancy.createOrUpdateTenant("tenantId", {
emailPasswordEnabled: true,
thirdPartyEnabled: true,
passwordlessEnabled: true,
firstFactors: ["emailpassword", "thirdparty"],
requiredSecondaryFactors: ["otp-phone", "totp"],
});
```
After:
```ts
Multitenancy.createOrUpdateTenant("tenantId", {
firstFactors: ["emailpassword", "thirdparty"],
requiredSecondaryFactors: ["otp-phone", "totp"],
});
```
4. Enable everything in core so that SDK can configure the required login methods and required secondary factors
Before:
```ts
Multitenancy.createOrUpdateTenant("tenantId", {
emailPasswordEnabled: true,
thirdPartyEnabled: true,
passwordlessEnabled: true,
});
```
After:
```ts
Multitenancy.createOrUpdateTenant("tenantId", {
firstFactors: null,
requiredSecondaryFactors: null,
});
```
#### Migrating `oidcDiscoveryEndpoint` in ThirdParty.init:
Before:
```ts
ThirdParty.init({
signInAndUpFeature: {
providers: [
{
config: {
thirdPartyId: "custom",
clients: [
// ...
],
oidcDiscoveryEndpoint: "https://auth.example.com",
},
},
],
},
});
```
After:
```ts
ThirdParty.init({
signInAndUpFeature: {
providers: [
{
config: {
thirdPartyId: "custom",
clients: [
// ...
],
oidcDiscoveryEndpoint: "https://auth.example.com/.well-known/openid-configuration",
},
},
],
},
});
```
#### Migrating `oidcDiscoveryEndpoint` in core (for custom providers only):
For each tenant, do the following
1. GET `/appid-<appId>/<tenantId>/recipe/multitenancy/tenant/v2`
You should see the thirdParty providers in the response using `response.thirdParty.providers`
2. For each config in providers list, if you have `oidcDiscoveryEndpoint` in the config, update it to include `.well-known/openid-configuration` at the end.
Here's a sample code snippet to update the `oidcDiscoveryEndpoint`:
```ts
import Multitenancy from "supertokens-node/recipe/multitenancy";
const tenantsRes = await Multitenancy.listAllTenants();
function isCustomProvider(thirdPartyId: string): boolean {
const customProviders = [
"custom",
//... all your custom thirdPartyIds
];
return customProviders.includes(thirdPartyId);
}
for (const tenant of tenantsRes.tenants) {
for (const provider of tenant.thirdParty.providers) {
if (isCustomProvider(provider.thirdPartyId) && provider.oidcDiscoveryEndpoint !== undefined) {
if (provider.oidcDiscoveryEndpoint.endsWith("/")) {
provider.oidcDiscoveryEndpoint = provider.oidcDiscoveryEndpoint.slice(0, -1);
}
provider.oidcDiscoveryEndpoint = `${provider.config.oidcDiscoveryEndpoint}/.well-known/openid-configuration`;
await Multitenancy.createOrUpdateThirdPartyConfig(tenant.tenantId, provider);
}
}
}
```
## [18.0.2] - 2024-07-09
- `refreshPOST` and `refreshSession` now clears all user tokens upon CSRF failures and if no tokens are found. See the latest comment on https://github.com/supertokens/supertokens-node/issues/141 for more details.
## [18.0.2] - 2024-07-09
- `refreshPOST` and `refreshSession` now clears all user tokens upon CSRF failures and if no tokens are found. See the latest comment on https://github.com/supertokens/supertokens-node/issues/141 for more details.
## [18.0.1] - 2024-06-19
### Fixes
- Fix a bug that was preventing errors from being caught in the fetch function, thus bypassing our error handling.
## [18.0.0] - 2024-05-23
### Breaking change
- Removed ThirdPartyEmailPassword and ThirdPartyPasswordless recipes. Instead, you should use ThirdParty + EmailPassword or ThirdParty + Passwordless recipes separately in your recipe list.
- Removed `rid` query param from:
- email verification links
- passwordless magic links
- password reset links
- The API for checking if an email exists in the passwordless recipe has changed to return true only if there exists a user with that email as a passwordless user. So for example, earlier, if a user existed with email `test@example.com` as an emailpassword user (and not passwordless user), the passwordless API for does email exist would return true, but now, it won't.
### Changes
- Even if the `rid` header is present in an API call, the routing now not only depends on that. If the SDK cannot resolve a request handler based on the `rid`, request path and method, it will try to resolve a request handler only based on the request path and method (therefore ignoring the `rid` header).
- New API handlers are:
- `GET /emailpassword/email/exists` => email password, does email exist API (used to be `GET /signup/email/exists` with `rid` of `emailpassword` or `thirdpartyemailpassword` which is now deprecated)
- `GET /passwordless/email/exists` => email password, does email exist API (used to be `GET /signup/email/exists` with `rid` of `passwordless` or `thirdpartypasswordless` which is now deprecated)
- `GET /passwordless/phonenumber/exists` => email password, does email exist API (used to be `GET /signup/phonenumber/exists` which is now deprecated)
- Support for FDI 2.0 and 3.0
### Migration guide
- If you were using `ThirdPartyEmailPassword`, you should now init `ThirdParty` and `EmailPassword` recipes separately. The config for the individual recipes are mostly the same, except the syntax may be different. Check our recipe guides for [ThirdParty](https://supertokens.com/docs/thirdparty/introduction) and [EmailPassword](https://supertokens.com/docs/emailpassword/introduction) for more information.
- If you were using `ThirdPartyPasswordless`, you should now init `ThirdParty` and `Passwordless` recipes separately. The config for the individual recipes are mostly the same, except the syntax may be different. Check our recipe guides for [ThirdParty](https://supertokens.com/docs/thirdparty/introduction) and [Passwordless](https://supertokens.com/docs/passwordless/introduction) for more information.
### Fixes
- Fixes override recursion build-up in built-in providers due to the modification of the `input.override` object in the ThirdParty providers list.
- Fixes issue with reference to `config` object in `TypeProvider` in the provider override. The issue was the `originalImplementation.config` object did not have the updated `config` values that was being used in the provider implementation.
## [17.1.2] - 2024-05-21
### Fixes
- Add workaround for unsupported 'cache' field in Cloudflare Workers. We retry fetch requests without the 'cache' field if they fail due to it not being implemented.
## [17.1.1] - 2024-05-16
### Fixes
- Fixed an issue when using Apple as a third party provider with our NextJs integration.
- Added a compatibility layer into `BaseRequest` to handle the form data parser returning `FormData` instead of the raw parsed object. This is to address/fix the above issues, possibly present in other frameworks.
## [17.1.0] - 2024-04-25
- Added `olderCookieDomain` config option in the session recipe. This will allow users to clear cookies from the older domain when the `cookieDomain` is changed.
- If `verifySession` detects multiple access tokens in the request, it will return a 401 error, prompting a refresh, even if one of the tokens is valid.
- `refreshPOST` (`/auth/session/refresh` by default) API changes:
- now returns 500 error if multiple access tokens are present in the request and `config.olderCookieDomain` is not set.
- now clears the access token cookie if it was called without a refresh token (if an access token cookie exists and if using cookie-based sessions).
- now clears cookies from the old domain if `olderCookieDomain` is specified and multiple refresh/access token cookies exist, without updating the front-token or any of the tokens.
- now a 200 response may not include new session tokens.
### Rationale
This update addresses an edge case where changing the `cookieDomain` config on the server can lead to session integrity issues. For instance, if the API server URL is 'api.example.com' with a cookie domain of '.example.com', and the server updates the cookie domain to 'api.example.com', the client may retain cookies with both '.example.com' and 'api.example.com' domains, resulting in multiple sets of session token cookies existing.
Previously, verifySession would select one of the access tokens from the incoming request. If it chose the older cookie, it would return a 401 status code, prompting a refresh request. However, the `refreshPOST` API would then set new session token cookies with the updated `cookieDomain`, but older cookies will persist, leading to repeated 401 errors and refresh loops.
With this update, verifySession will return a 401 error if it detects multiple access tokens in the request, prompting a refresh request. The `refreshPOST` API will clear cookies from the old domain if `olderCookieDomain` is specified in the configuration, then return a 200 status. If `olderCookieDomain` is not configured, the `refreshPOST` API will return a 500 error with a message instructing to set `olderCookieDomain`.
**Example:**
- `apiDomain`: 'api.example.com'
- `cookieDomain`: 'api.example.com'
**Flow:**
1. After authentication, the frontend has cookies set with `domain=api.example.com`, but the access token has expired.
2. The server updates `cookieDomain` to `.example.com`.
3. An API call requiring session with an expired access token (cookie with `domain=api.example.com`) results in a 401 response.
4. The frontend attempts to refresh the session, generating a new access token saved with `domain=.example.com`.
5. The original API call is retried, but because it sends both the old and new cookies, it again results in a 401 response.
6. The frontend tries to refresh the session with multiple access tokens: - If `olderCookieDomain` is not set, the refresh fails with a 500 error. - The user remains stuck until they clear cookies manually or `olderCookieDomain` is set. - If `olderCookieDomain` is set, the refresh clears the older cookie, returning a 200 response. - The frontend retries the original API call, sending only the new cookie (`domain=.example.com`), resulting in a successful request.
## [17.0.7] - 2024-05-03
- Adds `no-cache` header when querying core, so that frameworks like NextJS don't cache GET requests (https://nextjs.org/docs/app/building-your-application/caching#data-cache)
## [17.0.6] - 2024-05-02
- Fixes how FDI header is parsed from frontend requests to account for more than one version being passed.
## [17.0.5] - 2024-04-25
- Support for websiteDomain / apiDomain ending with `.local`: https://github.com/supertokens/supertokens-node/issues/823
## [17.0.4] - 2024-04-09
### Changes
- Improved error message to help debugging if MFA was enabled without account linking.
- Now the `resyncSessionAndFetchMFAInfoPUT` will throw if the user is in a stuck state, because they are required to complete factors, but they are not allowed to because of some configuration issue.
## [17.0.3] - 2024-04-08
### Fixes
- Smaller fixes in `Passwordless`:
- Fixed an issue in `createCodePOST` where the flowtype wasn't appropriately set in some MFA cases
- Fixed an interaction with the `firstFactors` config of the `MultiFactorAuth` recipe in `createCodePOST`
- Fixed an issue in `resendCodePOST` where the email/text message included a magic link when it shouldn't have in some MFA cases
## [17.0.2] - 2024-03-20
- Remove tenants listing dashboard API and update `getTenantLoginMethodsInfo` dashboard API to remove querying core in loop and return only firstFactors.
## [17.0.1] - 2024-03-08
### Changes
- We now allow sign in/up even if the session user is conflicting with the current sign in/up (because of the email verification status)
- This makes use-cases where an secondary factor (i.e.: otp-email) is also used as a means of verification.
## [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
Si