diff --git a/CHANGELOG.md b/CHANGELOG.md
index ed42be581..9b9b2029b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,91 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [unreleased]
+## [0.49.0] - 2024-10-07
+
+### Changes
+
+- Added the `OAuth2Provider` recipe
+- Changed the input types and default implementation of `AuthPageHeader` to show the client information in OAuth2 flows
+
+### Breaking changes
+
+- Now only supporting FDI 4.0 (Node >= 24.0.0)
+- All `getRedirectionURL` functions now also get a new `tenantIdFromQueryParams` prop
+ - This is used in OAuth2 + Multi-tenant flows.
+ - This should be safe to ignore if:
+ - You are not using those recipes
+ - You have a custom `getTenantId` implementation
+ - You are not customizing paths of the pages handled by SuperTokens.
+ - This is used to keep the `tenantId` query param during internal redirections between pages handled by the SDK.
+ - If you have custom paths, you should set the tenantId queryparam based on this. (See migrations below for more details)
+- Added a new `shouldTryLinkingToSessionUser` flag to sign in/up related function inputs:
+ - No action is needed if you are not using MFA/session based account linking.
+ - If you are implementing MFA:
+ - Plase set this flag to `false` (or leave as undefined) during first factor sign-ins
+ - Please set this flag to `true` for secondary factors.
+ - Please forward this flag to the original implementation in any of your overrides.
+ - Changed functions:
+ - `EmailPassword`:
+ - `signIn`, `signUp`: both override and callable functions
+ - `ThirdParty`:
+ - `getAuthorisationURLWithQueryParamsAndSetState`: both override and callable function
+ - `redirectToThirdPartyLogin`: callable function takes this flag as an optional input (it defaults to false on the backend)
+ - `Passwordless`:
+ - Functions overrides: `consumeCode`, `resendCode`, `createCode`, `setLoginAttemptInfo`, `getLoginAttemptInfo`
+ - Calling `createCode` and `setLoginAttemptInfo` take this flag as an optional input (it defaults to false on the backend)
+- Changed the default implementation of `getTenantId` to default to the `tenantId` query parameter (if present) then falling back to the public tenant instead of always defaulting to the public tenant
+- We now disable session based account linking in the magic link based flow in passwordless by default
+ - This is to make it function more consistently instead of only working if the link was opened on the same device
+ - You can override by overriding the `consumeCode` function in the Passwordless Recipe
+
+### Migration
+
+#### tenantIdFromQueryParams in getRedirectionURL
+
+Before:
+
+```ts
+EmailPassword.init({
+ async getRedirectionURL(context) {
+ if (context.action === "RESET_PASSWORD") {
+ return `/reset-password`;
+ }
+ return "";
+ },
+});
+```
+
+After:
+
+```ts
+EmailPassword.init({
+ async getRedirectionURL(context) {
+ return `/reset-password?tenantId=${context.tenantIdFromQueryParams}`;
+ },
+});
+```
+
+#### Session based account linking for magic link based flows
+
+You can re-enable linking by overriding the `consumeCode` function in the passwordless recipe and setting `shouldTryLinkingToSessionUser` to `true`.
+
+```ts
+Passwordless.init({
+ override: {
+ functions: (original) => {
+ return {
+ ...original,
+ consumeCode: async (input) => {
+ // Please note that this is means that the session is required and will cause an error if it is not present
+ return original.consumeCode({ ...input, shouldTryLinkingWithSessionUser: true });
+ },
+ };
+ },
+ },
+});
+```
+
## [0.47.1] - 2024-09-18
### Fixes
diff --git a/examples/for-tests/package.json b/examples/for-tests/package.json
index 9f67560d0..04323793d 100644
--- a/examples/for-tests/package.json
+++ b/examples/for-tests/package.json
@@ -4,8 +4,10 @@
"private": true,
"dependencies": {
"axios": "^0.21.0",
+ "oidc-client-ts": "^3.0.1",
"react": "^18.0.0",
"react-dom": "^18.0.0",
+ "react-oidc-context": "^3.1.0",
"react-router-dom": "6.11.2",
"react-scripts": "^5.0.1"
},
diff --git a/examples/for-tests/src/App.js b/examples/for-tests/src/App.js
index 071ada40f..71c1d7ea3 100644
--- a/examples/for-tests/src/App.js
+++ b/examples/for-tests/src/App.js
@@ -14,6 +14,7 @@ import Multitenancy from "supertokens-auth-react/recipe/multitenancy";
import UserRoles from "supertokens-auth-react/recipe/userroles";
import MultiFactorAuth from "supertokens-auth-react/recipe/multifactorauth";
import TOTP from "supertokens-auth-react/recipe/totp";
+import OAuth2Provider from "supertokens-auth-react/recipe/oauth2provider";
import axios from "axios";
import { useSessionContext } from "supertokens-auth-react/recipe/session";
@@ -27,6 +28,7 @@ import { logWithPrefix } from "./logWithPrefix";
import { ErrorBoundary } from "./ErrorBoundary";
import { useNavigate } from "react-router-dom";
import { getTestContext, getEnabledRecipes, getQueryParams } from "./testContext";
+import { getApiDomain, getWebsiteDomain } from "./config";
const loadv5RRD = window.localStorage.getItem("react-router-dom-is-v5") === "true";
if (loadv5RRD) {
@@ -43,18 +45,6 @@ const withRouter = function (Child) {
Session.addAxiosInterceptors(axios);
-export function getApiDomain() {
- const apiPort = process.env.REACT_APP_API_PORT || 8082;
- const apiUrl = process.env.REACT_APP_API_URL || `http://localhost:${apiPort}`;
- return apiUrl;
-}
-
-export function getWebsiteDomain() {
- const websitePort = process.env.REACT_APP_WEBSITE_PORT || 3031;
- const websiteUrl = process.env.REACT_APP_WEBSITE_URL || `http://localhost:${websitePort}`;
- return getQueryParams("websiteDomain") ?? websiteUrl;
-}
-
/*
* Use localStorage for tests configurations.
*/
@@ -419,6 +409,7 @@ let recipeList = [
console.log(`ST_LOGS SESSION ON_HANDLE_EVENT ${ctx.action}`);
},
}),
+ OAuth2Provider.init(),
];
let enabledRecipes = getEnabledRecipes();
@@ -452,6 +443,7 @@ if (testContext.enableMFA) {
SuperTokens.init({
usesDynamicLoginMethods: testContext.usesDynamicLoginMethods,
clientType: testContext.clientType,
+ enableDebugLogs: true,
appInfo: {
appName: "SuperTokens",
websiteDomain: getWebsiteDomain(),
@@ -813,7 +805,6 @@ function getSignInFormFields(formType) {
id: "test",
},
];
- return;
}
}
diff --git a/examples/for-tests/src/AppWithReactDomRouter.js b/examples/for-tests/src/AppWithReactDomRouter.js
index a545bb447..9e1a664ec 100644
--- a/examples/for-tests/src/AppWithReactDomRouter.js
+++ b/examples/for-tests/src/AppWithReactDomRouter.js
@@ -7,11 +7,13 @@ import { EmailPasswordPreBuiltUI } from "supertokens-auth-react/recipe/emailpass
import { PasswordlessPreBuiltUI } from "supertokens-auth-react/recipe/passwordless/prebuiltui";
import { EmailVerificationPreBuiltUI } from "supertokens-auth-react/recipe/emailverification/prebuiltui";
import { ThirdPartyPreBuiltUI, SignInAndUpCallback } from "supertokens-auth-react/recipe/thirdparty/prebuiltui";
+import { OAuth2ProviderPreBuiltUI } from "supertokens-auth-react/recipe/oauth2provider/prebuiltui";
import { AccessDeniedScreen } from "supertokens-auth-react/recipe/session/prebuiltui";
import { MultiFactorAuthPreBuiltUI } from "supertokens-auth-react/recipe/multifactorauth/prebuiltui";
import { TOTPPreBuiltUI } from "supertokens-auth-react/recipe/totp/prebuiltui";
import { BaseComponent, Home, Contact, Dashboard, DashboardNoAuthRequired } from "./App";
import { getEnabledRecipes, getTestContext } from "./testContext";
+import OAuth2Page from "./OAuth2Page";
function AppWithReactDomRouter(props) {
/**
@@ -30,7 +32,7 @@ function AppWithReactDomRouter(props) {
const emailVerificationMode = window.localStorage.getItem("mode") || "OFF";
const websiteBasePath = window.localStorage.getItem("websiteBasePath") || undefined;
- let recipePreBuiltUIList = [TOTPPreBuiltUI];
+ let recipePreBuiltUIList = [TOTPPreBuiltUI, OAuth2ProviderPreBuiltUI];
if (enabledRecipes.some((r) => r.startsWith("thirdparty"))) {
recipePreBuiltUIList.push(ThirdPartyPreBuiltUI);
}
@@ -172,6 +174,9 @@ function AppWithReactDomRouter(props) {
}
/>
)}
+
+ } />
+ } />
diff --git a/examples/for-tests/src/OAuth2Page.js b/examples/for-tests/src/OAuth2Page.js
new file mode 100644
index 000000000..3db24f8b8
--- /dev/null
+++ b/examples/for-tests/src/OAuth2Page.js
@@ -0,0 +1,91 @@
+import { AuthProvider, useAuth } from "react-oidc-context";
+import { getApiDomain, getWebsiteDomain } from "./config";
+
+// NOTE: For convenience, the same page/component handles both login initiation and callback.
+// Separate pages for login and callback are not required.
+
+const scopes = window.localStorage.getItem("oauth2-scopes") ?? "profile openid offline_access email";
+const extraConfig = JSON.parse(window.localStorage.getItem("oauth2-extra-config") ?? "{}");
+const extraSignInParams = JSON.parse(window.localStorage.getItem("oauth2-extra-sign-in-params") ?? "{}");
+const extraSignOutParams = JSON.parse(window.localStorage.getItem("oauth2-extra-sign-out-params") ?? "{}");
+
+const oidcConfig = {
+ client_id: window.localStorage.getItem("oauth2-client-id"),
+ authority: `${getApiDomain()}/auth`,
+ response_type: "code",
+ redirect_uri: `${getWebsiteDomain()}/oauth/callback`,
+ scope: scopes ? scopes : "profile openid offline_access email",
+ ...extraConfig,
+ onSigninCallback: async (user) => {
+ // Clears the response code and other params from the callback url
+ window.history.replaceState({}, document.title, window.location.pathname);
+ },
+};
+
+function AuthPage() {
+ const { signinRedirect, signinSilent, signoutSilent, signoutRedirect, user, error } = useAuth();
+
+ return (
+
+
OAuth2 Login Test
+
+ {error &&
Error: {error.message}
}
+ {user && (
+ <>
+
{JSON.stringify(user.profile, null, 2)}
+
signoutSilent(extraSignOutParams)}>
+ Logout
+
+
signoutRedirect(extraSignOutParams)}>
+ Logout (Redirect)
+
+ >
+ )}
+
signinRedirect(extraSignInParams)}>
+ Login With SuperTokens
+
+
signinSilent(extraSignInParams)}>
+ Login With SuperTokens (silent)
+
+
+ signinRedirect({
+ prompt: "login",
+ ...extraSignInParams,
+ })
+ }>
+ Login With SuperTokens (prompt=login)
+
+
+ signinRedirect({
+ max_age: 3,
+ ...extraSignInParams,
+ })
+ }>
+ Login With SuperTokens (max_age=3)
+
+
+ signinRedirect({
+ prompt: "none",
+ ...extraSignInParams,
+ })
+ }>
+ Login With SuperTokens (prompt=none)
+
+
+
+ );
+}
+
+export default function OAuth2Page() {
+ return (
+
+
+
+ );
+}
diff --git a/examples/for-tests/src/config.js b/examples/for-tests/src/config.js
new file mode 100644
index 000000000..ae591c224
--- /dev/null
+++ b/examples/for-tests/src/config.js
@@ -0,0 +1,13 @@
+import { getQueryParams } from "./testContext";
+
+export function getApiDomain() {
+ const apiPort = process.env.REACT_APP_API_PORT || 8082;
+ const apiUrl = process.env.REACT_APP_API_URL || `http://localhost:${apiPort}`;
+ return apiUrl;
+}
+
+export function getWebsiteDomain() {
+ const websitePort = process.env.REACT_APP_WEBSITE_PORT || 3031;
+ const websiteUrl = process.env.REACT_APP_WEBSITE_URL || `http://localhost:${websitePort}`;
+ return getQueryParams("websiteDomain") ?? websiteUrl;
+}
diff --git a/frontendDriverInterfaceSupported.json b/frontendDriverInterfaceSupported.json
index fb1c46a67..269e3d6ae 100644
--- a/frontendDriverInterfaceSupported.json
+++ b/frontendDriverInterfaceSupported.json
@@ -1,4 +1,4 @@
{
"_comment": "contains a list of frontend-backend interface versions that this package supports",
- "versions": ["2.0", "3.0"]
+ "versions": ["4.0"]
}
diff --git a/hooks/pre-commit.sh b/hooks/pre-commit.sh
index 68e81428d..c78117c0a 100755
--- a/hooks/pre-commit.sh
+++ b/hooks/pre-commit.sh
@@ -34,7 +34,7 @@ else
fi
npm run check-circular-dependencies
-circDep=$?
+circDep=$?
echo "$(tput setaf 3)* No circular dependencies?$(tput sgr 0)"
diff --git a/lib/.eslintrc.js b/lib/.eslintrc.js
index d7cb8d283..5f2f77fba 100644
--- a/lib/.eslintrc.js
+++ b/lib/.eslintrc.js
@@ -60,7 +60,10 @@ module.exports = {
],
"@typescript-eslint/naming-convention": "off",
"@typescript-eslint/no-explicit-any": "off",
- "@typescript-eslint/no-unused-vars": [2, { vars: "all", args: "all", varsIgnorePattern: "^React$|^jsx$" }],
+ "@typescript-eslint/no-unused-vars": [
+ 2,
+ { vars: "all", args: "all", varsIgnorePattern: "^React$|^jsx$", argsIgnorePattern: "^_" },
+ ],
"@typescript-eslint/prefer-namespace-keyword": "error",
"@typescript-eslint/quotes": ["error", "double"],
"@typescript-eslint/semi": ["error", "always"],
diff --git a/lib/build/components/assets/logoutIcon.d.ts b/lib/build/components/assets/logoutIcon.d.ts
new file mode 100644
index 000000000..4f3513ab8
--- /dev/null
+++ b/lib/build/components/assets/logoutIcon.d.ts
@@ -0,0 +1,2 @@
+///
+export default function LogoutIcon(): JSX.Element;
diff --git a/lib/build/constants.d.ts b/lib/build/constants.d.ts
index f4997a2e1..8ba89d3bd 100644
--- a/lib/build/constants.d.ts
+++ b/lib/build/constants.d.ts
@@ -1,4 +1,5 @@
export declare const RECIPE_ID_QUERY_PARAM = "rid";
+export declare const TENANT_ID_QUERY_PARAM = "tenantId";
export declare const DEFAULT_API_BASE_PATH = "/auth";
export declare const DEFAULT_WEBSITE_BASE_PATH = "/auth";
export declare const ST_ROOT_ID = "supertokens-root";
diff --git a/lib/build/emailpassword-shared3.js b/lib/build/emailpassword-shared3.js
index 73b589369..9abb90a67 100644
--- a/lib/build/emailpassword-shared3.js
+++ b/lib/build/emailpassword-shared3.js
@@ -2,7 +2,6 @@
var genericComponentOverrideContext = require("./genericComponentOverrideContext.js");
var EmailPasswordWebJS = require("supertokens-web-js/recipe/emailpassword");
-var NormalisedURLPath = require("supertokens-web-js/utils/normalisedURLPath");
var index = require("./authRecipe-shared2.js");
var types = require("./multifactorauth-shared.js");
var constants = require("./emailpassword-shared4.js");
@@ -13,7 +12,6 @@ function _interopDefault(e) {
}
var EmailPasswordWebJS__default = /*#__PURE__*/ _interopDefault(EmailPasswordWebJS);
-var NormalisedURLPath__default = /*#__PURE__*/ _interopDefault(NormalisedURLPath);
var getFunctionOverrides = function (onHandleEvent) {
return function (originalImp) {
@@ -600,29 +598,21 @@ var EmailPassword = /** @class */ (function (_super) {
_this.firstFactorIds = [types.FactorIds.EMAILPASSWORD];
_this.getDefaultRedirectionURL = function (context) {
return genericComponentOverrideContext.__awaiter(_this, void 0, void 0, function () {
- var resetPasswordPath;
return genericComponentOverrideContext.__generator(this, function (_a) {
if (context.action === "RESET_PASSWORD") {
- resetPasswordPath = new NormalisedURLPath__default.default(
- constants.DEFAULT_RESET_PASSWORD_PATH
- );
return [
2 /*return*/,
- ""
- .concat(
- this.config.appInfo.websiteBasePath
- .appendPath(resetPasswordPath)
- .getAsStringDangerous(),
- "?rid="
- )
- .concat(this.config.recipeId),
+ genericComponentOverrideContext.getDefaultRedirectionURLForPath(
+ this.config,
+ constants.DEFAULT_RESET_PASSWORD_PATH,
+ context
+ ),
];
}
return [2 /*return*/, this.getAuthRecipeDefaultRedirectionURL(context)];
});
});
};
- _this.recipeID = config.recipeId;
return _this;
}
EmailPassword.prototype.getFirstFactorsForAuthPage = function () {
diff --git a/lib/build/emailpassword.js b/lib/build/emailpassword.js
index 34ec5282c..d297074f3 100644
--- a/lib/build/emailpassword.js
+++ b/lib/build/emailpassword.js
@@ -20,6 +20,8 @@ require("./authRecipe-shared2.js");
require("./recipeModule-shared.js");
require("./multifactorauth-shared.js");
require("supertokens-web-js/recipe/session");
+require("./oauth2provider-shared.js");
+require("supertokens-web-js/recipe/oauth2provider");
require("./emailpassword-shared4.js");
require("./authRecipe-shared.js");
diff --git a/lib/build/emailpasswordprebuiltui.js b/lib/build/emailpasswordprebuiltui.js
index f0e7253a8..7614a23e1 100644
--- a/lib/build/emailpasswordprebuiltui.js
+++ b/lib/build/emailpasswordprebuiltui.js
@@ -15,12 +15,12 @@ var STGeneralError = require("supertokens-web-js/utils/error");
var button = require("./emailpassword-shared.js");
var authCompWrapper = require("./authCompWrapper.js");
var emailverification = require("./emailverification.js");
-var recipe = require("./emailverification-shared.js");
+var recipe$1 = require("./emailverification-shared.js");
var session = require("./session.js");
var types = require("./multifactorauth-shared.js");
+var recipe = require("./emailpassword-shared3.js");
var STGeneralError$1 = require("supertokens-web-js/lib/build/error");
var constants = require("./emailpassword-shared4.js");
-var recipe$1 = require("./emailpassword-shared3.js");
require("supertokens-web-js");
require("supertokens-web-js/utils/cookieHandler");
require("supertokens-web-js/utils/postSuperTokensInitCallbacks");
@@ -34,6 +34,8 @@ require("./multifactorauth-shared2.js");
require("supertokens-web-js/recipe/multifactorauth");
require("supertokens-web-js/utils/sessionClaimValidatorStore");
require("./recipeModule-shared.js");
+require("./oauth2provider-shared.js");
+require("supertokens-web-js/recipe/oauth2provider");
require("./authRecipe-shared.js");
require("supertokens-web-js/lib/build/normalisedURLPath");
require("./multifactorauth-shared3.js");
@@ -724,6 +726,7 @@ var SignInForm = uiEntry.withOverride("EmailPasswordSignInForm", function EmailP
4 /*yield*/,
props.recipeImplementation.signIn({
formFields: formFields,
+ shouldTryLinkingWithSessionUser: false,
userContext: userContext,
}),
];
@@ -767,14 +770,14 @@ function SignInTheme(props) {
);
}
-function useChildProps$1(recipe$1, error, onError, clearError, userContext, navigate) {
+function useChildProps$1(recipe$2, onAuthSuccess, error, onError, clearError, userContext, navigate) {
var _this = this;
var session$1 = uiEntry.useSessionContext();
var recipeImplementation = React.useMemo(
function () {
- return getModifiedRecipeImplementation$1(recipe$1.webJSRecipe);
+ return getModifiedRecipeImplementation$1(recipe$2.webJSRecipe);
},
- [recipe$1]
+ [recipe$2]
);
var rethrowInRender = genericComponentOverrideContext.useRethrowInRender();
var t = translationContext.useTranslation();
@@ -802,39 +805,38 @@ function useChildProps$1(recipe$1, error, onError, clearError, userContext, navi
case 3:
return [
2 /*return*/,
- types.Session.getInstanceOrThrow()
- .validateGlobalClaimsAndHandleSuccessRedirection(
- {
- action: "SUCCESS",
- createdNewUser: false,
- isNewRecipeUser: false,
- newSessionCreated:
- session$1.loading ||
- !session$1.doesSessionExist ||
- (payloadAfterCall !== undefined &&
- session$1.accessTokenPayload.sessionHandle !==
- payloadAfterCall.sessionHandle),
- recipeId: recipe$1.recipeID,
- },
- recipe$1.recipeID,
- genericComponentOverrideContext.getRedirectToPathFromURL(),
- userContext,
- navigate
- )
- .catch(rethrowInRender),
+ onAuthSuccess({
+ createdNewUser: false,
+ isNewRecipeUser: false,
+ newSessionCreated:
+ session$1.loading ||
+ !session$1.doesSessionExist ||
+ (payloadAfterCall !== undefined &&
+ session$1.accessTokenPayload.sessionHandle !==
+ payloadAfterCall.sessionHandle),
+ recipeId: recipe.EmailPassword.RECIPE_ID,
+ }).catch(rethrowInRender),
];
}
});
});
},
- [recipe$1, userContext, navigate]
+ [recipe$2, userContext, navigate]
);
return React.useMemo(
function () {
var onForgotPasswordClick = function () {
- return recipe$1.redirect({ action: "RESET_PASSWORD" }, navigate, undefined, userContext);
+ return recipe$2.redirect(
+ {
+ action: "RESET_PASSWORD",
+ tenantIdFromQueryParams: genericComponentOverrideContext.getTenantIdFromQueryParams(),
+ },
+ navigate,
+ undefined,
+ userContext
+ );
};
- var signInAndUpFeature = recipe$1.config.signInAndUpFeature;
+ var signInAndUpFeature = recipe$2.config.signInAndUpFeature;
var signInFeature = signInAndUpFeature.signInForm;
var formFields = signInFeature.formFields.map(function (f) {
return f.id !== "password"
@@ -869,7 +871,7 @@ function useChildProps$1(recipe$1, error, onError, clearError, userContext, navi
});
return {
recipeImplementation: recipeImplementation,
- config: recipe$1.config,
+ config: recipe$2.config,
styleFromInit: signInFeature.style,
formFields: formFields,
error: error,
@@ -906,12 +908,14 @@ function useChildProps$1(recipe$1, error, onError, clearError, userContext, navi
_b.label = 2;
case 2:
_b.trys.push([2, 4, , 5]);
- evInstance = recipe.EmailVerification.getInstanceOrThrow();
+ evInstance = recipe$1.EmailVerification.getInstanceOrThrow();
return [
4 /*yield*/,
evInstance.redirect(
{
action: "VERIFY_EMAIL",
+ tenantIdFromQueryParams:
+ genericComponentOverrideContext.getTenantIdFromQueryParams(),
},
navigate,
undefined,
@@ -936,12 +940,13 @@ function useChildProps$1(recipe$1, error, onError, clearError, userContext, navi
userContext: userContext,
};
},
- [recipe$1, error, userContext]
+ [recipe$2, error, userContext]
);
}
var SignInFeature = function (props) {
var childProps = useChildProps$1(
props.recipe,
+ props.onAuthSuccess,
props.error,
props.onError,
props.clearError,
@@ -975,7 +980,52 @@ var SignInFeature = function (props) {
);
};
var getModifiedRecipeImplementation$1 = function (origImpl) {
- return genericComponentOverrideContext.__assign({}, origImpl);
+ return genericComponentOverrideContext.__assign(genericComponentOverrideContext.__assign({}, origImpl), {
+ signIn: function (input) {
+ return genericComponentOverrideContext.__awaiter(this, void 0, void 0, function () {
+ var response;
+ return genericComponentOverrideContext.__generator(this, function (_a) {
+ switch (_a.label) {
+ case 0:
+ return [
+ 4 /*yield*/,
+ origImpl.signIn(
+ genericComponentOverrideContext.__assign(
+ genericComponentOverrideContext.__assign({}, input),
+ { shouldTryLinkingWithSessionUser: false }
+ )
+ ),
+ ];
+ case 1:
+ response = _a.sent();
+ return [2 /*return*/, response];
+ }
+ });
+ });
+ },
+ signUp: function (input) {
+ return genericComponentOverrideContext.__awaiter(this, void 0, void 0, function () {
+ var response;
+ return genericComponentOverrideContext.__generator(this, function (_a) {
+ switch (_a.label) {
+ case 0:
+ return [
+ 4 /*yield*/,
+ origImpl.signUp(
+ genericComponentOverrideContext.__assign(
+ genericComponentOverrideContext.__assign({}, input),
+ { shouldTryLinkingWithSessionUser: false }
+ )
+ ),
+ ];
+ case 1:
+ response = _a.sent();
+ return [2 /*return*/, response];
+ }
+ });
+ });
+ },
+ });
};
var SignUpForm = uiEntry.withOverride("EmailPasswordSignUpForm", function EmailPasswordSignUpForm(props) {
@@ -1016,6 +1066,7 @@ var SignUpForm = uiEntry.withOverride("EmailPasswordSignUpForm", function EmailP
4 /*yield*/,
props.recipeImplementation.signUp({
formFields: formFields,
+ shouldTryLinkingWithSessionUser: false,
userContext: userContext,
}),
];
@@ -1054,14 +1105,14 @@ function SignUpTheme(props) {
);
}
-function useChildProps(recipe$1, error, onError, clearError, userContext, navigate) {
+function useChildProps(recipe, onAuthSuccess, error, onError, clearError, userContext, navigate) {
var _this = this;
var session$1 = uiEntry.useSessionContext();
var recipeImplementation = React.useMemo(
function () {
- return recipe$1 && getModifiedRecipeImplementation(recipe$1.webJSRecipe);
+ return recipe && getModifiedRecipeImplementation(recipe.webJSRecipe);
},
- [recipe$1]
+ [recipe]
);
var rethrowInRender = genericComponentOverrideContext.useRethrowInRender();
var onSignUpSuccess = React.useCallback(
@@ -1088,42 +1139,33 @@ function useChildProps(recipe$1, error, onError, clearError, userContext, naviga
case 3:
return [
2 /*return*/,
- types.Session.getInstanceOrThrow()
- .validateGlobalClaimsAndHandleSuccessRedirection(
- {
- action: "SUCCESS",
- createdNewUser: result.user.loginMethods.length === 1,
- isNewRecipeUser: true,
- newSessionCreated:
- session$1.loading ||
- !session$1.doesSessionExist ||
- (payloadAfterCall !== undefined &&
- session$1.accessTokenPayload.sessionHandle !==
- payloadAfterCall.sessionHandle),
- recipeId: recipe$1.recipeID,
- },
- recipe$1.recipeID,
- genericComponentOverrideContext.getRedirectToPathFromURL(),
- userContext,
- navigate
- )
- .catch(rethrowInRender),
+ onAuthSuccess({
+ createdNewUser: result.user.loginMethods.length === 1,
+ isNewRecipeUser: true,
+ newSessionCreated:
+ session$1.loading ||
+ !session$1.doesSessionExist ||
+ (payloadAfterCall !== undefined &&
+ session$1.accessTokenPayload.sessionHandle !==
+ payloadAfterCall.sessionHandle),
+ recipeId: recipe.recipeID,
+ }).catch(rethrowInRender),
];
}
});
});
},
- [recipe$1, userContext, navigate]
+ [recipe, userContext, navigate]
);
return React.useMemo(
function () {
- var signInAndUpFeature = recipe$1.config.signInAndUpFeature;
+ var signInAndUpFeature = recipe.config.signInAndUpFeature;
var signUpFeature = signInAndUpFeature.signUpForm;
return {
recipeImplementation: recipeImplementation,
- config: recipe$1.config,
+ config: recipe.config,
styleFromInit: signUpFeature.style,
- formFields: getThemeSignUpFeatureFormFields(signUpFeature.formFields, recipe$1, userContext),
+ formFields: getThemeSignUpFeatureFormFields(signUpFeature.formFields, recipe, userContext),
onFetchError: function (err) {
return genericComponentOverrideContext.__awaiter(_this, void 0, void 0, function () {
var invalidClaims, evInstance;
@@ -1155,12 +1197,14 @@ function useChildProps(recipe$1, error, onError, clearError, userContext, naviga
_b.label = 2;
case 2:
_b.trys.push([2, 4, , 5]);
- evInstance = recipe.EmailVerification.getInstanceOrThrow();
+ evInstance = recipe$1.EmailVerification.getInstanceOrThrow();
return [
4 /*yield*/,
evInstance.redirect(
{
action: "VERIFY_EMAIL",
+ tenantIdFromQueryParams:
+ genericComponentOverrideContext.getTenantIdFromQueryParams(),
},
navigate,
undefined,
@@ -1187,7 +1231,7 @@ function useChildProps(recipe$1, error, onError, clearError, userContext, naviga
clearError: clearError,
};
},
- [recipe$1, error, userContext]
+ [recipe, error, userContext]
);
}
var SignUpFeature = function (props) {
@@ -1197,6 +1241,7 @@ var SignUpFeature = function (props) {
}
var childProps = useChildProps(
props.recipe,
+ props.onAuthSuccess,
props.error,
props.onError,
props.clearError,
@@ -1230,7 +1275,52 @@ var SignUpFeature = function (props) {
);
};
var getModifiedRecipeImplementation = function (origImpl) {
- return genericComponentOverrideContext.__assign({}, origImpl);
+ return genericComponentOverrideContext.__assign(genericComponentOverrideContext.__assign({}, origImpl), {
+ signIn: function (input) {
+ return genericComponentOverrideContext.__awaiter(this, void 0, void 0, function () {
+ var response;
+ return genericComponentOverrideContext.__generator(this, function (_a) {
+ switch (_a.label) {
+ case 0:
+ return [
+ 4 /*yield*/,
+ origImpl.signIn(
+ genericComponentOverrideContext.__assign(
+ genericComponentOverrideContext.__assign({}, input),
+ { shouldTryLinkingWithSessionUser: false }
+ )
+ ),
+ ];
+ case 1:
+ response = _a.sent();
+ return [2 /*return*/, response];
+ }
+ });
+ });
+ },
+ signUp: function (input) {
+ return genericComponentOverrideContext.__awaiter(this, void 0, void 0, function () {
+ var response;
+ return genericComponentOverrideContext.__generator(this, function (_a) {
+ switch (_a.label) {
+ case 0:
+ return [
+ 4 /*yield*/,
+ origImpl.signUp(
+ genericComponentOverrideContext.__assign(
+ genericComponentOverrideContext.__assign({}, input),
+ { shouldTryLinkingWithSessionUser: false }
+ )
+ ),
+ ];
+ case 1:
+ response = _a.sent();
+ return [2 /*return*/, response];
+ }
+ });
+ });
+ },
+ });
};
function getThemeSignUpFeatureFormFields(formFields, recipe, userContext) {
var _this = this;
@@ -1322,7 +1412,7 @@ var EmailPasswordPreBuiltUI = /** @class */ (function (_super) {
component: function (props) {
return _this.getFeatureComponent("resetpassword", props, useComponentOverrides);
},
- recipeID: recipe$1.EmailPassword.RECIPE_ID,
+ recipeID: recipe.EmailPassword.RECIPE_ID,
};
}
return features;
@@ -1356,7 +1446,7 @@ var EmailPasswordPreBuiltUI = /** @class */ (function (_super) {
// Static methods
EmailPasswordPreBuiltUI.getInstanceOrInitAndGetInstance = function () {
if (EmailPasswordPreBuiltUI.instance === undefined) {
- var recipeInstance = recipe$1.EmailPassword.getInstanceOrThrow();
+ var recipeInstance = recipe.EmailPassword.getInstanceOrThrow();
EmailPasswordPreBuiltUI.instance = new EmailPasswordPreBuiltUI(recipeInstance);
}
return EmailPasswordPreBuiltUI.instance;
diff --git a/lib/build/emailverification-shared.js b/lib/build/emailverification-shared.js
index e75d4a068..1c7d9189f 100644
--- a/lib/build/emailverification-shared.js
+++ b/lib/build/emailverification-shared.js
@@ -2,7 +2,6 @@
var genericComponentOverrideContext = require("./genericComponentOverrideContext.js");
var EmailVerificationWebJS = require("supertokens-web-js/recipe/emailverification");
-var NormalisedURLPath = require("supertokens-web-js/utils/normalisedURLPath");
var postSuperTokensInitCallbacks = require("supertokens-web-js/utils/postSuperTokensInitCallbacks");
var sessionClaimValidatorStore = require("supertokens-web-js/utils/sessionClaimValidatorStore");
var index = require("./recipeModule-shared.js");
@@ -12,7 +11,6 @@ function _interopDefault(e) {
}
var EmailVerificationWebJS__default = /*#__PURE__*/ _interopDefault(EmailVerificationWebJS);
-var NormalisedURLPath__default = /*#__PURE__*/ _interopDefault(NormalisedURLPath);
var _a = genericComponentOverrideContext.createGenericComponentsOverrideContext(),
useContext = _a[0],
@@ -55,7 +53,14 @@ var EmailVerificationClaimClass = /** @class */ (function (_super) {
}
var recipe = EmailVerification.getInstanceOrThrow();
if (recipe.config.mode === "REQUIRED") {
- return recipe.getRedirectUrl({ action: "VERIFY_EMAIL" }, args.userContext);
+ return recipe.getRedirectUrl(
+ {
+ action: "VERIFY_EMAIL",
+ tenantIdFromQueryParams:
+ genericComponentOverrideContext.getTenantIdFromQueryParams(),
+ },
+ args.userContext
+ );
}
return undefined;
},
@@ -202,20 +207,15 @@ var EmailVerification = /** @class */ (function (_super) {
_this.recipeID = EmailVerification.RECIPE_ID;
_this.getDefaultRedirectionURL = function (context) {
return genericComponentOverrideContext.__awaiter(_this, void 0, void 0, function () {
- var verifyEmailPath;
return genericComponentOverrideContext.__generator(this, function (_a) {
if (context.action === "VERIFY_EMAIL") {
- verifyEmailPath = new NormalisedURLPath__default.default(DEFAULT_VERIFY_EMAIL_PATH);
return [
2 /*return*/,
- ""
- .concat(
- this.config.appInfo.websiteBasePath
- .appendPath(verifyEmailPath)
- .getAsStringDangerous(),
- "?rid="
- )
- .concat(this.config.recipeId),
+ genericComponentOverrideContext.getDefaultRedirectionURLForPath(
+ this.config,
+ DEFAULT_VERIFY_EMAIL_PATH,
+ context
+ ),
];
} else {
return [2 /*return*/, "/"];
diff --git a/lib/build/emailverification-shared2.js b/lib/build/emailverification-shared2.js
index fe4b214a9..bfc3d9cef 100644
--- a/lib/build/emailverification-shared2.js
+++ b/lib/build/emailverification-shared2.js
@@ -6,7 +6,7 @@ var genericComponentOverrideContext = require("./genericComponentOverrideContext
var uiEntry = require("./index2.js");
var styles =
- '/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved.\n *\n * This software is licensed under the Apache License, Version 2.0 (the\n * "License") as published by the Apache Software Foundation.\n *\n * You may not use this file except in compliance with the License. You may\n * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\n[data-supertokens~="container"] {\n --palette-background: 255, 255, 255;\n --palette-inputBackground: 250, 250, 250;\n --palette-inputBorder: 224, 224, 224;\n --palette-primary: 28, 34, 42;\n --palette-primaryBorder: 45, 54, 68;\n --palette-success: 65, 167, 0;\n --palette-successBackground: 217, 255, 191;\n --palette-error: 255, 23, 23;\n --palette-errorBackground: 255, 241, 235;\n --palette-textTitle: 0, 0, 0;\n --palette-textLabel: 0, 0, 0;\n --palette-textInput: 0, 0, 0;\n --palette-textPrimary: 128, 128, 128;\n --palette-textLink: 0, 122, 255;\n --palette-buttonText: 255, 255, 255;\n --palette-textGray: 54, 54, 54;\n --palette-superTokensBrandingBackground: 242, 245, 246;\n --palette-superTokensBrandingText: 173, 189, 196;\n\n --font-size-0: 12px;\n --font-size-1: 14px;\n --font-size-2: 16px;\n --font-size-3: 19px;\n --font-size-4: 24px;\n --font-size-5: 28px;\n}\n\n/*\n * Default styles.\n */\n\n@keyframes slideTop {\n 0% {\n transform: translateY(-5px);\n }\n 100% {\n transform: translateY(0px);\n }\n}\n\n@keyframes swing-in-top-fwd {\n 0% {\n transform: rotateX(-100deg);\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n transform: rotateX(0deg);\n transform-origin: top;\n opacity: 1;\n }\n}\n\n[data-supertokens~="container"] {\n font-family: "Arial", sans-serif;\n margin: 12px auto;\n margin-top: 26px;\n margin-bottom: 26px;\n width: 420px;\n text-align: center;\n border-radius: 8px;\n box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.16);\n background-color: rgb(var(--palette-background));\n}\n\n@media (max-width: 440px) {\n [data-supertokens~="container"] {\n width: 95vw;\n }\n}\n\n[data-supertokens~="row"] {\n margin: 0 auto;\n width: 76%;\n padding-top: 30px;\n padding-bottom: 10px;\n}\n\n[data-supertokens~="superTokensBranding"] {\n display: block;\n margin: 10px auto 0;\n background: rgb(var(--palette-superTokensBrandingBackground));\n color: rgb(var(--palette-superTokensBrandingText));\n text-decoration: none;\n width: -webkit-fit-content;\n width: -moz-fit-content;\n width: fit-content;\n border-radius: 6px 6px 0 0;\n padding: 4px 9px;\n font-weight: 400;\n font-size: var(--font-size-0);\n letter-spacing: 0.4px;\n}\n\n[data-supertokens~="generalError"] {\n background: rgb(var(--palette-errorBackground));\n padding-top: 10px;\n padding-bottom: 10px;\n margin-bottom: 10px;\n margin-top: 24px;\n padding-left: 18px;\n padding-right: 18px;\n letter-spacing: 0.2px;\n font-size: var(--font-size-1);\n border-radius: 8px;\n color: rgb(var(--palette-error));\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n word-wrap: break-word;\n}\n\n[data-supertokens~="headerTitle"] {\n font-size: var(--font-size-4);\n line-height: 27.6px;\n letter-spacing: 0.58px;\n font-weight: 700;\n margin-bottom: 20px;\n color: rgb(var(--palette-textTitle));\n}\n\n[data-supertokens~="headerSubtitle"] {\n font-weight: 400;\n color: rgb(var(--palette-textGray));\n margin-bottom: 21px;\n}\n\n[data-supertokens~="headerSubtitle"][data-supertokens~="secondaryText"] {\n color: rgb(var(--palette-textGray));\n font-weight: 400;\n}\n\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] {\n max-width: 300px;\n margin-top: 10px;\n}\n\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] a {\n line-height: 21px;\n}\n\n/* TODO: split the link style into separate things*/\n\n/* We add this before primary and secondary text, because if they are applied to the same element the other ones take priority */\n\n[data-supertokens~="link"] {\n padding-left: 3px;\n padding-right: 3px;\n color: rgb(var(--palette-textLink));\n font-size: var(--font-size-1);\n cursor: pointer;\n letter-spacing: 0.16px;\n line-height: 26px;\n}\n\n[data-supertokens~="primaryText"] {\n font-size: var(--font-size-2);\n font-weight: 400;\n letter-spacing: 0.4px;\n line-height: 21px;\n color: rgb(var(--palette-textLabel));\n}\n\n[data-supertokens~="secondaryText"] {\n font-size: var(--font-size-1);\n font-weight: 400;\n letter-spacing: 0.4px;\n color: rgb(var(--palette-textPrimary));\n}\n\n[data-supertokens~="secondaryText"] strong {\n font-weight: 600;\n}\n\n[data-supertokens~="divider"] {\n margin-top: 1.5em;\n margin-bottom: 1.5em;\n border-bottom: 0.3px solid #dddddd;\n align-items: center;\n padding-bottom: 5px;\n flex: 3 3;\n}\n\n[data-supertokens~="headerTinyTitle"] {\n margin-top: 24px;\n font-size: var(--font-size-5);\n letter-spacing: 1.1px;\n font-weight: 700;\n line-height: 28px;\n}\n\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n}\n\n[data-supertokens~="secondaryLinkWithArrow"]:hover {\n position: relative;\n left: 2px;\n word-spacing: 4px;\n}\n\n[data-supertokens~="generalSuccess"] {\n color: rgb(var(--palette-success));\n font-size: var(--font-size-1);\n background: rgb(var(--palette-successBackground));\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n padding: 9px 15px 9px 15px;\n border-radius: 6px;\n display: inline-block;\n}\n\n[data-supertokens~="spinner"] {\n width: 80px;\n height: auto;\n padding-top: 20px;\n padding-bottom: 40px;\n margin: 0 auto;\n}\n\n[data-supertokens~="error"] {\n color: rgb(var(--palette-error));\n}\n\n[data-supertokens~="linkButton"] {\n font-family: "Arial", sans-serif;\n background-color: transparent;\n border: 0;\n}\n\n[data-supertokens~="secondaryLinkWithLeftArrow"] {\n color: rgb(var(--palette-textGray));\n font-weight: 400;\n margin-top: 10px;\n margin-bottom: 40px;\n cursor: pointer;\n}\n\n[data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n margin-right: 0.3em;\n}\n\n[data-supertokens~="secondaryLinkWithLeftArrow"]:hover svg {\n position: relative;\n left: -4px;\n}\n\n[data-supertokens~="button"] {\n font-family: "Arial", sans-serif;\n background-color: rgb(var(--palette-primary));\n color: rgb(var(--palette-buttonText));\n width: 100%;\n height: 34px;\n font-weight: 600;\n border-width: 1px;\n border-style: solid;\n border-radius: 6px;\n border-color: rgb(var(--palette-primaryBorder));\n background-position: center;\n transition: all 0.4s;\n background-size: 12000%;\n cursor: pointer;\n}\n\n[data-supertokens~="button"]:disabled {\n border: none;\n cursor: no-drop;\n}\n\n[data-supertokens~="button"]:active {\n outline: none;\n transition: all 0s;\n background-size: 100%;\n filter: brightness(0.85);\n}\n\n[data-supertokens~="button"]:focus {\n outline: none;\n}\n\n[data-supertokens~="backButtonCommon"] {\n width: 16px;\n height: 13px;\n}\n\n[data-supertokens~="backButton"] {\n cursor: pointer;\n border: none;\n background-color: transparent;\n padding: 0px;\n}\n\n[data-supertokens~="backButtonPlaceholder"] {\n display: block;\n}\n\n[data-supertokens~="delayedRender"] {\n animation-duration: 0.1s;\n animation-name: animate-fade;\n animation-delay: 0.2s;\n animation-fill-mode: backwards;\n}\n\n@keyframes animate-fade {\n 0% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n}\n\n[data-supertokens~="footerLinkGroupVert"] {\n display: flex;\n flex-direction: column;\n margin-top: 10px;\n gap: 24px;\n}\n\n[data-supertokens~="footerLinkGroupVert"] > div {\n cursor: pointer;\n margin: 0;\n}\n\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryText"] {\n font-weight: 400;\n}\n\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n font-weight: 400;\n position: relative;\n left: -6px; /* half the width of the left arrow */\n}\n\n@media (max-width: 360px) {\n [data-supertokens~="footerLinkGroupVert"] {\n flex-direction: column;\n }\n [data-supertokens~="footerLinkGroupVert"] > div {\n margin: 0 auto;\n }\n}\n\n[data-supertokens~="footerLinkGroupVert"] div:only-child {\n margin-left: auto;\n margin-right: auto;\n margin-top: 14px;\n}\n\n[data-supertokens~="withBackButton"] {\n position: relative;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n[data-supertokens~="dividerWithOr"] {\n padding-top: 5px;\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n color: rgb(var(--palette-textPrimary));\n}\n\n[data-supertokens~="dividerText"] {\n flex: 1 1;\n font-weight: 400;\n font-size: var(--font-size-1);\n}\n\n[data-supertokens~="formLabelWithLinkWrapper"] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n[data-supertokens~="formLabelLinkBtn"] {\n width: auto;\n margin-top: 0;\n line-height: 24px;\n font-size: var(--font-size-0);\n}\n\n[data-supertokens~="formLabelLinkBtn"]:hover {\n text-decoration: underline;\n}\n\n[data-supertokens~="formLabelLinkBtn"]:disabled {\n color: rgb(var(--palette-textPrimary));\n cursor: default;\n text-decoration: none;\n}\n\n[data-supertokens~="authComponentList"] {\n padding-bottom: 20px;\n}\n\n[data-supertokens~="buttonWithArrow"] {\n border-radius: 6px;\n border: 1px solid #d0d5dd;\n width: 100%;\n color: rgb(var(--palette-textGray));\n display: flex;\n justify-content: center;\n align-items: center;\n gap: 5px;\n margin: 24px 0;\n min-height: 48px;\n cursor: pointer;\n}\n\n[data-supertokens~="buttonWithArrow"]:hover {\n background-color: rgb(var(--palette-inputBackground));\n}\n\n[data-supertokens~="buttonWithArrow"] [data-supertokens~="secondaryText"] {\n font-weight: 700;\n font-size: var(--font-size-2);\n color: rgb(var(--palette-textGray));\n margin: 0;\n}\n\n[data-supertokens~="buttonWithArrow"]:hover [data-supertokens~="secondaryLinkWithRightArrow"] ~ svg {\n position: relative;\n left: 2px;\n}\n\n[data-supertokens~="buttonWithArrow"]:hover [data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n position: relative;\n left: -2px;\n}\n\n[data-supertokens~="buttonWithArrow"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n display: flex;\n align-items: center;\n}\n\n[data-supertokens~="inputContainer"] {\n margin-top: 6px;\n}\n\n[data-supertokens~="inputWrapper"] {\n box-sizing: border-box;\n width: 100%;\n display: flex;\n align-items: center;\n background-color: rgb(var(--palette-inputBackground));\n height: 34px;\n border-radius: 6px;\n border: 1px solid rgb(var(--palette-inputBorder));\n}\n\n[data-supertokens~="inputWrapper"][focus-within] {\n background-color: rgba(var(--palette-inputBackground), 0.25);\n border: 1px solid rgb(var(--palette-primary));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-primary), 0.25);\n outline: none;\n}\n\n[data-supertokens~="inputWrapper"]:focus-within {\n background-color: rgba(var(--palette-inputBackground), 0.25);\n border: 1px solid rgb(var(--palette-primary));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-primary), 0.25);\n outline: none;\n}\n\n[data-supertokens~="inputError"] {\n border: 1px solid rgb(var(--palette-error));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-error), 0.25);\n outline: none;\n}\n\n[data-supertokens~="inputError"][focus-within] {\n border: 1px solid rgb(var(--palette-error));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-error), 0.25);\n outline: none;\n}\n\n[data-supertokens~="inputError"]:focus-within {\n border: 1px solid rgb(var(--palette-error));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-error), 0.25);\n outline: none;\n}\n\n[data-supertokens~="input"] {\n box-sizing: border-box;\n padding-left: 15px;\n filter: none;\n color: rgb(var(--palette-textInput));\n background-color: transparent;\n border-radius: 6px;\n font-size: var(--font-size-1);\n border: none;\n padding-right: 25px;\n letter-spacing: 1.2px;\n flex: 9 1 75%;\n width: 75%;\n height: 32px;\n}\n\n[data-supertokens~="input"]:focus {\n border: none;\n outline: none;\n}\n\n[data-supertokens~="input"]:-webkit-autofill,\n[data-supertokens~="input"]:-webkit-autofill:hover,\n[data-supertokens~="input"]:-webkit-autofill:focus,\n[data-supertokens~="input"]:-webkit-autofill:active {\n -webkit-text-fill-color: rgb(var(--palette-textInput));\n box-shadow: 0 0 0 30px rgb(var(--palette-inputBackground)) inset;\n}\n\n[data-supertokens~="inputAdornment"] {\n justify-content: center;\n margin-right: 5px;\n}\n\n[data-supertokens~="showPassword"] {\n cursor: pointer;\n}\n\n[data-supertokens~="enterEmailSuccessMessage"] {\n margin-top: 15px;\n margin-bottom: 15px;\n word-break: break-word;\n}\n\n[data-supertokens~="submitNewPasswordSuccessMessage"] {\n margin-top: 15px;\n margin-bottom: 15px;\n}\n\n[data-supertokens~="inputErrorMessage"] {\n padding-top: 5px;\n padding-bottom: 5px;\n color: rgb(var(--palette-error));\n line-height: 24px;\n font-weight: 400;\n font-size: var(--font-size-1);\n text-align: left;\n animation: slideTop 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;\n max-width: 330px;\n}\n\n@media (max-width: 440px) {\n [data-supertokens~="inputErrorMessage"] {\n max-width: 250px;\n }\n}\n\n[data-supertokens~="inputErrorSymbol"] {\n margin-right: 5px;\n top: 1px;\n position: relative;\n left: 2px;\n}\n\n[data-supertokens~="label"] {\n text-align: left;\n font-weight: 700;\n font-size: var(--font-size-0);\n line-height: 24px;\n color: rgb(var(--palette-textLabel));\n}\n\n[data-supertokens~="formRow"] {\n display: flex;\n flex-direction: column;\n padding-top: 0px;\n padding-bottom: 20px;\n}\n\n[data-supertokens~="formRow"][data-supertokens~="hasError"] {\n padding-bottom: 0;\n}\n\n[data-supertokens~="formRow"]:last-child {\n padding-bottom: 0;\n}\n\n[data-supertokens~="sendVerifyEmailIcon"] {\n margin-top: 11px;\n}\n\n[data-supertokens~="primaryText"][data-supertokens~="sendVerifyEmailText"] {\n text-align: center;\n letter-spacing: 0.8px;\n color: rgb(var(--palette-textPrimary));\n}\n\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n font-weight: 700;\n}\n\n[data-supertokens~="sendVerifyEmailResend"] {\n margin-top: 13px;\n font-weight: 400;\n}\n\n[data-supertokens~="sendVerifyEmailResend"]:hover {\n text-decoration: underline;\n}\n\n[data-supertokens~="noFormRow"] {\n padding-bottom: 25px;\n}\n\n[data-supertokens~="emailVerificationButtonWrapper"] {\n padding-top: 25px;\n max-width: 96px;\n margin: 0 auto;\n}\n\n[data-supertokens~="resendEmailLink"] {\n display: inline-block;\n}\n\n[data-supertokens~="resetPasswordEmailForm"] {\n padding-bottom: 20px;\n}\n\n[data-supertokens~="resetPasswordPasswordForm"] {\n padding-bottom: 20px;\n}\n';
+ '/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved.\n *\n * This software is licensed under the Apache License, Version 2.0 (the\n * "License") as published by the Apache Software Foundation.\n *\n * You may not use this file except in compliance with the License. You may\n * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\n[data-supertokens~="container"] {\n --palette-background: 255, 255, 255;\n --palette-inputBackground: 250, 250, 250;\n --palette-inputBorder: 224, 224, 224;\n --palette-primary: 28, 34, 42;\n --palette-primaryBorder: 45, 54, 68;\n --palette-success: 65, 167, 0;\n --palette-successBackground: 217, 255, 191;\n --palette-error: 255, 23, 23;\n --palette-errorBackground: 255, 241, 235;\n --palette-textTitle: 0, 0, 0;\n --palette-textLabel: 0, 0, 0;\n --palette-textInput: 0, 0, 0;\n --palette-textPrimary: 128, 128, 128;\n --palette-textLink: 0, 122, 255;\n --palette-buttonText: 255, 255, 255;\n --palette-textGray: 54, 54, 54;\n --palette-superTokensBrandingBackground: 242, 245, 246;\n --palette-superTokensBrandingText: 173, 189, 196;\n\n --font-size-0: 12px;\n --font-size-1: 14px;\n --font-size-2: 16px;\n --font-size-3: 19px;\n --font-size-4: 24px;\n --font-size-5: 28px;\n}\n\n/*\n * Default styles.\n */\n\n@keyframes slideTop {\n 0% {\n transform: translateY(-5px);\n }\n 100% {\n transform: translateY(0px);\n }\n}\n\n@keyframes swing-in-top-fwd {\n 0% {\n transform: rotateX(-100deg);\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n transform: rotateX(0deg);\n transform-origin: top;\n opacity: 1;\n }\n}\n\n[data-supertokens~="container"] {\n font-family: "Arial", sans-serif;\n margin: 12px auto;\n margin-top: 26px;\n margin-bottom: 26px;\n width: 420px;\n text-align: center;\n border-radius: 8px;\n box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.16);\n background-color: rgb(var(--palette-background));\n}\n\n@media (max-width: 440px) {\n [data-supertokens~="container"] {\n width: 95vw;\n }\n}\n\n[data-supertokens~="row"] {\n margin: 0 auto;\n width: 76%;\n padding-top: 30px;\n padding-bottom: 10px;\n}\n\n[data-supertokens~="superTokensBranding"] {\n display: block;\n margin: 10px auto 0;\n background: rgb(var(--palette-superTokensBrandingBackground));\n color: rgb(var(--palette-superTokensBrandingText));\n text-decoration: none;\n width: -webkit-fit-content;\n width: -moz-fit-content;\n width: fit-content;\n border-radius: 6px 6px 0 0;\n padding: 4px 9px;\n font-weight: 400;\n font-size: var(--font-size-0);\n letter-spacing: 0.4px;\n}\n\n[data-supertokens~="generalError"] {\n background: rgb(var(--palette-errorBackground));\n padding-top: 10px;\n padding-bottom: 10px;\n margin-bottom: 10px;\n margin-top: 24px;\n padding-left: 18px;\n padding-right: 18px;\n letter-spacing: 0.2px;\n font-size: var(--font-size-1);\n border-radius: 8px;\n color: rgb(var(--palette-error));\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n word-wrap: break-word;\n}\n\n[data-supertokens~="headerTitle"] {\n font-size: var(--font-size-4);\n line-height: 27.6px;\n letter-spacing: 0.58px;\n font-weight: 700;\n margin-bottom: 20px;\n color: rgb(var(--palette-textTitle));\n}\n\n[data-supertokens~="headerSubtitle"] {\n font-weight: 400;\n color: rgb(var(--palette-textGray));\n margin-bottom: 21px;\n}\n\n[data-supertokens~="headerSubtitle"][data-supertokens~="secondaryText"] {\n color: rgb(var(--palette-textGray));\n font-weight: 400;\n}\n\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] {\n max-width: 300px;\n margin-top: 10px;\n}\n\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] a {\n line-height: 21px;\n}\n\n/* TODO: split the link style into separate things*/\n\n/* We add this before primary and secondary text, because if they are applied to the same element the other ones take priority */\n\n[data-supertokens~="link"] {\n padding-left: 3px;\n padding-right: 3px;\n color: rgb(var(--palette-textLink));\n font-size: var(--font-size-1);\n cursor: pointer;\n letter-spacing: 0.16px;\n line-height: 26px;\n}\n\n[data-supertokens~="primaryText"] {\n font-size: var(--font-size-2);\n font-weight: 400;\n letter-spacing: 0.4px;\n line-height: 21px;\n color: rgb(var(--palette-textLabel));\n}\n\n[data-supertokens~="secondaryText"] {\n font-size: var(--font-size-1);\n font-weight: 400;\n letter-spacing: 0.4px;\n color: rgb(var(--palette-textPrimary));\n}\n\n[data-supertokens~="secondaryText"] strong {\n font-weight: 600;\n}\n\n[data-supertokens~="divider"] {\n margin-top: 1.5em;\n margin-bottom: 1.5em;\n border-bottom: 0.3px solid #dddddd;\n align-items: center;\n padding-bottom: 5px;\n flex: 3 3;\n}\n\n[data-supertokens~="headerTinyTitle"] {\n margin-top: 24px;\n font-size: var(--font-size-5);\n letter-spacing: 1.1px;\n font-weight: 700;\n line-height: 28px;\n}\n\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n}\n\n[data-supertokens~="secondaryLinkWithArrow"]:hover {\n position: relative;\n left: 2px;\n word-spacing: 4px;\n}\n\n[data-supertokens~="generalSuccess"] {\n color: rgb(var(--palette-success));\n font-size: var(--font-size-1);\n background: rgb(var(--palette-successBackground));\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n padding: 9px 15px 9px 15px;\n border-radius: 6px;\n display: inline-block;\n}\n\n[data-supertokens~="spinner"] {\n width: 80px;\n height: auto;\n padding-top: 20px;\n padding-bottom: 40px;\n margin: 0 auto;\n}\n\n[data-supertokens~="error"] {\n color: rgb(var(--palette-error));\n}\n\n[data-supertokens~="linkButton"] {\n font-family: "Arial", sans-serif;\n background-color: transparent;\n border: 0;\n}\n\n[data-supertokens~="secondaryLinkWithLeftArrow"] {\n color: rgb(var(--palette-textGray));\n font-weight: 400;\n margin-top: 10px;\n margin-bottom: 40px;\n cursor: pointer;\n}\n\n[data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n margin-right: 0.3em;\n}\n\n[data-supertokens~="secondaryLinkWithLeftArrow"]:hover svg {\n position: relative;\n left: -4px;\n}\n\n[data-supertokens~="button"] {\n font-family: "Arial", sans-serif;\n background-color: rgb(var(--palette-primary));\n color: rgb(var(--palette-buttonText));\n width: 100%;\n height: 34px;\n font-weight: 600;\n border-width: 1px;\n border-style: solid;\n border-radius: 6px;\n border-color: rgb(var(--palette-primaryBorder));\n background-position: center;\n transition: all 0.4s;\n background-size: 12000%;\n cursor: pointer;\n}\n\n[data-supertokens~="button"]:disabled {\n border: none;\n cursor: no-drop;\n}\n\n[data-supertokens~="button"]:active {\n outline: none;\n transition: all 0s;\n background-size: 100%;\n filter: brightness(0.85);\n}\n\n[data-supertokens~="button"]:focus {\n outline: none;\n}\n\n[data-supertokens~="backButtonCommon"] {\n width: 16px;\n height: 13px;\n}\n\n[data-supertokens~="backButton"] {\n cursor: pointer;\n border: none;\n background-color: transparent;\n padding: 0px;\n}\n\n[data-supertokens~="backButtonPlaceholder"] {\n display: block;\n}\n\n[data-supertokens~="delayedRender"] {\n animation-duration: 0.1s;\n animation-name: animate-fade;\n animation-delay: 0.2s;\n animation-fill-mode: backwards;\n}\n\n@keyframes animate-fade {\n 0% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n}\n\n[data-supertokens~="footerLinkGroupVert"] {\n display: flex;\n flex-direction: column;\n margin-top: 10px;\n gap: 24px;\n}\n\n[data-supertokens~="footerLinkGroupVert"] > div {\n cursor: pointer;\n margin: 0;\n}\n\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryText"] {\n font-weight: 400;\n}\n\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n font-weight: 400;\n position: relative;\n left: -6px; /* half the width of the left arrow */\n}\n\n@media (max-width: 360px) {\n [data-supertokens~="footerLinkGroupVert"] {\n flex-direction: column;\n }\n [data-supertokens~="footerLinkGroupVert"] > div {\n margin: 0 auto;\n }\n}\n\n[data-supertokens~="footerLinkGroupVert"] div:only-child {\n margin-left: auto;\n margin-right: auto;\n margin-top: 14px;\n}\n\n[data-supertokens~="withBackButton"] {\n position: relative;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n[data-supertokens~="dividerWithOr"] {\n padding-top: 5px;\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n color: rgb(var(--palette-textPrimary));\n}\n\n[data-supertokens~="dividerText"] {\n flex: 1 1;\n font-weight: 400;\n font-size: var(--font-size-1);\n}\n\n[data-supertokens~="formLabelWithLinkWrapper"] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n[data-supertokens~="formLabelLinkBtn"] {\n width: auto;\n margin-top: 0;\n line-height: 24px;\n font-size: var(--font-size-0);\n}\n\n[data-supertokens~="formLabelLinkBtn"]:hover {\n text-decoration: underline;\n}\n\n[data-supertokens~="formLabelLinkBtn"]:disabled {\n color: rgb(var(--palette-textPrimary));\n cursor: default;\n text-decoration: none;\n}\n\n[data-supertokens~="authComponentList"] {\n padding-bottom: 20px;\n}\n\n[data-supertokens~="authPageTitleOAuthClient"] {\n color: rgb(var(--palette-textGray));\n font-size: var(--font-size-1);\n font-weight: 400;\n margin: 10px 0 25px;\n}\n\n[data-supertokens~="authPageTitleOAuthClientUrl"] {\n text-decoration: none;\n}\n\n[data-supertokens~="authPageTitleOAuthClientLogo"] {\n width: 44px;\n height: 44px;\n margin-bottom: 10px;\n}\n\n[data-supertokens~="authPageTitleOAuthClient"] [data-supertokens~="authPageTitleOAuthClientName"] {\n color: rgb(var(--palette-textTitle));\n}\n\n[data-supertokens~="buttonWithArrow"] {\n border-radius: 6px;\n border: 1px solid #d0d5dd;\n width: 100%;\n color: rgb(var(--palette-textGray));\n display: flex;\n justify-content: center;\n align-items: center;\n gap: 5px;\n margin: 24px 0;\n min-height: 48px;\n cursor: pointer;\n}\n\n[data-supertokens~="buttonWithArrow"]:hover {\n background-color: rgb(var(--palette-inputBackground));\n}\n\n[data-supertokens~="buttonWithArrow"] [data-supertokens~="secondaryText"] {\n font-weight: 700;\n font-size: var(--font-size-2);\n color: rgb(var(--palette-textGray));\n margin: 0;\n}\n\n[data-supertokens~="buttonWithArrow"]:hover [data-supertokens~="secondaryLinkWithRightArrow"] ~ svg {\n position: relative;\n left: 2px;\n}\n\n[data-supertokens~="buttonWithArrow"]:hover [data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n position: relative;\n left: -2px;\n}\n\n[data-supertokens~="buttonWithArrow"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n display: flex;\n align-items: center;\n}\n\n[data-supertokens~="inputContainer"] {\n margin-top: 6px;\n}\n\n[data-supertokens~="inputWrapper"] {\n box-sizing: border-box;\n width: 100%;\n display: flex;\n align-items: center;\n background-color: rgb(var(--palette-inputBackground));\n height: 34px;\n border-radius: 6px;\n border: 1px solid rgb(var(--palette-inputBorder));\n}\n\n[data-supertokens~="inputWrapper"][focus-within] {\n background-color: rgba(var(--palette-inputBackground), 0.25);\n border: 1px solid rgb(var(--palette-primary));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-primary), 0.25);\n outline: none;\n}\n\n[data-supertokens~="inputWrapper"]:focus-within {\n background-color: rgba(var(--palette-inputBackground), 0.25);\n border: 1px solid rgb(var(--palette-primary));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-primary), 0.25);\n outline: none;\n}\n\n[data-supertokens~="inputError"] {\n border: 1px solid rgb(var(--palette-error));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-error), 0.25);\n outline: none;\n}\n\n[data-supertokens~="inputError"][focus-within] {\n border: 1px solid rgb(var(--palette-error));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-error), 0.25);\n outline: none;\n}\n\n[data-supertokens~="inputError"]:focus-within {\n border: 1px solid rgb(var(--palette-error));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-error), 0.25);\n outline: none;\n}\n\n[data-supertokens~="input"] {\n box-sizing: border-box;\n padding-left: 15px;\n filter: none;\n color: rgb(var(--palette-textInput));\n background-color: transparent;\n border-radius: 6px;\n font-size: var(--font-size-1);\n border: none;\n padding-right: 25px;\n letter-spacing: 1.2px;\n flex: 9 1 75%;\n width: 75%;\n height: 32px;\n}\n\n[data-supertokens~="input"]:focus {\n border: none;\n outline: none;\n}\n\n[data-supertokens~="input"]:-webkit-autofill,\n[data-supertokens~="input"]:-webkit-autofill:hover,\n[data-supertokens~="input"]:-webkit-autofill:focus,\n[data-supertokens~="input"]:-webkit-autofill:active {\n -webkit-text-fill-color: rgb(var(--palette-textInput));\n box-shadow: 0 0 0 30px rgb(var(--palette-inputBackground)) inset;\n}\n\n[data-supertokens~="inputAdornment"] {\n justify-content: center;\n margin-right: 5px;\n}\n\n[data-supertokens~="showPassword"] {\n cursor: pointer;\n}\n\n[data-supertokens~="enterEmailSuccessMessage"] {\n margin-top: 15px;\n margin-bottom: 15px;\n word-break: break-word;\n}\n\n[data-supertokens~="submitNewPasswordSuccessMessage"] {\n margin-top: 15px;\n margin-bottom: 15px;\n}\n\n[data-supertokens~="inputErrorMessage"] {\n padding-top: 5px;\n padding-bottom: 5px;\n color: rgb(var(--palette-error));\n line-height: 24px;\n font-weight: 400;\n font-size: var(--font-size-1);\n text-align: left;\n animation: slideTop 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;\n max-width: 330px;\n}\n\n@media (max-width: 440px) {\n [data-supertokens~="inputErrorMessage"] {\n max-width: 250px;\n }\n}\n\n[data-supertokens~="inputErrorSymbol"] {\n margin-right: 5px;\n top: 1px;\n position: relative;\n left: 2px;\n}\n\n[data-supertokens~="label"] {\n text-align: left;\n font-weight: 700;\n font-size: var(--font-size-0);\n line-height: 24px;\n color: rgb(var(--palette-textLabel));\n}\n\n[data-supertokens~="formRow"] {\n display: flex;\n flex-direction: column;\n padding-top: 0px;\n padding-bottom: 20px;\n}\n\n[data-supertokens~="formRow"][data-supertokens~="hasError"] {\n padding-bottom: 0;\n}\n\n[data-supertokens~="formRow"]:last-child {\n padding-bottom: 0;\n}\n\n[data-supertokens~="sendVerifyEmailIcon"] {\n margin-top: 11px;\n}\n\n[data-supertokens~="primaryText"][data-supertokens~="sendVerifyEmailText"] {\n text-align: center;\n letter-spacing: 0.8px;\n color: rgb(var(--palette-textPrimary));\n}\n\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n font-weight: 700;\n}\n\n[data-supertokens~="sendVerifyEmailResend"] {\n margin-top: 13px;\n font-weight: 400;\n}\n\n[data-supertokens~="sendVerifyEmailResend"]:hover {\n text-decoration: underline;\n}\n\n[data-supertokens~="noFormRow"] {\n padding-bottom: 25px;\n}\n\n[data-supertokens~="emailVerificationButtonWrapper"] {\n padding-top: 25px;\n max-width: 96px;\n margin: 0 auto;\n}\n\n[data-supertokens~="resendEmailLink"] {\n display: inline-block;\n}\n\n[data-supertokens~="resetPasswordEmailForm"] {\n padding-bottom: 20px;\n}\n\n[data-supertokens~="resetPasswordPasswordForm"] {\n padding-bottom: 20px;\n}\n';
var ThemeBase = function (_a) {
var children = _a.children,
diff --git a/lib/build/emailverificationprebuiltui.js b/lib/build/emailverificationprebuiltui.js
index c52942f44..abfc568bc 100644
--- a/lib/build/emailverificationprebuiltui.js
+++ b/lib/build/emailverificationprebuiltui.js
@@ -26,6 +26,8 @@ require("./multifactorauth-shared2.js");
require("supertokens-web-js/recipe/multifactorauth");
require("supertokens-web-js/utils/sessionClaimValidatorStore");
require("./recipeModule-shared.js");
+require("./oauth2provider-shared.js");
+require("supertokens-web-js/recipe/oauth2provider");
require("./authRecipe-shared.js");
require("supertokens-web-js/lib/build/normalisedURLPath");
require("supertokens-web-js/recipe/session");
diff --git a/lib/build/genericComponentOverrideContext.js b/lib/build/genericComponentOverrideContext.js
index 6ff313470..9f8c18ad7 100644
--- a/lib/build/genericComponentOverrideContext.js
+++ b/lib/build/genericComponentOverrideContext.js
@@ -245,6 +245,7 @@ typeof SuppressedError === "function"
* Consts.
*/
var RECIPE_ID_QUERY_PARAM = "rid";
+var TENANT_ID_QUERY_PARAM = "tenantId";
var DEFAULT_API_BASE_PATH = "/auth";
var DEFAULT_WEBSITE_BASE_PATH = "/auth";
var ST_ROOT_ID = "supertokens-root";
@@ -265,7 +266,7 @@ var SSR_ERROR =
* License for the specific language governing permissions and limitations
* under the License.
*/
-var package_version = "0.47.1";
+var package_version = "0.49.0";
/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved.
*
@@ -389,6 +390,32 @@ function getRedirectToPathFromURL() {
}
}
}
+function getTenantIdFromQueryParams() {
+ var _a;
+ return (_a = getQueryParams(TENANT_ID_QUERY_PARAM)) !== null && _a !== void 0 ? _a : undefined;
+}
+function getDefaultRedirectionURLForPath(config, defaultPath, context, extraQueryParams) {
+ var redirectPath = config.appInfo.websiteBasePath
+ .appendPath(new NormalisedURLPath__default.default(defaultPath))
+ .getAsStringDangerous();
+ var queryParams = new URLSearchParams();
+ if (context.tenantIdFromQueryParams !== undefined) {
+ queryParams.set(TENANT_ID_QUERY_PARAM, context.tenantIdFromQueryParams);
+ }
+ if (extraQueryParams !== undefined) {
+ Object.entries(extraQueryParams).forEach(function (_a) {
+ var key = _a[0],
+ value = _a[1];
+ if (value !== undefined) {
+ queryParams.set(key, value);
+ }
+ });
+ }
+ if (queryParams.toString() !== "") {
+ return "".concat(redirectPath, "?").concat(queryParams.toString());
+ }
+ return redirectPath;
+}
/*
* isTest
*/
@@ -1220,6 +1247,7 @@ var SuperTokens = /** @class */ (function () {
{
action: "TO_AUTH",
showSignIn: options.show === "signin",
+ tenantIdFromQueryParams: getTenantIdFromQueryParams(),
},
options.userContext
),
@@ -1359,22 +1387,33 @@ var SuperTokens = /** @class */ (function () {
SuperTokens.prototype.getRedirectUrl = function (context, userContext) {
var _a;
return __awaiter(this, void 0, void 0, function () {
- var userRes, redirectUrl;
- return __generator(this, function (_b) {
- switch (_b.label) {
+ var userRes, redirectUrl, basePath;
+ var _b;
+ return __generator(this, function (_c) {
+ switch (_c.label) {
case 0:
if (!this.userGetRedirectionURL) return [3 /*break*/, 2];
return [4 /*yield*/, this.userGetRedirectionURL(context, userContext)];
case 1:
- userRes = _b.sent();
+ userRes = _c.sent();
if (userRes !== undefined) {
return [2 /*return*/, userRes];
}
- _b.label = 2;
+ _c.label = 2;
case 2:
if (context.action === "TO_AUTH") {
redirectUrl = this.appInfo.websiteBasePath.getAsStringDangerous();
- return [2 /*return*/, appendTrailingSlashToURL(redirectUrl)];
+ basePath = appendTrailingSlashToURL(redirectUrl);
+ if (context.tenantIdFromQueryParams) {
+ return [
+ 2 /*return*/,
+ appendQueryParamsToURL(
+ basePath,
+ ((_b = {}), (_b[TENANT_ID_QUERY_PARAM] = context.tenantIdFromQueryParams), _b)
+ ),
+ ];
+ }
+ return [2 /*return*/, basePath];
} else if (context.action === "SUCCESS") {
return [2 /*return*/, (_a = context.redirectToPath) !== null && _a !== void 0 ? _a : "/"];
}
@@ -1450,10 +1489,12 @@ exports.createGenericComponentsOverrideContext = createGenericComponentsOverride
exports.getCurrentLanguageFromCookie = getCurrentLanguageFromCookie;
exports.getCurrentNormalisedUrlPath = getCurrentNormalisedUrlPath;
exports.getCurrentNormalisedUrlPathWithQueryParamsAndFragments = getCurrentNormalisedUrlPathWithQueryParamsAndFragments;
+exports.getDefaultRedirectionURLForPath = getDefaultRedirectionURLForPath;
exports.getLocalStorage = getLocalStorage;
exports.getNormalisedUserContext = getNormalisedUserContext;
exports.getQueryParams = getQueryParams;
exports.getRedirectToPathFromURL = getRedirectToPathFromURL;
+exports.getTenantIdFromQueryParams = getTenantIdFromQueryParams;
exports.getURLHash = getURLHash;
exports.isTest = isTest;
exports.logDebugMessage = logDebugMessage;
diff --git a/lib/build/index.js b/lib/build/index.js
index 3df5aed90..b2a26c6c8 100644
--- a/lib/build/index.js
+++ b/lib/build/index.js
@@ -23,6 +23,8 @@ require("supertokens-web-js/utils/sessionClaimValidatorStore");
require("./recipeModule-shared.js");
require("./multifactorauth-shared.js");
require("supertokens-web-js/recipe/session");
+require("./oauth2provider-shared.js");
+require("supertokens-web-js/recipe/oauth2provider");
require("./authRecipe-shared.js");
require("supertokens-web-js/lib/build/normalisedURLPath");
diff --git a/lib/build/index2.js b/lib/build/index2.js
index bf0faa82a..bc16a1368 100644
--- a/lib/build/index2.js
+++ b/lib/build/index2.js
@@ -8,8 +8,9 @@ var translationContext = require("./translationContext.js");
var windowHandler = require("supertokens-web-js/utils/windowHandler");
var reactDom = require("react-dom");
var componentOverrideContext = require("./multitenancy-shared.js");
-var recipe = require("./multifactorauth-shared2.js");
+var recipe$1 = require("./multifactorauth-shared2.js");
var types = require("./multifactorauth-shared.js");
+var recipe = require("./oauth2provider-shared.js");
var utils = require("./authRecipe-shared.js");
var NormalisedURLPath$1 = require("supertokens-web-js/lib/build/normalisedURLPath");
@@ -120,7 +121,7 @@ var withOverride = function (overrideKey, DefaultComponent) {
};
var styles$1 =
- '[data-supertokens~="container"] {\n --palette-background: 255, 255, 255;\n --palette-inputBackground: 250, 250, 250;\n --palette-inputBorder: 224, 224, 224;\n --palette-primary: 28, 34, 42;\n --palette-primaryBorder: 45, 54, 68;\n --palette-success: 65, 167, 0;\n --palette-successBackground: 217, 255, 191;\n --palette-error: 255, 23, 23;\n --palette-errorBackground: 255, 241, 235;\n --palette-textTitle: 0, 0, 0;\n --palette-textLabel: 0, 0, 0;\n --palette-textInput: 0, 0, 0;\n --palette-textPrimary: 128, 128, 128;\n --palette-textLink: 0, 122, 255;\n --palette-buttonText: 255, 255, 255;\n --palette-textGray: 54, 54, 54;\n --palette-superTokensBrandingBackground: 242, 245, 246;\n --palette-superTokensBrandingText: 173, 189, 196;\n\n --font-size-0: 12px;\n --font-size-1: 14px;\n --font-size-2: 16px;\n --font-size-3: 19px;\n --font-size-4: 24px;\n --font-size-5: 28px;\n}\n/*\n * Default styles.\n */\n@keyframes slideTop {\n 0% {\n transform: translateY(-5px);\n }\n 100% {\n transform: translateY(0px);\n }\n}\n@keyframes swing-in-top-fwd {\n 0% {\n transform: rotateX(-100deg);\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n transform: rotateX(0deg);\n transform-origin: top;\n opacity: 1;\n }\n}\n[data-supertokens~="container"] {\n font-family: "Arial", sans-serif;\n margin: 12px auto;\n margin-top: 26px;\n margin-bottom: 26px;\n width: 420px;\n text-align: center;\n border-radius: 8px;\n box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.16);\n background-color: rgb(var(--palette-background));\n}\n@media (max-width: 440px) {\n [data-supertokens~="container"] {\n width: 95vw;\n }\n}\n[data-supertokens~="row"] {\n margin: 0 auto;\n width: 76%;\n padding-top: 30px;\n padding-bottom: 10px;\n}\n[data-supertokens~="superTokensBranding"] {\n display: block;\n margin: 10px auto 0;\n background: rgb(var(--palette-superTokensBrandingBackground));\n color: rgb(var(--palette-superTokensBrandingText));\n text-decoration: none;\n width: -webkit-fit-content;\n width: -moz-fit-content;\n width: fit-content;\n border-radius: 6px 6px 0 0;\n padding: 4px 9px;\n font-weight: 400;\n font-size: var(--font-size-0);\n letter-spacing: 0.4px;\n}\n[data-supertokens~="generalError"] {\n background: rgb(var(--palette-errorBackground));\n padding-top: 10px;\n padding-bottom: 10px;\n margin-bottom: 10px;\n margin-top: 24px;\n padding-left: 18px;\n padding-right: 18px;\n letter-spacing: 0.2px;\n font-size: var(--font-size-1);\n border-radius: 8px;\n color: rgb(var(--palette-error));\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n word-wrap: break-word;\n}\n[data-supertokens~="headerTitle"] {\n font-size: var(--font-size-4);\n line-height: 27.6px;\n letter-spacing: 0.58px;\n font-weight: 700;\n margin-bottom: 20px;\n color: rgb(var(--palette-textTitle));\n}\n[data-supertokens~="headerSubtitle"] {\n font-weight: 400;\n color: rgb(var(--palette-textGray));\n margin-bottom: 21px;\n}\n[data-supertokens~="headerSubtitle"][data-supertokens~="secondaryText"] {\n color: rgb(var(--palette-textGray));\n font-weight: 400;\n}\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] {\n max-width: 300px;\n margin-top: 10px;\n}\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] a {\n line-height: 21px;\n}\n/* TODO: split the link style into separate things*/\n/* We add this before primary and secondary text, because if they are applied to the same element the other ones take priority */\n[data-supertokens~="link"] {\n padding-left: 3px;\n padding-right: 3px;\n color: rgb(var(--palette-textLink));\n font-size: var(--font-size-1);\n cursor: pointer;\n letter-spacing: 0.16px;\n line-height: 26px;\n}\n[data-supertokens~="primaryText"] {\n font-size: var(--font-size-2);\n font-weight: 400;\n letter-spacing: 0.4px;\n line-height: 21px;\n color: rgb(var(--palette-textLabel));\n}\n[data-supertokens~="secondaryText"] {\n font-size: var(--font-size-1);\n font-weight: 400;\n letter-spacing: 0.4px;\n color: rgb(var(--palette-textPrimary));\n}\n[data-supertokens~="secondaryText"] strong {\n font-weight: 600;\n}\n[data-supertokens~="divider"] {\n margin-top: 1.5em;\n margin-bottom: 1.5em;\n border-bottom: 0.3px solid #dddddd;\n align-items: center;\n padding-bottom: 5px;\n flex: 3 3;\n}\n[data-supertokens~="headerTinyTitle"] {\n margin-top: 24px;\n font-size: var(--font-size-5);\n letter-spacing: 1.1px;\n font-weight: 700;\n line-height: 28px;\n}\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithArrow"]:hover {\n position: relative;\n left: 2px;\n word-spacing: 4px;\n}\n[data-supertokens~="generalSuccess"] {\n color: rgb(var(--palette-success));\n font-size: var(--font-size-1);\n background: rgb(var(--palette-successBackground));\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n padding: 9px 15px 9px 15px;\n border-radius: 6px;\n display: inline-block;\n}\n[data-supertokens~="spinner"] {\n width: 80px;\n height: auto;\n padding-top: 20px;\n padding-bottom: 40px;\n margin: 0 auto;\n}\n[data-supertokens~="error"] {\n color: rgb(var(--palette-error));\n}\n[data-supertokens~="linkButton"] {\n font-family: "Arial", sans-serif;\n background-color: transparent;\n border: 0;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"] {\n color: rgb(var(--palette-textGray));\n font-weight: 400;\n margin-top: 10px;\n margin-bottom: 40px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n margin-right: 0.3em;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"]:hover svg {\n position: relative;\n left: -4px;\n}\n[data-supertokens~="button"] {\n font-family: "Arial", sans-serif;\n background-color: rgb(var(--palette-primary));\n color: rgb(var(--palette-buttonText));\n width: 100%;\n height: 34px;\n font-weight: 600;\n border-width: 1px;\n border-style: solid;\n border-radius: 6px;\n border-color: rgb(var(--palette-primaryBorder));\n background-position: center;\n transition: all 0.4s;\n background-size: 12000%;\n cursor: pointer;\n}\n[data-supertokens~="button"]:disabled {\n border: none;\n cursor: no-drop;\n}\n[data-supertokens~="button"]:active {\n outline: none;\n transition: all 0s;\n background-size: 100%;\n filter: brightness(0.85);\n}\n[data-supertokens~="button"]:focus {\n outline: none;\n}\n[data-supertokens~="backButtonCommon"] {\n width: 16px;\n height: 13px;\n}\n[data-supertokens~="backButton"] {\n cursor: pointer;\n border: none;\n background-color: transparent;\n padding: 0px;\n}\n[data-supertokens~="backButtonPlaceholder"] {\n display: block;\n}\n[data-supertokens~="delayedRender"] {\n animation-duration: 0.1s;\n animation-name: animate-fade;\n animation-delay: 0.2s;\n animation-fill-mode: backwards;\n}\n@keyframes animate-fade {\n 0% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n}\n[data-supertokens~="footerLinkGroupVert"] {\n display: flex;\n flex-direction: column;\n margin-top: 10px;\n gap: 24px;\n}\n[data-supertokens~="footerLinkGroupVert"] > div {\n cursor: pointer;\n margin: 0;\n}\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryText"] {\n font-weight: 400;\n}\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n font-weight: 400;\n position: relative;\n left: -6px; /* half the width of the left arrow */\n}\n@media (max-width: 360px) {\n [data-supertokens~="footerLinkGroupVert"] {\n flex-direction: column;\n }\n [data-supertokens~="footerLinkGroupVert"] > div {\n margin: 0 auto;\n }\n}\n[data-supertokens~="footerLinkGroupVert"] div:only-child {\n margin-left: auto;\n margin-right: auto;\n margin-top: 14px;\n}\n[data-supertokens~="withBackButton"] {\n position: relative;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n[data-supertokens~="dividerWithOr"] {\n padding-top: 5px;\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n color: rgb(var(--palette-textPrimary));\n}\n[data-supertokens~="dividerText"] {\n flex: 1 1;\n font-weight: 400;\n font-size: var(--font-size-1);\n}\n[data-supertokens~="formLabelWithLinkWrapper"] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n[data-supertokens~="formLabelLinkBtn"] {\n width: auto;\n margin-top: 0;\n line-height: 24px;\n font-size: var(--font-size-0);\n}\n[data-supertokens~="formLabelLinkBtn"]:hover {\n text-decoration: underline;\n}\n[data-supertokens~="formLabelLinkBtn"]:disabled {\n color: rgb(var(--palette-textPrimary));\n cursor: default;\n text-decoration: none;\n}\n[data-supertokens~="authComponentList"] {\n padding-bottom: 20px;\n}\n[data-supertokens~="buttonWithArrow"] {\n border-radius: 6px;\n border: 1px solid #d0d5dd;\n width: 100%;\n color: rgb(var(--palette-textGray));\n display: flex;\n justify-content: center;\n align-items: center;\n gap: 5px;\n margin: 24px 0;\n min-height: 48px;\n cursor: pointer;\n}\n[data-supertokens~="buttonWithArrow"]:hover {\n background-color: rgb(var(--palette-inputBackground));\n}\n[data-supertokens~="buttonWithArrow"] [data-supertokens~="secondaryText"] {\n font-weight: 700;\n font-size: var(--font-size-2);\n color: rgb(var(--palette-textGray));\n margin: 0;\n}\n[data-supertokens~="buttonWithArrow"]:hover [data-supertokens~="secondaryLinkWithRightArrow"] ~ svg {\n position: relative;\n left: 2px;\n}\n[data-supertokens~="buttonWithArrow"]:hover [data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n position: relative;\n left: -2px;\n}\n[data-supertokens~="buttonWithArrow"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n display: flex;\n align-items: center;\n}\n';
+ '[data-supertokens~="container"] {\n --palette-background: 255, 255, 255;\n --palette-inputBackground: 250, 250, 250;\n --palette-inputBorder: 224, 224, 224;\n --palette-primary: 28, 34, 42;\n --palette-primaryBorder: 45, 54, 68;\n --palette-success: 65, 167, 0;\n --palette-successBackground: 217, 255, 191;\n --palette-error: 255, 23, 23;\n --palette-errorBackground: 255, 241, 235;\n --palette-textTitle: 0, 0, 0;\n --palette-textLabel: 0, 0, 0;\n --palette-textInput: 0, 0, 0;\n --palette-textPrimary: 128, 128, 128;\n --palette-textLink: 0, 122, 255;\n --palette-buttonText: 255, 255, 255;\n --palette-textGray: 54, 54, 54;\n --palette-superTokensBrandingBackground: 242, 245, 246;\n --palette-superTokensBrandingText: 173, 189, 196;\n\n --font-size-0: 12px;\n --font-size-1: 14px;\n --font-size-2: 16px;\n --font-size-3: 19px;\n --font-size-4: 24px;\n --font-size-5: 28px;\n}\n/*\n * Default styles.\n */\n@keyframes slideTop {\n 0% {\n transform: translateY(-5px);\n }\n 100% {\n transform: translateY(0px);\n }\n}\n@keyframes swing-in-top-fwd {\n 0% {\n transform: rotateX(-100deg);\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n transform: rotateX(0deg);\n transform-origin: top;\n opacity: 1;\n }\n}\n[data-supertokens~="container"] {\n font-family: "Arial", sans-serif;\n margin: 12px auto;\n margin-top: 26px;\n margin-bottom: 26px;\n width: 420px;\n text-align: center;\n border-radius: 8px;\n box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.16);\n background-color: rgb(var(--palette-background));\n}\n@media (max-width: 440px) {\n [data-supertokens~="container"] {\n width: 95vw;\n }\n}\n[data-supertokens~="row"] {\n margin: 0 auto;\n width: 76%;\n padding-top: 30px;\n padding-bottom: 10px;\n}\n[data-supertokens~="superTokensBranding"] {\n display: block;\n margin: 10px auto 0;\n background: rgb(var(--palette-superTokensBrandingBackground));\n color: rgb(var(--palette-superTokensBrandingText));\n text-decoration: none;\n width: -webkit-fit-content;\n width: -moz-fit-content;\n width: fit-content;\n border-radius: 6px 6px 0 0;\n padding: 4px 9px;\n font-weight: 400;\n font-size: var(--font-size-0);\n letter-spacing: 0.4px;\n}\n[data-supertokens~="generalError"] {\n background: rgb(var(--palette-errorBackground));\n padding-top: 10px;\n padding-bottom: 10px;\n margin-bottom: 10px;\n margin-top: 24px;\n padding-left: 18px;\n padding-right: 18px;\n letter-spacing: 0.2px;\n font-size: var(--font-size-1);\n border-radius: 8px;\n color: rgb(var(--palette-error));\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n word-wrap: break-word;\n}\n[data-supertokens~="headerTitle"] {\n font-size: var(--font-size-4);\n line-height: 27.6px;\n letter-spacing: 0.58px;\n font-weight: 700;\n margin-bottom: 20px;\n color: rgb(var(--palette-textTitle));\n}\n[data-supertokens~="headerSubtitle"] {\n font-weight: 400;\n color: rgb(var(--palette-textGray));\n margin-bottom: 21px;\n}\n[data-supertokens~="headerSubtitle"][data-supertokens~="secondaryText"] {\n color: rgb(var(--palette-textGray));\n font-weight: 400;\n}\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] {\n max-width: 300px;\n margin-top: 10px;\n}\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] a {\n line-height: 21px;\n}\n/* TODO: split the link style into separate things*/\n/* We add this before primary and secondary text, because if they are applied to the same element the other ones take priority */\n[data-supertokens~="link"] {\n padding-left: 3px;\n padding-right: 3px;\n color: rgb(var(--palette-textLink));\n font-size: var(--font-size-1);\n cursor: pointer;\n letter-spacing: 0.16px;\n line-height: 26px;\n}\n[data-supertokens~="primaryText"] {\n font-size: var(--font-size-2);\n font-weight: 400;\n letter-spacing: 0.4px;\n line-height: 21px;\n color: rgb(var(--palette-textLabel));\n}\n[data-supertokens~="secondaryText"] {\n font-size: var(--font-size-1);\n font-weight: 400;\n letter-spacing: 0.4px;\n color: rgb(var(--palette-textPrimary));\n}\n[data-supertokens~="secondaryText"] strong {\n font-weight: 600;\n}\n[data-supertokens~="divider"] {\n margin-top: 1.5em;\n margin-bottom: 1.5em;\n border-bottom: 0.3px solid #dddddd;\n align-items: center;\n padding-bottom: 5px;\n flex: 3 3;\n}\n[data-supertokens~="headerTinyTitle"] {\n margin-top: 24px;\n font-size: var(--font-size-5);\n letter-spacing: 1.1px;\n font-weight: 700;\n line-height: 28px;\n}\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithArrow"]:hover {\n position: relative;\n left: 2px;\n word-spacing: 4px;\n}\n[data-supertokens~="generalSuccess"] {\n color: rgb(var(--palette-success));\n font-size: var(--font-size-1);\n background: rgb(var(--palette-successBackground));\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n padding: 9px 15px 9px 15px;\n border-radius: 6px;\n display: inline-block;\n}\n[data-supertokens~="spinner"] {\n width: 80px;\n height: auto;\n padding-top: 20px;\n padding-bottom: 40px;\n margin: 0 auto;\n}\n[data-supertokens~="error"] {\n color: rgb(var(--palette-error));\n}\n[data-supertokens~="linkButton"] {\n font-family: "Arial", sans-serif;\n background-color: transparent;\n border: 0;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"] {\n color: rgb(var(--palette-textGray));\n font-weight: 400;\n margin-top: 10px;\n margin-bottom: 40px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n margin-right: 0.3em;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"]:hover svg {\n position: relative;\n left: -4px;\n}\n[data-supertokens~="button"] {\n font-family: "Arial", sans-serif;\n background-color: rgb(var(--palette-primary));\n color: rgb(var(--palette-buttonText));\n width: 100%;\n height: 34px;\n font-weight: 600;\n border-width: 1px;\n border-style: solid;\n border-radius: 6px;\n border-color: rgb(var(--palette-primaryBorder));\n background-position: center;\n transition: all 0.4s;\n background-size: 12000%;\n cursor: pointer;\n}\n[data-supertokens~="button"]:disabled {\n border: none;\n cursor: no-drop;\n}\n[data-supertokens~="button"]:active {\n outline: none;\n transition: all 0s;\n background-size: 100%;\n filter: brightness(0.85);\n}\n[data-supertokens~="button"]:focus {\n outline: none;\n}\n[data-supertokens~="backButtonCommon"] {\n width: 16px;\n height: 13px;\n}\n[data-supertokens~="backButton"] {\n cursor: pointer;\n border: none;\n background-color: transparent;\n padding: 0px;\n}\n[data-supertokens~="backButtonPlaceholder"] {\n display: block;\n}\n[data-supertokens~="delayedRender"] {\n animation-duration: 0.1s;\n animation-name: animate-fade;\n animation-delay: 0.2s;\n animation-fill-mode: backwards;\n}\n@keyframes animate-fade {\n 0% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n}\n[data-supertokens~="footerLinkGroupVert"] {\n display: flex;\n flex-direction: column;\n margin-top: 10px;\n gap: 24px;\n}\n[data-supertokens~="footerLinkGroupVert"] > div {\n cursor: pointer;\n margin: 0;\n}\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryText"] {\n font-weight: 400;\n}\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n font-weight: 400;\n position: relative;\n left: -6px; /* half the width of the left arrow */\n}\n@media (max-width: 360px) {\n [data-supertokens~="footerLinkGroupVert"] {\n flex-direction: column;\n }\n [data-supertokens~="footerLinkGroupVert"] > div {\n margin: 0 auto;\n }\n}\n[data-supertokens~="footerLinkGroupVert"] div:only-child {\n margin-left: auto;\n margin-right: auto;\n margin-top: 14px;\n}\n[data-supertokens~="withBackButton"] {\n position: relative;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n[data-supertokens~="dividerWithOr"] {\n padding-top: 5px;\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n color: rgb(var(--palette-textPrimary));\n}\n[data-supertokens~="dividerText"] {\n flex: 1 1;\n font-weight: 400;\n font-size: var(--font-size-1);\n}\n[data-supertokens~="formLabelWithLinkWrapper"] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n[data-supertokens~="formLabelLinkBtn"] {\n width: auto;\n margin-top: 0;\n line-height: 24px;\n font-size: var(--font-size-0);\n}\n[data-supertokens~="formLabelLinkBtn"]:hover {\n text-decoration: underline;\n}\n[data-supertokens~="formLabelLinkBtn"]:disabled {\n color: rgb(var(--palette-textPrimary));\n cursor: default;\n text-decoration: none;\n}\n[data-supertokens~="authComponentList"] {\n padding-bottom: 20px;\n}\n[data-supertokens~="authPageTitleOAuthClient"] {\n color: rgb(var(--palette-textGray));\n font-size: var(--font-size-1);\n font-weight: 400;\n margin: 10px 0 25px;\n}\n[data-supertokens~="authPageTitleOAuthClientUrl"] {\n text-decoration: none;\n}\n[data-supertokens~="authPageTitleOAuthClientLogo"] {\n width: 44px;\n height: 44px;\n margin-bottom: 10px;\n}\n[data-supertokens~="authPageTitleOAuthClient"] [data-supertokens~="authPageTitleOAuthClientName"] {\n color: rgb(var(--palette-textTitle));\n}\n[data-supertokens~="buttonWithArrow"] {\n border-radius: 6px;\n border: 1px solid #d0d5dd;\n width: 100%;\n color: rgb(var(--palette-textGray));\n display: flex;\n justify-content: center;\n align-items: center;\n gap: 5px;\n margin: 24px 0;\n min-height: 48px;\n cursor: pointer;\n}\n[data-supertokens~="buttonWithArrow"]:hover {\n background-color: rgb(var(--palette-inputBackground));\n}\n[data-supertokens~="buttonWithArrow"] [data-supertokens~="secondaryText"] {\n font-weight: 700;\n font-size: var(--font-size-2);\n color: rgb(var(--palette-textGray));\n margin: 0;\n}\n[data-supertokens~="buttonWithArrow"]:hover [data-supertokens~="secondaryLinkWithRightArrow"] ~ svg {\n position: relative;\n left: 2px;\n}\n[data-supertokens~="buttonWithArrow"]:hover [data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n position: relative;\n left: -2px;\n}\n[data-supertokens~="buttonWithArrow"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n display: flex;\n align-items: center;\n}\n';
var ThemeBase$1 = function (_a) {
var children = _a.children,
@@ -354,6 +355,7 @@ var defaultTranslationsCommon = {
AUTH_PAGE_HEADER_TITLE_SIGN_IN_AND_UP: "Sign Up / Sign In",
AUTH_PAGE_HEADER_TITLE_SIGN_IN: "Sign In",
AUTH_PAGE_HEADER_TITLE_SIGN_UP: "Sign Up",
+ AUTH_PAGE_HEADER_TITLE_SIGN_IN_UP_TO_APP: " to continue to ",
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_START: "Not registered yet?",
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_SIGN_UP_LINK: "Sign Up",
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_END: "",
@@ -459,7 +461,7 @@ function GeneralError(_a) {
}
var styles =
- '[data-supertokens~="container"] {\n --palette-background: 255, 255, 255;\n --palette-inputBackground: 250, 250, 250;\n --palette-inputBorder: 224, 224, 224;\n --palette-primary: 28, 34, 42;\n --palette-primaryBorder: 45, 54, 68;\n --palette-success: 65, 167, 0;\n --palette-successBackground: 217, 255, 191;\n --palette-error: 255, 23, 23;\n --palette-errorBackground: 255, 241, 235;\n --palette-textTitle: 0, 0, 0;\n --palette-textLabel: 0, 0, 0;\n --palette-textInput: 0, 0, 0;\n --palette-textPrimary: 128, 128, 128;\n --palette-textLink: 0, 122, 255;\n --palette-buttonText: 255, 255, 255;\n --palette-textGray: 54, 54, 54;\n --palette-superTokensBrandingBackground: 242, 245, 246;\n --palette-superTokensBrandingText: 173, 189, 196;\n\n --font-size-0: 12px;\n --font-size-1: 14px;\n --font-size-2: 16px;\n --font-size-3: 19px;\n --font-size-4: 24px;\n --font-size-5: 28px;\n}\n/*\n * Default styles.\n */\n@keyframes slideTop {\n 0% {\n transform: translateY(-5px);\n }\n 100% {\n transform: translateY(0px);\n }\n}\n@keyframes swing-in-top-fwd {\n 0% {\n transform: rotateX(-100deg);\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n transform: rotateX(0deg);\n transform-origin: top;\n opacity: 1;\n }\n}\n[data-supertokens~="container"] {\n font-family: "Arial", sans-serif;\n margin: 12px auto;\n margin-top: 26px;\n margin-bottom: 26px;\n width: 420px;\n text-align: center;\n border-radius: 8px;\n box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.16);\n background-color: rgb(var(--palette-background));\n}\n@media (max-width: 440px) {\n [data-supertokens~="container"] {\n width: 95vw;\n }\n}\n[data-supertokens~="row"] {\n margin: 0 auto;\n width: 76%;\n padding-top: 30px;\n padding-bottom: 10px;\n}\n[data-supertokens~="superTokensBranding"] {\n display: block;\n margin: 10px auto 0;\n background: rgb(var(--palette-superTokensBrandingBackground));\n color: rgb(var(--palette-superTokensBrandingText));\n text-decoration: none;\n width: -webkit-fit-content;\n width: -moz-fit-content;\n width: fit-content;\n border-radius: 6px 6px 0 0;\n padding: 4px 9px;\n font-weight: 400;\n font-size: var(--font-size-0);\n letter-spacing: 0.4px;\n}\n[data-supertokens~="generalError"] {\n background: rgb(var(--palette-errorBackground));\n padding-top: 10px;\n padding-bottom: 10px;\n margin-bottom: 10px;\n margin-top: 24px;\n padding-left: 18px;\n padding-right: 18px;\n letter-spacing: 0.2px;\n font-size: var(--font-size-1);\n border-radius: 8px;\n color: rgb(var(--palette-error));\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n word-wrap: break-word;\n}\n[data-supertokens~="headerTitle"] {\n font-size: var(--font-size-4);\n line-height: 27.6px;\n letter-spacing: 0.58px;\n font-weight: 700;\n margin-bottom: 20px;\n color: rgb(var(--palette-textTitle));\n}\n[data-supertokens~="headerSubtitle"] {\n font-weight: 400;\n color: rgb(var(--palette-textGray));\n margin-bottom: 21px;\n}\n[data-supertokens~="headerSubtitle"][data-supertokens~="secondaryText"] {\n color: rgb(var(--palette-textGray));\n font-weight: 400;\n}\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] {\n max-width: 300px;\n margin-top: 10px;\n}\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] a {\n line-height: 21px;\n}\n/* TODO: split the link style into separate things*/\n/* We add this before primary and secondary text, because if they are applied to the same element the other ones take priority */\n[data-supertokens~="link"] {\n padding-left: 3px;\n padding-right: 3px;\n color: rgb(var(--palette-textLink));\n font-size: var(--font-size-1);\n cursor: pointer;\n letter-spacing: 0.16px;\n line-height: 26px;\n}\n[data-supertokens~="primaryText"] {\n font-size: var(--font-size-2);\n font-weight: 400;\n letter-spacing: 0.4px;\n line-height: 21px;\n color: rgb(var(--palette-textLabel));\n}\n[data-supertokens~="secondaryText"] {\n font-size: var(--font-size-1);\n font-weight: 400;\n letter-spacing: 0.4px;\n color: rgb(var(--palette-textPrimary));\n}\n[data-supertokens~="secondaryText"] strong {\n font-weight: 600;\n}\n[data-supertokens~="divider"] {\n margin-top: 1.5em;\n margin-bottom: 1.5em;\n border-bottom: 0.3px solid #dddddd;\n align-items: center;\n padding-bottom: 5px;\n flex: 3 3;\n}\n[data-supertokens~="headerTinyTitle"] {\n margin-top: 24px;\n font-size: var(--font-size-5);\n letter-spacing: 1.1px;\n font-weight: 700;\n line-height: 28px;\n}\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithArrow"]:hover {\n position: relative;\n left: 2px;\n word-spacing: 4px;\n}\n[data-supertokens~="generalSuccess"] {\n color: rgb(var(--palette-success));\n font-size: var(--font-size-1);\n background: rgb(var(--palette-successBackground));\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n padding: 9px 15px 9px 15px;\n border-radius: 6px;\n display: inline-block;\n}\n[data-supertokens~="spinner"] {\n width: 80px;\n height: auto;\n padding-top: 20px;\n padding-bottom: 40px;\n margin: 0 auto;\n}\n[data-supertokens~="error"] {\n color: rgb(var(--palette-error));\n}\n[data-supertokens~="linkButton"] {\n font-family: "Arial", sans-serif;\n background-color: transparent;\n border: 0;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"] {\n color: rgb(var(--palette-textGray));\n font-weight: 400;\n margin-top: 10px;\n margin-bottom: 40px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n margin-right: 0.3em;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"]:hover svg {\n position: relative;\n left: -4px;\n}\n[data-supertokens~="button"] {\n font-family: "Arial", sans-serif;\n background-color: rgb(var(--palette-primary));\n color: rgb(var(--palette-buttonText));\n width: 100%;\n height: 34px;\n font-weight: 600;\n border-width: 1px;\n border-style: solid;\n border-radius: 6px;\n border-color: rgb(var(--palette-primaryBorder));\n background-position: center;\n transition: all 0.4s;\n background-size: 12000%;\n cursor: pointer;\n}\n[data-supertokens~="button"]:disabled {\n border: none;\n cursor: no-drop;\n}\n[data-supertokens~="button"]:active {\n outline: none;\n transition: all 0s;\n background-size: 100%;\n filter: brightness(0.85);\n}\n[data-supertokens~="button"]:focus {\n outline: none;\n}\n[data-supertokens~="backButtonCommon"] {\n width: 16px;\n height: 13px;\n}\n[data-supertokens~="backButton"] {\n cursor: pointer;\n border: none;\n background-color: transparent;\n padding: 0px;\n}\n[data-supertokens~="backButtonPlaceholder"] {\n display: block;\n}\n[data-supertokens~="delayedRender"] {\n animation-duration: 0.1s;\n animation-name: animate-fade;\n animation-delay: 0.2s;\n animation-fill-mode: backwards;\n}\n@keyframes animate-fade {\n 0% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n}\n[data-supertokens~="footerLinkGroupVert"] {\n display: flex;\n flex-direction: column;\n margin-top: 10px;\n gap: 24px;\n}\n[data-supertokens~="footerLinkGroupVert"] > div {\n cursor: pointer;\n margin: 0;\n}\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryText"] {\n font-weight: 400;\n}\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n font-weight: 400;\n position: relative;\n left: -6px; /* half the width of the left arrow */\n}\n@media (max-width: 360px) {\n [data-supertokens~="footerLinkGroupVert"] {\n flex-direction: column;\n }\n [data-supertokens~="footerLinkGroupVert"] > div {\n margin: 0 auto;\n }\n}\n[data-supertokens~="footerLinkGroupVert"] div:only-child {\n margin-left: auto;\n margin-right: auto;\n margin-top: 14px;\n}\n[data-supertokens~="withBackButton"] {\n position: relative;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n[data-supertokens~="dividerWithOr"] {\n padding-top: 5px;\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n color: rgb(var(--palette-textPrimary));\n}\n[data-supertokens~="dividerText"] {\n flex: 1 1;\n font-weight: 400;\n font-size: var(--font-size-1);\n}\n[data-supertokens~="formLabelWithLinkWrapper"] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n[data-supertokens~="formLabelLinkBtn"] {\n width: auto;\n margin-top: 0;\n line-height: 24px;\n font-size: var(--font-size-0);\n}\n[data-supertokens~="formLabelLinkBtn"]:hover {\n text-decoration: underline;\n}\n[data-supertokens~="formLabelLinkBtn"]:disabled {\n color: rgb(var(--palette-textPrimary));\n cursor: default;\n text-decoration: none;\n}\n[data-supertokens~="authComponentList"] {\n padding-bottom: 20px;\n}\n[data-supertokens~="buttonWithArrow"] {\n border-radius: 6px;\n border: 1px solid #d0d5dd;\n width: 100%;\n color: rgb(var(--palette-textGray));\n display: flex;\n justify-content: center;\n align-items: center;\n gap: 5px;\n margin: 24px 0;\n min-height: 48px;\n cursor: pointer;\n}\n[data-supertokens~="buttonWithArrow"]:hover {\n background-color: rgb(var(--palette-inputBackground));\n}\n[data-supertokens~="buttonWithArrow"] [data-supertokens~="secondaryText"] {\n font-weight: 700;\n font-size: var(--font-size-2);\n color: rgb(var(--palette-textGray));\n margin: 0;\n}\n[data-supertokens~="buttonWithArrow"]:hover [data-supertokens~="secondaryLinkWithRightArrow"] ~ svg {\n position: relative;\n left: 2px;\n}\n[data-supertokens~="buttonWithArrow"]:hover [data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n position: relative;\n left: -2px;\n}\n[data-supertokens~="buttonWithArrow"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n display: flex;\n align-items: center;\n}\n';
+ '[data-supertokens~="container"] {\n --palette-background: 255, 255, 255;\n --palette-inputBackground: 250, 250, 250;\n --palette-inputBorder: 224, 224, 224;\n --palette-primary: 28, 34, 42;\n --palette-primaryBorder: 45, 54, 68;\n --palette-success: 65, 167, 0;\n --palette-successBackground: 217, 255, 191;\n --palette-error: 255, 23, 23;\n --palette-errorBackground: 255, 241, 235;\n --palette-textTitle: 0, 0, 0;\n --palette-textLabel: 0, 0, 0;\n --palette-textInput: 0, 0, 0;\n --palette-textPrimary: 128, 128, 128;\n --palette-textLink: 0, 122, 255;\n --palette-buttonText: 255, 255, 255;\n --palette-textGray: 54, 54, 54;\n --palette-superTokensBrandingBackground: 242, 245, 246;\n --palette-superTokensBrandingText: 173, 189, 196;\n\n --font-size-0: 12px;\n --font-size-1: 14px;\n --font-size-2: 16px;\n --font-size-3: 19px;\n --font-size-4: 24px;\n --font-size-5: 28px;\n}\n/*\n * Default styles.\n */\n@keyframes slideTop {\n 0% {\n transform: translateY(-5px);\n }\n 100% {\n transform: translateY(0px);\n }\n}\n@keyframes swing-in-top-fwd {\n 0% {\n transform: rotateX(-100deg);\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n transform: rotateX(0deg);\n transform-origin: top;\n opacity: 1;\n }\n}\n[data-supertokens~="container"] {\n font-family: "Arial", sans-serif;\n margin: 12px auto;\n margin-top: 26px;\n margin-bottom: 26px;\n width: 420px;\n text-align: center;\n border-radius: 8px;\n box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.16);\n background-color: rgb(var(--palette-background));\n}\n@media (max-width: 440px) {\n [data-supertokens~="container"] {\n width: 95vw;\n }\n}\n[data-supertokens~="row"] {\n margin: 0 auto;\n width: 76%;\n padding-top: 30px;\n padding-bottom: 10px;\n}\n[data-supertokens~="superTokensBranding"] {\n display: block;\n margin: 10px auto 0;\n background: rgb(var(--palette-superTokensBrandingBackground));\n color: rgb(var(--palette-superTokensBrandingText));\n text-decoration: none;\n width: -webkit-fit-content;\n width: -moz-fit-content;\n width: fit-content;\n border-radius: 6px 6px 0 0;\n padding: 4px 9px;\n font-weight: 400;\n font-size: var(--font-size-0);\n letter-spacing: 0.4px;\n}\n[data-supertokens~="generalError"] {\n background: rgb(var(--palette-errorBackground));\n padding-top: 10px;\n padding-bottom: 10px;\n margin-bottom: 10px;\n margin-top: 24px;\n padding-left: 18px;\n padding-right: 18px;\n letter-spacing: 0.2px;\n font-size: var(--font-size-1);\n border-radius: 8px;\n color: rgb(var(--palette-error));\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n word-wrap: break-word;\n}\n[data-supertokens~="headerTitle"] {\n font-size: var(--font-size-4);\n line-height: 27.6px;\n letter-spacing: 0.58px;\n font-weight: 700;\n margin-bottom: 20px;\n color: rgb(var(--palette-textTitle));\n}\n[data-supertokens~="headerSubtitle"] {\n font-weight: 400;\n color: rgb(var(--palette-textGray));\n margin-bottom: 21px;\n}\n[data-supertokens~="headerSubtitle"][data-supertokens~="secondaryText"] {\n color: rgb(var(--palette-textGray));\n font-weight: 400;\n}\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] {\n max-width: 300px;\n margin-top: 10px;\n}\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] a {\n line-height: 21px;\n}\n/* TODO: split the link style into separate things*/\n/* We add this before primary and secondary text, because if they are applied to the same element the other ones take priority */\n[data-supertokens~="link"] {\n padding-left: 3px;\n padding-right: 3px;\n color: rgb(var(--palette-textLink));\n font-size: var(--font-size-1);\n cursor: pointer;\n letter-spacing: 0.16px;\n line-height: 26px;\n}\n[data-supertokens~="primaryText"] {\n font-size: var(--font-size-2);\n font-weight: 400;\n letter-spacing: 0.4px;\n line-height: 21px;\n color: rgb(var(--palette-textLabel));\n}\n[data-supertokens~="secondaryText"] {\n font-size: var(--font-size-1);\n font-weight: 400;\n letter-spacing: 0.4px;\n color: rgb(var(--palette-textPrimary));\n}\n[data-supertokens~="secondaryText"] strong {\n font-weight: 600;\n}\n[data-supertokens~="divider"] {\n margin-top: 1.5em;\n margin-bottom: 1.5em;\n border-bottom: 0.3px solid #dddddd;\n align-items: center;\n padding-bottom: 5px;\n flex: 3 3;\n}\n[data-supertokens~="headerTinyTitle"] {\n margin-top: 24px;\n font-size: var(--font-size-5);\n letter-spacing: 1.1px;\n font-weight: 700;\n line-height: 28px;\n}\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithArrow"]:hover {\n position: relative;\n left: 2px;\n word-spacing: 4px;\n}\n[data-supertokens~="generalSuccess"] {\n color: rgb(var(--palette-success));\n font-size: var(--font-size-1);\n background: rgb(var(--palette-successBackground));\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n padding: 9px 15px 9px 15px;\n border-radius: 6px;\n display: inline-block;\n}\n[data-supertokens~="spinner"] {\n width: 80px;\n height: auto;\n padding-top: 20px;\n padding-bottom: 40px;\n margin: 0 auto;\n}\n[data-supertokens~="error"] {\n color: rgb(var(--palette-error));\n}\n[data-supertokens~="linkButton"] {\n font-family: "Arial", sans-serif;\n background-color: transparent;\n border: 0;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"] {\n color: rgb(var(--palette-textGray));\n font-weight: 400;\n margin-top: 10px;\n margin-bottom: 40px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n margin-right: 0.3em;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"]:hover svg {\n position: relative;\n left: -4px;\n}\n[data-supertokens~="button"] {\n font-family: "Arial", sans-serif;\n background-color: rgb(var(--palette-primary));\n color: rgb(var(--palette-buttonText));\n width: 100%;\n height: 34px;\n font-weight: 600;\n border-width: 1px;\n border-style: solid;\n border-radius: 6px;\n border-color: rgb(var(--palette-primaryBorder));\n background-position: center;\n transition: all 0.4s;\n background-size: 12000%;\n cursor: pointer;\n}\n[data-supertokens~="button"]:disabled {\n border: none;\n cursor: no-drop;\n}\n[data-supertokens~="button"]:active {\n outline: none;\n transition: all 0s;\n background-size: 100%;\n filter: brightness(0.85);\n}\n[data-supertokens~="button"]:focus {\n outline: none;\n}\n[data-supertokens~="backButtonCommon"] {\n width: 16px;\n height: 13px;\n}\n[data-supertokens~="backButton"] {\n cursor: pointer;\n border: none;\n background-color: transparent;\n padding: 0px;\n}\n[data-supertokens~="backButtonPlaceholder"] {\n display: block;\n}\n[data-supertokens~="delayedRender"] {\n animation-duration: 0.1s;\n animation-name: animate-fade;\n animation-delay: 0.2s;\n animation-fill-mode: backwards;\n}\n@keyframes animate-fade {\n 0% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n}\n[data-supertokens~="footerLinkGroupVert"] {\n display: flex;\n flex-direction: column;\n margin-top: 10px;\n gap: 24px;\n}\n[data-supertokens~="footerLinkGroupVert"] > div {\n cursor: pointer;\n margin: 0;\n}\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryText"] {\n font-weight: 400;\n}\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n font-weight: 400;\n position: relative;\n left: -6px; /* half the width of the left arrow */\n}\n@media (max-width: 360px) {\n [data-supertokens~="footerLinkGroupVert"] {\n flex-direction: column;\n }\n [data-supertokens~="footerLinkGroupVert"] > div {\n margin: 0 auto;\n }\n}\n[data-supertokens~="footerLinkGroupVert"] div:only-child {\n margin-left: auto;\n margin-right: auto;\n margin-top: 14px;\n}\n[data-supertokens~="withBackButton"] {\n position: relative;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n[data-supertokens~="dividerWithOr"] {\n padding-top: 5px;\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n color: rgb(var(--palette-textPrimary));\n}\n[data-supertokens~="dividerText"] {\n flex: 1 1;\n font-weight: 400;\n font-size: var(--font-size-1);\n}\n[data-supertokens~="formLabelWithLinkWrapper"] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n[data-supertokens~="formLabelLinkBtn"] {\n width: auto;\n margin-top: 0;\n line-height: 24px;\n font-size: var(--font-size-0);\n}\n[data-supertokens~="formLabelLinkBtn"]:hover {\n text-decoration: underline;\n}\n[data-supertokens~="formLabelLinkBtn"]:disabled {\n color: rgb(var(--palette-textPrimary));\n cursor: default;\n text-decoration: none;\n}\n[data-supertokens~="authComponentList"] {\n padding-bottom: 20px;\n}\n[data-supertokens~="authPageTitleOAuthClient"] {\n color: rgb(var(--palette-textGray));\n font-size: var(--font-size-1);\n font-weight: 400;\n margin: 10px 0 25px;\n}\n[data-supertokens~="authPageTitleOAuthClientUrl"] {\n text-decoration: none;\n}\n[data-supertokens~="authPageTitleOAuthClientLogo"] {\n width: 44px;\n height: 44px;\n margin-bottom: 10px;\n}\n[data-supertokens~="authPageTitleOAuthClient"] [data-supertokens~="authPageTitleOAuthClientName"] {\n color: rgb(var(--palette-textTitle));\n}\n[data-supertokens~="buttonWithArrow"] {\n border-radius: 6px;\n border: 1px solid #d0d5dd;\n width: 100%;\n color: rgb(var(--palette-textGray));\n display: flex;\n justify-content: center;\n align-items: center;\n gap: 5px;\n margin: 24px 0;\n min-height: 48px;\n cursor: pointer;\n}\n[data-supertokens~="buttonWithArrow"]:hover {\n background-color: rgb(var(--palette-inputBackground));\n}\n[data-supertokens~="buttonWithArrow"] [data-supertokens~="secondaryText"] {\n font-weight: 700;\n font-size: var(--font-size-2);\n color: rgb(var(--palette-textGray));\n margin: 0;\n}\n[data-supertokens~="buttonWithArrow"]:hover [data-supertokens~="secondaryLinkWithRightArrow"] ~ svg {\n position: relative;\n left: 2px;\n}\n[data-supertokens~="buttonWithArrow"]:hover [data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n position: relative;\n left: -2px;\n}\n[data-supertokens~="buttonWithArrow"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n display: flex;\n align-items: center;\n}\n';
var ThemeBase = function (_a) {
var children = _a.children,
@@ -628,10 +630,17 @@ var AuthPageHeader = withOverride("AuthPageHeader", function AuthPageHeader(_a)
hasSeparateSignUpView = _a.hasSeparateSignUpView,
isSignUp = _a.isSignUp,
showBackButton = _a.showBackButton,
- resetFactorList = _a.resetFactorList;
+ resetFactorList = _a.resetFactorList,
+ oauth2ClientInfo = _a.oauth2ClientInfo;
var t = translationContext.useTranslation();
return jsxRuntime.jsxs(React.Fragment, {
children: [
+ (oauth2ClientInfo === null || oauth2ClientInfo === void 0 ? void 0 : oauth2ClientInfo.logoUri) &&
+ jsxRuntime.jsx("img", {
+ src: oauth2ClientInfo.logoUri,
+ alt: oauth2ClientInfo.clientName,
+ "data-supertokens": "authPageTitleOAuthClientLogo",
+ }),
jsxRuntime.jsxs(
"div",
genericComponentOverrideContext.__assign(
@@ -653,6 +662,38 @@ var AuthPageHeader = withOverride("AuthPageHeader", function AuthPageHeader(_a)
}
)
),
+ oauth2ClientInfo &&
+ oauth2ClientInfo.clientName !== undefined &&
+ oauth2ClientInfo.clientName.length > 0 &&
+ jsxRuntime.jsxs(
+ "div",
+ genericComponentOverrideContext.__assign(
+ { "data-supertokens": "authPageTitleOAuthClient" },
+ {
+ children: [
+ t("AUTH_PAGE_HEADER_TITLE_SIGN_IN_UP_TO_APP"),
+ oauth2ClientInfo.clientUri !== undefined
+ ? jsxRuntime.jsx(
+ "a",
+ genericComponentOverrideContext.__assign(
+ {
+ "data-supertokens": "authPageTitleOAuthClientUrl link",
+ href: oauth2ClientInfo.clientUri,
+ },
+ { children: oauth2ClientInfo.clientName }
+ )
+ )
+ : jsxRuntime.jsx(
+ "span",
+ genericComponentOverrideContext.__assign(
+ { "data-supertokens": "authPageTitleOAuthClientName" },
+ { children: oauth2ClientInfo.clientName }
+ )
+ ),
+ ],
+ }
+ )
+ ),
hasSeparateSignUpView &&
(!isSignUp
? jsxRuntime.jsxs(
@@ -731,6 +772,7 @@ function AuthPageTheme(props) {
hasSeparateSignUpView: props.hasSeparateSignUpView,
resetFactorList: props.resetFactorList,
showBackButton: props.showBackButton,
+ oauth2ClientInfo: props.oauth2ClientInfo,
}),
props.error !== undefined && jsxRuntime.jsx(GeneralError, { error: props.error }),
jsxRuntime.jsx(
@@ -836,33 +878,38 @@ var AuthPageInner = function (props) {
: undefined;
var showStringFromQSRef = React.useRef(showStringFromQS);
var errorFromQSRef = React.useRef(errorFromQS);
+ var loginChallenge = search.get("loginChallenge");
+ var forceFreshAuth = search.get("forceFreshAuth") === "true";
var sessionContext = useSessionContext();
var userContext = useUserContext();
var rethrowInRender = genericComponentOverrideContext.useRethrowInRender();
var _f = React.useState(undefined),
loadedDynamicLoginMethods = _f[0],
setLoadedDynamicLoginMethods = _f[1];
- var _g = React.useState(errorFromQS),
- error = _g[0],
- setError = _g[1];
- var _h = React.useState(false),
- sessionLoadedAndNotRedirecting = _h[0],
- setSessionLoadedAndNotRedirecting = _h[1];
+ var _g = React.useState(undefined),
+ oauth2ClientInfo = _g[0],
+ setOAuth2ClientInfo = _g[1];
+ var _h = React.useState(errorFromQS),
+ error = _h[0],
+ setError = _h[1];
+ var _j = React.useState(false),
+ sessionLoadedAndNotRedirecting = _j[0],
+ setSessionLoadedAndNotRedirecting = _j[1];
var st = genericComponentOverrideContext.SuperTokens.getInstanceOrThrow();
- var _j = React.useState(props.factors),
- factorList = _j[0],
- setFactorList = _j[1];
- var _k = React.useState(
+ var _k = React.useState(props.factors),
+ factorList = _k[0],
+ setFactorList = _k[1];
+ var _l = React.useState(
(_e = (_d = props.isSignUp) !== null && _d !== void 0 ? _d : isSignUpFromQS) !== null && _e !== void 0
? _e
: st.defaultToSignUp
),
- isSignUp = _k[0],
- setIsSignUp = _k[1];
+ isSignUp = _l[0],
+ setIsSignUp = _l[1];
// We use this to signal that we need to update the components we show on screen
- var _l = React.useState(0),
- rebuildReqCount = _l[0],
- setRebuildReqCount = _l[1];
+ var _m = React.useState(0),
+ rebuildReqCount = _m[0],
+ setRebuildReqCount = _m[1];
var lastBuild = React.useRef({ buildReq: undefined });
React.useEffect(function () {
if (props.useSignUpStateFromQueryString && showStringFromQSRef.current !== showStringFromQS) {
@@ -918,6 +965,46 @@ var AuthPageInner = function (props) {
},
[loadedDynamicLoginMethods, setLoadedDynamicLoginMethods]
);
+ genericComponentOverrideContext.useOnMountAPICall(
+ function () {
+ return genericComponentOverrideContext.__awaiter(void 0, void 0, void 0, function () {
+ var oauth2Recipe;
+ return genericComponentOverrideContext.__generator(this, function (_a) {
+ if (oauth2ClientInfo) {
+ return [2 /*return*/];
+ }
+ oauth2Recipe = recipe.OAuth2Provider.getInstance();
+ if (oauth2Recipe !== undefined && loginChallenge !== null) {
+ return [
+ 2 /*return*/,
+ oauth2Recipe.webJSRecipe.getLoginChallengeInfo({
+ loginChallenge: loginChallenge,
+ userContext: userContext,
+ }),
+ ];
+ }
+ return [2 /*return*/, undefined];
+ });
+ });
+ },
+ function (info) {
+ return genericComponentOverrideContext.__awaiter(void 0, void 0, void 0, function () {
+ return genericComponentOverrideContext.__generator(this, function (_a) {
+ if (info !== undefined) {
+ if (info.status === "OK") {
+ setOAuth2ClientInfo(info.info);
+ } else {
+ setError("SOMETHING_WENT_WRONG_ERROR");
+ }
+ }
+ return [2 /*return*/];
+ });
+ });
+ },
+ function () {
+ return genericComponentOverrideContext.clearQueryParams(["loginChallenge"]);
+ }
+ );
React.useEffect(
function () {
if (sessionLoadedAndNotRedirecting) {
@@ -930,19 +1017,64 @@ var AuthPageInner = function (props) {
if (sessionContext.doesSessionExist) {
if (props.onSessionAlreadyExists !== undefined) {
props.onSessionAlreadyExists();
- } else if (props.redirectOnSessionExists !== false) {
+ } else if (props.redirectOnSessionExists !== false && !forceFreshAuth) {
types.Session.getInstanceOrThrow().config.onHandleEvent({
action: "SESSION_ALREADY_EXISTS",
});
- void types.Session.getInstanceOrThrow()
- .validateGlobalClaimsAndHandleSuccessRedirection(
- undefined,
- types.Session.RECIPE_ID, // TODO
- genericComponentOverrideContext.getRedirectToPathFromURL(),
- userContext,
- props.navigate
- )
- .catch(rethrowInRender);
+ var oauth2Recipe_1 = recipe.OAuth2Provider.getInstance();
+ if (loginChallenge !== null && oauth2Recipe_1 !== undefined) {
+ (function () {
+ return genericComponentOverrideContext.__awaiter(this, void 0, void 0, function () {
+ var frontendRedirectTo;
+ return genericComponentOverrideContext.__generator(this, function (_a) {
+ switch (_a.label) {
+ case 0:
+ return [
+ 4 /*yield*/,
+ oauth2Recipe_1.webJSRecipe.getRedirectURLToContinueOAuthFlow({
+ loginChallenge: loginChallenge,
+ userContext: userContext,
+ }),
+ ];
+ case 1:
+ frontendRedirectTo = _a.sent().frontendRedirectTo;
+ return [
+ 2 /*return*/,
+ types.Session.getInstanceOrThrow().validateGlobalClaimsAndHandleSuccessRedirection(
+ {
+ // We get here if the user was redirected to the auth screen with an already existing session
+ // and a loginChallenge (we check the forceFreshAuth queryparam above)
+ action: "SUCCESS_OAUTH2",
+ frontendRedirectTo: frontendRedirectTo,
+ // We can use these defaults, since this is not the result of a sign in/up call
+ createdNewUser: false,
+ isNewRecipeUser: false,
+ newSessionCreated: false,
+ tenantIdFromQueryParams:
+ genericComponentOverrideContext.getTenantIdFromQueryParams(),
+ recipeId: types.Session.RECIPE_ID,
+ },
+ types.Session.RECIPE_ID,
+ genericComponentOverrideContext.getRedirectToPathFromURL(),
+ userContext,
+ props.navigate
+ ),
+ ];
+ }
+ });
+ });
+ })().catch(rethrowInRender);
+ } else {
+ void types.Session.getInstanceOrThrow()
+ .validateGlobalClaimsAndHandleSuccessRedirection(
+ undefined,
+ types.Session.RECIPE_ID,
+ genericComponentOverrideContext.getRedirectToPathFromURL(),
+ userContext,
+ props.navigate
+ )
+ .catch(rethrowInRender);
+ }
} else {
setSessionLoadedAndNotRedirecting(true);
}
@@ -953,9 +1085,9 @@ var AuthPageInner = function (props) {
},
[sessionContext.loading]
);
- var _m = React.useState(),
- authComponentListInfo = _m[0],
- setAuthComponentListInfo = _m[1];
+ var _o = React.useState(),
+ authComponentListInfo = _o[0],
+ setAuthComponentListInfo = _o[1];
var showUseAnotherLink =
factorList !== undefined &&
(props.factors === undefined ||
@@ -1005,11 +1137,76 @@ var AuthPageInner = function (props) {
rethrowInRender,
]
);
+ var onAuthSuccess = React.useCallback(
+ function (ctx) {
+ return genericComponentOverrideContext.__awaiter(void 0, void 0, void 0, function () {
+ var oauth2Recipe, frontendRedirectTo;
+ return genericComponentOverrideContext.__generator(this, function (_a) {
+ switch (_a.label) {
+ case 0:
+ oauth2Recipe = recipe.OAuth2Provider.getInstance();
+ if (loginChallenge === null || oauth2Recipe === undefined) {
+ return [
+ 2 /*return*/,
+ types.Session.getInstanceOrThrow().validateGlobalClaimsAndHandleSuccessRedirection(
+ genericComponentOverrideContext.__assign(
+ genericComponentOverrideContext.__assign({}, ctx),
+ {
+ action: "SUCCESS",
+ tenantIdFromQueryParams:
+ genericComponentOverrideContext.getTenantIdFromQueryParams(),
+ redirectToPath:
+ genericComponentOverrideContext.getRedirectToPathFromURL(),
+ }
+ ),
+ ctx.recipeId,
+ genericComponentOverrideContext.getRedirectToPathFromURL(),
+ userContext,
+ props.navigate
+ ),
+ ];
+ }
+ return [
+ 4 /*yield*/,
+ oauth2Recipe.webJSRecipe.getRedirectURLToContinueOAuthFlow({
+ loginChallenge: loginChallenge,
+ userContext: userContext,
+ }),
+ ];
+ case 1:
+ frontendRedirectTo = _a.sent().frontendRedirectTo;
+ return [
+ 2 /*return*/,
+ types.Session.getInstanceOrThrow().validateGlobalClaimsAndHandleSuccessRedirection(
+ genericComponentOverrideContext.__assign(
+ genericComponentOverrideContext.__assign({}, ctx),
+ {
+ action: "SUCCESS_OAUTH2",
+ tenantIdFromQueryParams:
+ genericComponentOverrideContext.getTenantIdFromQueryParams(),
+ frontendRedirectTo: frontendRedirectTo,
+ }
+ ),
+ ctx.recipeId,
+ genericComponentOverrideContext.getRedirectToPathFromURL(),
+ userContext,
+ props.navigate
+ ),
+ ];
+ }
+ });
+ });
+ },
+ [loginChallenge]
+ );
var childProps =
- authComponentListInfo !== undefined
+ authComponentListInfo !== undefined &&
+ (loginChallenge === null || oauth2ClientInfo !== undefined || recipe.OAuth2Provider.getInstance() === undefined)
? genericComponentOverrideContext.__assign(
genericComponentOverrideContext.__assign({}, authComponentListInfo),
{
+ oauth2ClientInfo: oauth2ClientInfo,
+ onAuthSuccess: onAuthSuccess,
error: error,
onError: function (err) {
setError(err);
@@ -1166,7 +1363,7 @@ function buildAndSetChildProps(
? void 0
: loadedDynamicLoginMethods.firstFactors) !== null && _a !== void 0
? _a
- : (_b = recipe.MultiFactorAuth.getInstance()) === null || _b === void 0
+ : (_b = recipe$1.MultiFactorAuth.getInstance()) === null || _b === void 0
? void 0
: _b.config.firstFactors) !== null && _c !== void 0
? _c
@@ -1182,7 +1379,7 @@ function buildAndSetChildProps(
(loadedDynamicLoginMethods === null || loadedDynamicLoginMethods === void 0
? void 0
: loadedDynamicLoginMethods.firstFactors) === undefined &&
- ((_d = recipe.MultiFactorAuth.getInstance()) === null || _d === void 0
+ ((_d = recipe$1.MultiFactorAuth.getInstance()) === null || _d === void 0
? void 0
: _d.config.firstFactors) === undefined
) {
@@ -1318,7 +1515,7 @@ function buildAndSetChildProps(
? void 0
: loadedDynamicLoginMethods.firstFactors) !== undefined
? "dynamic tenant configuration"
- : ((_e = recipe.MultiFactorAuth.getInstance()) === null || _e === void 0
+ : ((_e = recipe$1.MultiFactorAuth.getInstance()) === null || _e === void 0
? void 0
: _e.config.firstFactors) !== undefined
? "the config passed to the MFA recipe"
@@ -1613,7 +1810,7 @@ var RecipeRouter = /** @class */ (function () {
if (defaultToStaticList) {
return defaultComp;
}
- var mfaRecipe = recipe.MultiFactorAuth.getInstance();
+ var mfaRecipe = recipe$1.MultiFactorAuth.getInstance();
if (genericComponentOverrideContext.SuperTokens.usesDynamicLoginMethods === false) {
// If we are not using dynamic login methods, we can use the rid requested by the app
if (componentMatchingRid) {
@@ -2566,6 +2763,7 @@ exports.AuthPageHeader = AuthPageHeader;
exports.AuthPageTheme = AuthPageTheme;
exports.BackButton = BackButton;
exports.ComponentOverrideContext = ComponentOverrideContext;
+exports.DynamicLoginMethodsSpinner = DynamicLoginMethodsSpinner;
exports.FeatureWrapper = FeatureWrapper;
exports.GeneralError = GeneralError;
exports.Provider = Provider;
diff --git a/lib/build/multifactorauth-shared.js b/lib/build/multifactorauth-shared.js
index dcbacf133..7b88f6acf 100644
--- a/lib/build/multifactorauth-shared.js
+++ b/lib/build/multifactorauth-shared.js
@@ -2,6 +2,7 @@
var genericComponentOverrideContext = require("./genericComponentOverrideContext.js");
var WebJSSessionRecipe = require("supertokens-web-js/recipe/session");
+var recipe = require("./oauth2provider-shared.js");
var index = require("./recipeModule-shared.js");
var utils = require("supertokens-web-js/utils");
var windowHandler = require("supertokens-web-js/utils/windowHandler");
@@ -350,13 +351,25 @@ var Session = /** @class */ (function (_super) {
createdNewUser: false,
isNewRecipeUser: false,
newSessionCreated: false,
+ tenantIdFromQueryParams: genericComponentOverrideContext.getTenantIdFromQueryParams(),
};
_a.label = 13;
case 13:
if (successRedirectContext === undefined) {
throw new Error("This should never happen: successRedirectContext undefined ");
}
- if (redirectToPath !== undefined) {
+ if (successRedirectContext.action === "SUCCESS_OAUTH2") {
+ return [
+ 2 /*return*/,
+ recipe.OAuth2Provider.getInstanceOrThrow().redirect(
+ successRedirectContext,
+ navigate,
+ {},
+ userContext
+ ),
+ ];
+ }
+ if (successRedirectContext.action === "SUCCESS" && redirectToPath !== undefined) {
successRedirectContext.redirectToPath = redirectToPath;
}
return [
@@ -379,6 +392,7 @@ var Session = /** @class */ (function (_super) {
_this.getDefaultRedirectionURL = function () {
return genericComponentOverrideContext.__awaiter(_this, void 0, void 0, function () {
return genericComponentOverrideContext.__generator(this, function (_a) {
+ // We do not use the util here, since we are redirecting outside of the SDK routes
return [2 /*return*/, "/"];
});
});
diff --git a/lib/build/multifactorauth-shared2.js b/lib/build/multifactorauth-shared2.js
index 708a9f1e9..d5e65825c 100644
--- a/lib/build/multifactorauth-shared2.js
+++ b/lib/build/multifactorauth-shared2.js
@@ -3,7 +3,6 @@
var genericComponentOverrideContext = require("./genericComponentOverrideContext.js");
var MultiFactorAuthWebJS = require("supertokens-web-js/recipe/multifactorauth");
var utils = require("supertokens-web-js/utils");
-var NormalisedURLPath = require("supertokens-web-js/utils/normalisedURLPath");
var postSuperTokensInitCallbacks = require("supertokens-web-js/utils/postSuperTokensInitCallbacks");
var sessionClaimValidatorStore = require("supertokens-web-js/utils/sessionClaimValidatorStore");
var windowHandler = require("supertokens-web-js/utils/windowHandler");
@@ -15,7 +14,6 @@ function _interopDefault(e) {
}
var MultiFactorAuthWebJS__default = /*#__PURE__*/ _interopDefault(MultiFactorAuthWebJS);
-var NormalisedURLPath__default = /*#__PURE__*/ _interopDefault(NormalisedURLPath);
/* Copyright (c) 2024, VRAI Labs and/or its affiliates. All rights reserved.
*
@@ -349,6 +347,23 @@ function normaliseMultiFactorAuthFeature(config) {
);
}
function getAvailableFactors(factors, nextArrayQueryParam, recipe, userContext) {
+ genericComponentOverrideContext.logDebugMessage(
+ "getAvailableFactors: allowed to setup: ".concat(factors.allowedToSetup)
+ );
+ genericComponentOverrideContext.logDebugMessage(
+ "getAvailableFactors: already setup: ".concat(factors.alreadySetup)
+ );
+ genericComponentOverrideContext.logDebugMessage("getAvailableFactors: next from factorInfo: ".concat(factors.next));
+ genericComponentOverrideContext.logDebugMessage(
+ "getAvailableFactors: nextArrayQueryParam: ".concat(nextArrayQueryParam)
+ );
+ genericComponentOverrideContext.logDebugMessage(
+ "getAvailableFactors: secondary factors: ".concat(
+ recipe.getSecondaryFactors(userContext).map(function (f) {
+ return f.id;
+ })
+ )
+ );
// There are 3 cases here:
// 1. The app provided an array of factors to show (nextArrayQueryParam) -> we show whatever is in the array
// 2. no app provided list and validator passed -> we show all factors available to set up or complete
@@ -389,41 +404,42 @@ var MultiFactorAuth = /** @class */ (function (_super) {
_this.secondaryFactors = [];
_this.getDefaultRedirectionURL = function (context, userContext) {
return genericComponentOverrideContext.__awaiter(_this, void 0, void 0, function () {
- var chooserPath, url, queryParams, redirectInfo, url, queryParams;
+ var nParam, redirectInfo;
return genericComponentOverrideContext.__generator(this, function (_b) {
if (context.action === "FACTOR_CHOOSER") {
- chooserPath = new NormalisedURLPath__default.default(DEFAULT_FACTOR_CHOOSER_PATH);
- url = this.config.appInfo.websiteBasePath.appendPath(chooserPath).getAsStringDangerous();
- queryParams = new URLSearchParams();
- if (context.nextFactorOptions && context.nextFactorOptions.length > 0) {
- queryParams.set("n", context.nextFactorOptions.join(","));
- }
- if (context.stepUp) {
- queryParams.set("stepUp", "true");
- }
- if (queryParams.toString() !== "") {
- url += "?" + queryParams.toString();
- }
- return [2 /*return*/, url];
+ nParam =
+ context.nextFactorOptions && context.nextFactorOptions.length > 0
+ ? context.nextFactorOptions.join(",")
+ : undefined;
+ return [
+ 2 /*return*/,
+ genericComponentOverrideContext.getDefaultRedirectionURLForPath(
+ this.config,
+ DEFAULT_FACTOR_CHOOSER_PATH,
+ context,
+ {
+ n: nParam,
+ stepUp: context.stepUp ? "true" : undefined,
+ }
+ ),
+ ];
} else if (context.action === "GO_TO_FACTOR") {
redirectInfo = this.getSecondaryFactors(userContext).find(function (f) {
return f.id === context.factorId;
});
if (redirectInfo !== undefined) {
- url = this.config.appInfo.websiteBasePath
- .appendPath(new NormalisedURLPath__default.default(redirectInfo.path))
- .getAsStringDangerous();
- queryParams = new URLSearchParams();
- if (context.forceSetup) {
- queryParams.set("setup", "true");
- }
- if (context.stepUp) {
- queryParams.set("stepUp", "true");
- }
- if (queryParams.toString() !== "") {
- url += "?" + queryParams.toString();
- }
- return [2 /*return*/, url];
+ return [
+ 2 /*return*/,
+ genericComponentOverrideContext.getDefaultRedirectionURLForPath(
+ this.config,
+ redirectInfo.path,
+ context,
+ {
+ setup: context.forceSetup ? "true" : undefined,
+ stepUp: context.stepUp ? "true" : undefined,
+ }
+ ),
+ ];
}
throw new Error("Requested redirect to unknown factor id: " + context.factorId);
} else {
@@ -526,7 +542,14 @@ var MultiFactorAuth = /** @class */ (function (_super) {
return [
4 /*yield*/,
this.getRedirectUrl(
- { action: "GO_TO_FACTOR", forceSetup: forceSetup, stepUp: stepUp, factorId: factorId },
+ {
+ action: "GO_TO_FACTOR",
+ forceSetup: forceSetup,
+ stepUp: stepUp,
+ factorId: factorId,
+ tenantIdFromQueryParams:
+ genericComponentOverrideContext.getTenantIdFromQueryParams(),
+ },
utils.getNormalisedUserContext(userContext)
),
];
@@ -587,7 +610,13 @@ var MultiFactorAuth = /** @class */ (function (_super) {
return [
4 /*yield*/,
this.getRedirectUrl(
- { action: "FACTOR_CHOOSER", nextFactorOptions: nextFactorOptions, stepUp: stepUp },
+ {
+ action: "FACTOR_CHOOSER",
+ nextFactorOptions: nextFactorOptions,
+ stepUp: stepUp,
+ tenantIdFromQueryParams:
+ genericComponentOverrideContext.getTenantIdFromQueryParams(),
+ },
utils.getNormalisedUserContext(userContext)
),
];
@@ -643,7 +672,19 @@ var MultiFactorAuth = /** @class */ (function (_super) {
return genericComponentOverrideContext.__generator(_a, function (_b) {
switch (_b.label) {
case 0:
- return [4 /*yield*/, this.getInstanceOrThrow().getRedirectUrl(context, userContext)];
+ return [
+ 4 /*yield*/,
+ this.getInstanceOrThrow().getRedirectUrl(
+ genericComponentOverrideContext.__assign(
+ genericComponentOverrideContext.__assign({}, context),
+ {
+ tenantIdFromQueryParams:
+ genericComponentOverrideContext.getTenantIdFromQueryParams(),
+ }
+ ),
+ userContext
+ ),
+ ];
case 1:
return [2 /*return*/, _b.sent() || undefined];
}
diff --git a/lib/build/multifactorauth.js b/lib/build/multifactorauth.js
index ab535c278..c837953b2 100644
--- a/lib/build/multifactorauth.js
+++ b/lib/build/multifactorauth.js
@@ -20,6 +20,8 @@ require("supertokens-web-js/recipe/multifactorauth");
require("supertokens-web-js/utils/sessionClaimValidatorStore");
require("./recipeModule-shared.js");
require("supertokens-web-js/recipe/session");
+require("./oauth2provider-shared.js");
+require("supertokens-web-js/recipe/oauth2provider");
/* Copyright (c) 2024, VRAI Labs and/or its affiliates. All rights reserved.
*
diff --git a/lib/build/multifactorauthprebuiltui.js b/lib/build/multifactorauthprebuiltui.js
index 83d04b517..7685444ea 100644
--- a/lib/build/multifactorauthprebuiltui.js
+++ b/lib/build/multifactorauthprebuiltui.js
@@ -21,11 +21,13 @@ require("supertokens-web-js/utils");
require("supertokens-web-js/utils/normalisedURLDomain");
require("react-dom");
require("./multitenancy-shared.js");
+require("./oauth2provider-shared.js");
+require("supertokens-web-js/recipe/oauth2provider");
+require("./recipeModule-shared.js");
require("./authRecipe-shared.js");
require("supertokens-web-js/lib/build/normalisedURLPath");
require("supertokens-web-js/recipe/session");
require("./session-shared.js");
-require("./recipeModule-shared.js");
require("supertokens-web-js/recipe/multifactorauth");
require("supertokens-web-js/utils/sessionClaimValidatorStore");
@@ -63,7 +65,7 @@ var NormalisedURLPath__default = /*#__PURE__*/ _interopDefault(NormalisedURLPath
var React__namespace = /*#__PURE__*/ _interopNamespace(React);
var styles =
- '[data-supertokens~="container"] {\n --palette-background: 255, 255, 255;\n --palette-inputBackground: 250, 250, 250;\n --palette-inputBorder: 224, 224, 224;\n --palette-primary: 28, 34, 42;\n --palette-primaryBorder: 45, 54, 68;\n --palette-success: 65, 167, 0;\n --palette-successBackground: 217, 255, 191;\n --palette-error: 255, 23, 23;\n --palette-errorBackground: 255, 241, 235;\n --palette-textTitle: 0, 0, 0;\n --palette-textLabel: 0, 0, 0;\n --palette-textInput: 0, 0, 0;\n --palette-textPrimary: 128, 128, 128;\n --palette-textLink: 0, 122, 255;\n --palette-buttonText: 255, 255, 255;\n --palette-textGray: 54, 54, 54;\n --palette-superTokensBrandingBackground: 242, 245, 246;\n --palette-superTokensBrandingText: 173, 189, 196;\n\n --font-size-0: 12px;\n --font-size-1: 14px;\n --font-size-2: 16px;\n --font-size-3: 19px;\n --font-size-4: 24px;\n --font-size-5: 28px;\n}\n/*\n * Default styles.\n */\n@keyframes slideTop {\n 0% {\n transform: translateY(-5px);\n }\n 100% {\n transform: translateY(0px);\n }\n}\n@keyframes swing-in-top-fwd {\n 0% {\n transform: rotateX(-100deg);\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n transform: rotateX(0deg);\n transform-origin: top;\n opacity: 1;\n }\n}\n[data-supertokens~="container"] {\n font-family: "Arial", sans-serif;\n margin: 12px auto;\n margin-top: 26px;\n margin-bottom: 26px;\n width: 420px;\n text-align: center;\n border-radius: 8px;\n box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.16);\n background-color: rgb(var(--palette-background));\n}\n@media (max-width: 440px) {\n [data-supertokens~="container"] {\n width: 95vw;\n }\n}\n[data-supertokens~="row"] {\n margin: 0 auto;\n width: 76%;\n padding-top: 30px;\n padding-bottom: 10px;\n}\n[data-supertokens~="superTokensBranding"] {\n display: block;\n margin: 10px auto 0;\n background: rgb(var(--palette-superTokensBrandingBackground));\n color: rgb(var(--palette-superTokensBrandingText));\n text-decoration: none;\n width: -webkit-fit-content;\n width: -moz-fit-content;\n width: fit-content;\n border-radius: 6px 6px 0 0;\n padding: 4px 9px;\n font-weight: 400;\n font-size: var(--font-size-0);\n letter-spacing: 0.4px;\n}\n[data-supertokens~="generalError"] {\n background: rgb(var(--palette-errorBackground));\n padding-top: 10px;\n padding-bottom: 10px;\n margin-bottom: 10px;\n margin-top: 24px;\n padding-left: 18px;\n padding-right: 18px;\n letter-spacing: 0.2px;\n font-size: var(--font-size-1);\n border-radius: 8px;\n color: rgb(var(--palette-error));\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n word-wrap: break-word;\n}\n[data-supertokens~="headerTitle"] {\n font-size: var(--font-size-4);\n line-height: 27.6px;\n letter-spacing: 0.58px;\n font-weight: 700;\n margin-bottom: 20px;\n color: rgb(var(--palette-textTitle));\n}\n[data-supertokens~="headerSubtitle"] {\n font-weight: 400;\n color: rgb(var(--palette-textGray));\n margin-bottom: 21px;\n}\n[data-supertokens~="headerSubtitle"][data-supertokens~="secondaryText"] {\n color: rgb(var(--palette-textGray));\n font-weight: 400;\n}\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] {\n max-width: 300px;\n margin-top: 10px;\n}\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] a {\n line-height: 21px;\n}\n/* TODO: split the link style into separate things*/\n/* We add this before primary and secondary text, because if they are applied to the same element the other ones take priority */\n[data-supertokens~="link"] {\n padding-left: 3px;\n padding-right: 3px;\n color: rgb(var(--palette-textLink));\n font-size: var(--font-size-1);\n cursor: pointer;\n letter-spacing: 0.16px;\n line-height: 26px;\n}\n[data-supertokens~="primaryText"] {\n font-size: var(--font-size-2);\n font-weight: 400;\n letter-spacing: 0.4px;\n line-height: 21px;\n color: rgb(var(--palette-textLabel));\n}\n[data-supertokens~="secondaryText"] {\n font-size: var(--font-size-1);\n font-weight: 400;\n letter-spacing: 0.4px;\n color: rgb(var(--palette-textPrimary));\n}\n[data-supertokens~="secondaryText"] strong {\n font-weight: 600;\n}\n[data-supertokens~="divider"] {\n margin-top: 1.5em;\n margin-bottom: 1.5em;\n border-bottom: 0.3px solid #dddddd;\n align-items: center;\n padding-bottom: 5px;\n flex: 3 3;\n}\n[data-supertokens~="headerTinyTitle"] {\n margin-top: 24px;\n font-size: var(--font-size-5);\n letter-spacing: 1.1px;\n font-weight: 700;\n line-height: 28px;\n}\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithArrow"]:hover {\n position: relative;\n left: 2px;\n word-spacing: 4px;\n}\n[data-supertokens~="generalSuccess"] {\n color: rgb(var(--palette-success));\n font-size: var(--font-size-1);\n background: rgb(var(--palette-successBackground));\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n padding: 9px 15px 9px 15px;\n border-radius: 6px;\n display: inline-block;\n}\n[data-supertokens~="spinner"] {\n width: 80px;\n height: auto;\n padding-top: 20px;\n padding-bottom: 40px;\n margin: 0 auto;\n}\n[data-supertokens~="error"] {\n color: rgb(var(--palette-error));\n}\n[data-supertokens~="linkButton"] {\n font-family: "Arial", sans-serif;\n background-color: transparent;\n border: 0;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"] {\n color: rgb(var(--palette-textGray));\n font-weight: 400;\n margin-top: 10px;\n margin-bottom: 40px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n margin-right: 0.3em;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"]:hover svg {\n position: relative;\n left: -4px;\n}\n[data-supertokens~="button"] {\n font-family: "Arial", sans-serif;\n background-color: rgb(var(--palette-primary));\n color: rgb(var(--palette-buttonText));\n width: 100%;\n height: 34px;\n font-weight: 600;\n border-width: 1px;\n border-style: solid;\n border-radius: 6px;\n border-color: rgb(var(--palette-primaryBorder));\n background-position: center;\n transition: all 0.4s;\n background-size: 12000%;\n cursor: pointer;\n}\n[data-supertokens~="button"]:disabled {\n border: none;\n cursor: no-drop;\n}\n[data-supertokens~="button"]:active {\n outline: none;\n transition: all 0s;\n background-size: 100%;\n filter: brightness(0.85);\n}\n[data-supertokens~="button"]:focus {\n outline: none;\n}\n[data-supertokens~="backButtonCommon"] {\n width: 16px;\n height: 13px;\n}\n[data-supertokens~="backButton"] {\n cursor: pointer;\n border: none;\n background-color: transparent;\n padding: 0px;\n}\n[data-supertokens~="backButtonPlaceholder"] {\n display: block;\n}\n[data-supertokens~="delayedRender"] {\n animation-duration: 0.1s;\n animation-name: animate-fade;\n animation-delay: 0.2s;\n animation-fill-mode: backwards;\n}\n@keyframes animate-fade {\n 0% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n}\n[data-supertokens~="footerLinkGroupVert"] {\n display: flex;\n flex-direction: column;\n margin-top: 10px;\n gap: 24px;\n}\n[data-supertokens~="footerLinkGroupVert"] > div {\n cursor: pointer;\n margin: 0;\n}\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryText"] {\n font-weight: 400;\n}\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n font-weight: 400;\n position: relative;\n left: -6px; /* half the width of the left arrow */\n}\n@media (max-width: 360px) {\n [data-supertokens~="footerLinkGroupVert"] {\n flex-direction: column;\n }\n [data-supertokens~="footerLinkGroupVert"] > div {\n margin: 0 auto;\n }\n}\n[data-supertokens~="footerLinkGroupVert"] div:only-child {\n margin-left: auto;\n margin-right: auto;\n margin-top: 14px;\n}\n[data-supertokens~="withBackButton"] {\n position: relative;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n[data-supertokens~="dividerWithOr"] {\n padding-top: 5px;\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n color: rgb(var(--palette-textPrimary));\n}\n[data-supertokens~="dividerText"] {\n flex: 1 1;\n font-weight: 400;\n font-size: var(--font-size-1);\n}\n[data-supertokens~="formLabelWithLinkWrapper"] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n[data-supertokens~="formLabelLinkBtn"] {\n width: auto;\n margin-top: 0;\n line-height: 24px;\n font-size: var(--font-size-0);\n}\n[data-supertokens~="formLabelLinkBtn"]:hover {\n text-decoration: underline;\n}\n[data-supertokens~="formLabelLinkBtn"]:disabled {\n color: rgb(var(--palette-textPrimary));\n cursor: default;\n text-decoration: none;\n}\n[data-supertokens~="authComponentList"] {\n padding-bottom: 20px;\n}\n[data-supertokens~="buttonWithArrow"] {\n border-radius: 6px;\n border: 1px solid #d0d5dd;\n width: 100%;\n color: rgb(var(--palette-textGray));\n display: flex;\n justify-content: center;\n align-items: center;\n gap: 5px;\n margin: 24px 0;\n min-height: 48px;\n cursor: pointer;\n}\n[data-supertokens~="buttonWithArrow"]:hover {\n background-color: rgb(var(--palette-inputBackground));\n}\n[data-supertokens~="buttonWithArrow"] [data-supertokens~="secondaryText"] {\n font-weight: 700;\n font-size: var(--font-size-2);\n color: rgb(var(--palette-textGray));\n margin: 0;\n}\n[data-supertokens~="buttonWithArrow"]:hover [data-supertokens~="secondaryLinkWithRightArrow"] ~ svg {\n position: relative;\n left: 2px;\n}\n[data-supertokens~="buttonWithArrow"]:hover [data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n position: relative;\n left: -2px;\n}\n[data-supertokens~="buttonWithArrow"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n display: flex;\n align-items: center;\n}\n[data-supertokens~="mfa"][data-supertokens~="container"] {\n padding-top: 34px;\n}\n[data-supertokens~="mfa"] [data-supertokens~="row"] {\n padding-top: 6px;\n padding-bottom: 6px;\n}\n[data-supertokens~="mfa"] [data-supertokens~="headerTitle"] {\n font-size: var(--font-size-3);\n font-weight: 600;\n line-height: 30px;\n}\n[data-supertokens~="mfa"] [data-supertokens~="factorChooserList"] {\n margin-bottom: 12px;\n}\n[data-supertokens~="factorChooserOption"] {\n display: flex;\n flex-direction: row;\n border-radius: 6px;\n border: 1px solid rgb(var(--palette-inputBorder));\n padding: 20px 16px;\n cursor: pointer;\n margin-top: 12px;\n}\n[data-supertokens~="factorChooserOption"]:hover {\n border: 1px solid rgba(var(--palette-primary), 0.6);\n}\n[data-supertokens~="factorOptionText"] {\n flex-grow: 1;\n display: flex;\n flex-direction: column;\n align-items: start;\n text-align: left;\n}\n[data-supertokens~="factorLogo"] {\n flex-grow: 0;\n min-width: 30px;\n text-align: left;\n margin-top: 6px;\n}\n[data-supertokens~="totp"] [data-supertokens~="factorLogo"] {\n margin-top: 3px;\n margin-left: -1px;\n}\n[data-supertokens~="factorName"] {\n color: rgb(var(--palette-primary));\n font-size: var(--font-size-1);\n font-weight: 400;\n margin: 4px;\n}\n[data-supertokens~="factorDescription"] {\n color: rgb(var(--palette-textPrimary));\n font-size: var(--font-size-0);\n margin: 4px;\n}\n[data-supertokens~="mfa"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n margin-bottom: 26px;\n text-align: right;\n}\n';
+ '[data-supertokens~="container"] {\n --palette-background: 255, 255, 255;\n --palette-inputBackground: 250, 250, 250;\n --palette-inputBorder: 224, 224, 224;\n --palette-primary: 28, 34, 42;\n --palette-primaryBorder: 45, 54, 68;\n --palette-success: 65, 167, 0;\n --palette-successBackground: 217, 255, 191;\n --palette-error: 255, 23, 23;\n --palette-errorBackground: 255, 241, 235;\n --palette-textTitle: 0, 0, 0;\n --palette-textLabel: 0, 0, 0;\n --palette-textInput: 0, 0, 0;\n --palette-textPrimary: 128, 128, 128;\n --palette-textLink: 0, 122, 255;\n --palette-buttonText: 255, 255, 255;\n --palette-textGray: 54, 54, 54;\n --palette-superTokensBrandingBackground: 242, 245, 246;\n --palette-superTokensBrandingText: 173, 189, 196;\n\n --font-size-0: 12px;\n --font-size-1: 14px;\n --font-size-2: 16px;\n --font-size-3: 19px;\n --font-size-4: 24px;\n --font-size-5: 28px;\n}\n/*\n * Default styles.\n */\n@keyframes slideTop {\n 0% {\n transform: translateY(-5px);\n }\n 100% {\n transform: translateY(0px);\n }\n}\n@keyframes swing-in-top-fwd {\n 0% {\n transform: rotateX(-100deg);\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n transform: rotateX(0deg);\n transform-origin: top;\n opacity: 1;\n }\n}\n[data-supertokens~="container"] {\n font-family: "Arial", sans-serif;\n margin: 12px auto;\n margin-top: 26px;\n margin-bottom: 26px;\n width: 420px;\n text-align: center;\n border-radius: 8px;\n box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.16);\n background-color: rgb(var(--palette-background));\n}\n@media (max-width: 440px) {\n [data-supertokens~="container"] {\n width: 95vw;\n }\n}\n[data-supertokens~="row"] {\n margin: 0 auto;\n width: 76%;\n padding-top: 30px;\n padding-bottom: 10px;\n}\n[data-supertokens~="superTokensBranding"] {\n display: block;\n margin: 10px auto 0;\n background: rgb(var(--palette-superTokensBrandingBackground));\n color: rgb(var(--palette-superTokensBrandingText));\n text-decoration: none;\n width: -webkit-fit-content;\n width: -moz-fit-content;\n width: fit-content;\n border-radius: 6px 6px 0 0;\n padding: 4px 9px;\n font-weight: 400;\n font-size: var(--font-size-0);\n letter-spacing: 0.4px;\n}\n[data-supertokens~="generalError"] {\n background: rgb(var(--palette-errorBackground));\n padding-top: 10px;\n padding-bottom: 10px;\n margin-bottom: 10px;\n margin-top: 24px;\n padding-left: 18px;\n padding-right: 18px;\n letter-spacing: 0.2px;\n font-size: var(--font-size-1);\n border-radius: 8px;\n color: rgb(var(--palette-error));\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n word-wrap: break-word;\n}\n[data-supertokens~="headerTitle"] {\n font-size: var(--font-size-4);\n line-height: 27.6px;\n letter-spacing: 0.58px;\n font-weight: 700;\n margin-bottom: 20px;\n color: rgb(var(--palette-textTitle));\n}\n[data-supertokens~="headerSubtitle"] {\n font-weight: 400;\n color: rgb(var(--palette-textGray));\n margin-bottom: 21px;\n}\n[data-supertokens~="headerSubtitle"][data-supertokens~="secondaryText"] {\n color: rgb(var(--palette-textGray));\n font-weight: 400;\n}\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] {\n max-width: 300px;\n margin-top: 10px;\n}\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] a {\n line-height: 21px;\n}\n/* TODO: split the link style into separate things*/\n/* We add this before primary and secondary text, because if they are applied to the same element the other ones take priority */\n[data-supertokens~="link"] {\n padding-left: 3px;\n padding-right: 3px;\n color: rgb(var(--palette-textLink));\n font-size: var(--font-size-1);\n cursor: pointer;\n letter-spacing: 0.16px;\n line-height: 26px;\n}\n[data-supertokens~="primaryText"] {\n font-size: var(--font-size-2);\n font-weight: 400;\n letter-spacing: 0.4px;\n line-height: 21px;\n color: rgb(var(--palette-textLabel));\n}\n[data-supertokens~="secondaryText"] {\n font-size: var(--font-size-1);\n font-weight: 400;\n letter-spacing: 0.4px;\n color: rgb(var(--palette-textPrimary));\n}\n[data-supertokens~="secondaryText"] strong {\n font-weight: 600;\n}\n[data-supertokens~="divider"] {\n margin-top: 1.5em;\n margin-bottom: 1.5em;\n border-bottom: 0.3px solid #dddddd;\n align-items: center;\n padding-bottom: 5px;\n flex: 3 3;\n}\n[data-supertokens~="headerTinyTitle"] {\n margin-top: 24px;\n font-size: var(--font-size-5);\n letter-spacing: 1.1px;\n font-weight: 700;\n line-height: 28px;\n}\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithArrow"]:hover {\n position: relative;\n left: 2px;\n word-spacing: 4px;\n}\n[data-supertokens~="generalSuccess"] {\n color: rgb(var(--palette-success));\n font-size: var(--font-size-1);\n background: rgb(var(--palette-successBackground));\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n padding: 9px 15px 9px 15px;\n border-radius: 6px;\n display: inline-block;\n}\n[data-supertokens~="spinner"] {\n width: 80px;\n height: auto;\n padding-top: 20px;\n padding-bottom: 40px;\n margin: 0 auto;\n}\n[data-supertokens~="error"] {\n color: rgb(var(--palette-error));\n}\n[data-supertokens~="linkButton"] {\n font-family: "Arial", sans-serif;\n background-color: transparent;\n border: 0;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"] {\n color: rgb(var(--palette-textGray));\n font-weight: 400;\n margin-top: 10px;\n margin-bottom: 40px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n margin-right: 0.3em;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"]:hover svg {\n position: relative;\n left: -4px;\n}\n[data-supertokens~="button"] {\n font-family: "Arial", sans-serif;\n background-color: rgb(var(--palette-primary));\n color: rgb(var(--palette-buttonText));\n width: 100%;\n height: 34px;\n font-weight: 600;\n border-width: 1px;\n border-style: solid;\n border-radius: 6px;\n border-color: rgb(var(--palette-primaryBorder));\n background-position: center;\n transition: all 0.4s;\n background-size: 12000%;\n cursor: pointer;\n}\n[data-supertokens~="button"]:disabled {\n border: none;\n cursor: no-drop;\n}\n[data-supertokens~="button"]:active {\n outline: none;\n transition: all 0s;\n background-size: 100%;\n filter: brightness(0.85);\n}\n[data-supertokens~="button"]:focus {\n outline: none;\n}\n[data-supertokens~="backButtonCommon"] {\n width: 16px;\n height: 13px;\n}\n[data-supertokens~="backButton"] {\n cursor: pointer;\n border: none;\n background-color: transparent;\n padding: 0px;\n}\n[data-supertokens~="backButtonPlaceholder"] {\n display: block;\n}\n[data-supertokens~="delayedRender"] {\n animation-duration: 0.1s;\n animation-name: animate-fade;\n animation-delay: 0.2s;\n animation-fill-mode: backwards;\n}\n@keyframes animate-fade {\n 0% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n}\n[data-supertokens~="footerLinkGroupVert"] {\n display: flex;\n flex-direction: column;\n margin-top: 10px;\n gap: 24px;\n}\n[data-supertokens~="footerLinkGroupVert"] > div {\n cursor: pointer;\n margin: 0;\n}\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryText"] {\n font-weight: 400;\n}\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n font-weight: 400;\n position: relative;\n left: -6px; /* half the width of the left arrow */\n}\n@media (max-width: 360px) {\n [data-supertokens~="footerLinkGroupVert"] {\n flex-direction: column;\n }\n [data-supertokens~="footerLinkGroupVert"] > div {\n margin: 0 auto;\n }\n}\n[data-supertokens~="footerLinkGroupVert"] div:only-child {\n margin-left: auto;\n margin-right: auto;\n margin-top: 14px;\n}\n[data-supertokens~="withBackButton"] {\n position: relative;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n[data-supertokens~="dividerWithOr"] {\n padding-top: 5px;\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n color: rgb(var(--palette-textPrimary));\n}\n[data-supertokens~="dividerText"] {\n flex: 1 1;\n font-weight: 400;\n font-size: var(--font-size-1);\n}\n[data-supertokens~="formLabelWithLinkWrapper"] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n[data-supertokens~="formLabelLinkBtn"] {\n width: auto;\n margin-top: 0;\n line-height: 24px;\n font-size: var(--font-size-0);\n}\n[data-supertokens~="formLabelLinkBtn"]:hover {\n text-decoration: underline;\n}\n[data-supertokens~="formLabelLinkBtn"]:disabled {\n color: rgb(var(--palette-textPrimary));\n cursor: default;\n text-decoration: none;\n}\n[data-supertokens~="authComponentList"] {\n padding-bottom: 20px;\n}\n[data-supertokens~="authPageTitleOAuthClient"] {\n color: rgb(var(--palette-textGray));\n font-size: var(--font-size-1);\n font-weight: 400;\n margin: 10px 0 25px;\n}\n[data-supertokens~="authPageTitleOAuthClientUrl"] {\n text-decoration: none;\n}\n[data-supertokens~="authPageTitleOAuthClientLogo"] {\n width: 44px;\n height: 44px;\n margin-bottom: 10px;\n}\n[data-supertokens~="authPageTitleOAuthClient"] [data-supertokens~="authPageTitleOAuthClientName"] {\n color: rgb(var(--palette-textTitle));\n}\n[data-supertokens~="buttonWithArrow"] {\n border-radius: 6px;\n border: 1px solid #d0d5dd;\n width: 100%;\n color: rgb(var(--palette-textGray));\n display: flex;\n justify-content: center;\n align-items: center;\n gap: 5px;\n margin: 24px 0;\n min-height: 48px;\n cursor: pointer;\n}\n[data-supertokens~="buttonWithArrow"]:hover {\n background-color: rgb(var(--palette-inputBackground));\n}\n[data-supertokens~="buttonWithArrow"] [data-supertokens~="secondaryText"] {\n font-weight: 700;\n font-size: var(--font-size-2);\n color: rgb(var(--palette-textGray));\n margin: 0;\n}\n[data-supertokens~="buttonWithArrow"]:hover [data-supertokens~="secondaryLinkWithRightArrow"] ~ svg {\n position: relative;\n left: 2px;\n}\n[data-supertokens~="buttonWithArrow"]:hover [data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n position: relative;\n left: -2px;\n}\n[data-supertokens~="buttonWithArrow"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n display: flex;\n align-items: center;\n}\n[data-supertokens~="mfa"][data-supertokens~="container"] {\n padding-top: 34px;\n}\n[data-supertokens~="mfa"] [data-supertokens~="row"] {\n padding-top: 6px;\n padding-bottom: 6px;\n}\n[data-supertokens~="mfa"] [data-supertokens~="headerTitle"] {\n font-size: var(--font-size-3);\n font-weight: 600;\n line-height: 30px;\n}\n[data-supertokens~="mfa"] [data-supertokens~="factorChooserList"] {\n margin-bottom: 12px;\n}\n[data-supertokens~="factorChooserOption"] {\n display: flex;\n flex-direction: row;\n border-radius: 6px;\n border: 1px solid rgb(var(--palette-inputBorder));\n padding: 20px 16px;\n cursor: pointer;\n margin-top: 12px;\n}\n[data-supertokens~="factorChooserOption"]:hover {\n border: 1px solid rgba(var(--palette-primary), 0.6);\n}\n[data-supertokens~="factorOptionText"] {\n flex-grow: 1;\n display: flex;\n flex-direction: column;\n align-items: start;\n text-align: left;\n}\n[data-supertokens~="factorLogo"] {\n flex-grow: 0;\n min-width: 30px;\n text-align: left;\n margin-top: 6px;\n}\n[data-supertokens~="totp"] [data-supertokens~="factorLogo"] {\n margin-top: 3px;\n margin-left: -1px;\n}\n[data-supertokens~="factorName"] {\n color: rgb(var(--palette-primary));\n font-size: var(--font-size-1);\n font-weight: 400;\n margin: 4px;\n}\n[data-supertokens~="factorDescription"] {\n color: rgb(var(--palette-textPrimary));\n font-size: var(--font-size-0);\n margin: 4px;\n}\n[data-supertokens~="mfa"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n margin-bottom: 26px;\n text-align: right;\n}\n';
var ThemeBase = function (_a) {
var children = _a.children,
diff --git a/lib/build/oauth2provider-shared.js b/lib/build/oauth2provider-shared.js
new file mode 100644
index 000000000..27f1e02ea
--- /dev/null
+++ b/lib/build/oauth2provider-shared.js
@@ -0,0 +1,197 @@
+"use strict";
+
+var genericComponentOverrideContext = require("./genericComponentOverrideContext.js");
+var OAuth2WebJS = require("supertokens-web-js/recipe/oauth2provider");
+var index = require("./recipeModule-shared.js");
+
+function _interopDefault(e) {
+ return e && e.__esModule ? e : { default: e };
+}
+
+var OAuth2WebJS__default = /*#__PURE__*/ _interopDefault(OAuth2WebJS);
+
+var getFunctionOverrides = function (onHandleEvent) {
+ return function (originalImp) {
+ return genericComponentOverrideContext.__assign(genericComponentOverrideContext.__assign({}, originalImp), {
+ getLoginChallengeInfo: function (input) {
+ return genericComponentOverrideContext.__awaiter(this, void 0, void 0, function () {
+ var response;
+ return genericComponentOverrideContext.__generator(this, function (_a) {
+ switch (_a.label) {
+ case 0:
+ return [4 /*yield*/, originalImp.getLoginChallengeInfo(input)];
+ case 1:
+ response = _a.sent();
+ onHandleEvent({
+ action: "LOADED_LOGIN_CHALLENGE",
+ loginChallenge: input.loginChallenge,
+ loginInfo: response.info,
+ userContext: input.userContext,
+ });
+ return [2 /*return*/, response];
+ }
+ });
+ });
+ },
+ logOut: function (input) {
+ return genericComponentOverrideContext.__awaiter(this, void 0, void 0, function () {
+ var response;
+ return genericComponentOverrideContext.__generator(this, function (_a) {
+ switch (_a.label) {
+ case 0:
+ return [4 /*yield*/, originalImp.logOut(input)];
+ case 1:
+ response = _a.sent();
+ onHandleEvent({
+ action: "OAUTH2_LOGOUT_SUCCESS",
+ frontendRedirectTo: response.frontendRedirectTo,
+ userContext: input.userContext,
+ });
+ return [2 /*return*/, response];
+ }
+ });
+ });
+ },
+ });
+ };
+};
+
+function normaliseOAuth2Config(config) {
+ var _a;
+ return genericComponentOverrideContext.__assign(
+ genericComponentOverrideContext.__assign(
+ {},
+ genericComponentOverrideContext.normaliseRecipeModuleConfig(config)
+ ),
+ {
+ disableDefaultUI:
+ (_a = config === null || config === void 0 ? void 0 : config.disableDefaultUI) !== null && _a !== void 0
+ ? _a
+ : false,
+ tryRefreshPage: genericComponentOverrideContext.__assign(
+ { disableDefaultUI: false },
+ config === null || config === void 0 ? void 0 : config.tryRefreshPage
+ ),
+ oauth2LogoutScreen: genericComponentOverrideContext.__assign(
+ { disableDefaultUI: false, style: "" },
+ config === null || config === void 0 ? void 0 : config.oauth2LogoutScreen
+ ),
+ override: genericComponentOverrideContext.__assign(
+ {
+ functions: function (originalImplementation) {
+ return originalImplementation;
+ },
+ },
+ config === null || config === void 0 ? void 0 : config.override
+ ),
+ }
+ );
+}
+
+/* Copyright (c) 2024, VRAI Labs and/or its affiliates. All rights reserved.
+ *
+ * This software is licensed under the Apache License, Version 2.0 (the
+ * "License") as published by the Apache Software Foundation.
+ *
+ * You may not use this file except in compliance with the License. You may
+ * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+/*
+ * Class.
+ */
+var OAuth2Provider = /** @class */ (function (_super) {
+ genericComponentOverrideContext.__extends(OAuth2Provider, _super);
+ function OAuth2Provider(config, webJSRecipe) {
+ if (webJSRecipe === void 0) {
+ webJSRecipe = OAuth2WebJS__default.default;
+ }
+ var _this = _super.call(this, config) || this;
+ _this.webJSRecipe = webJSRecipe;
+ _this.recipeID = OAuth2Provider.RECIPE_ID;
+ return _this;
+ }
+ OAuth2Provider.init = function (config) {
+ var normalisedConfig = normaliseOAuth2Config(config);
+ return {
+ recipeID: OAuth2Provider.RECIPE_ID,
+ authReact: function (appInfo) {
+ OAuth2Provider.instance = new OAuth2Provider(
+ genericComponentOverrideContext.__assign(
+ genericComponentOverrideContext.__assign({}, normalisedConfig),
+ { appInfo: appInfo, recipeId: OAuth2Provider.RECIPE_ID }
+ )
+ );
+ return OAuth2Provider.instance;
+ },
+ webJS: OAuth2WebJS__default.default.init(
+ genericComponentOverrideContext.__assign(
+ genericComponentOverrideContext.__assign({}, normalisedConfig),
+ {
+ override: {
+ functions: function (originalImpl, builder) {
+ var functions = getFunctionOverrides(normalisedConfig.onHandleEvent);
+ builder.override(functions);
+ builder.override(normalisedConfig.override.functions);
+ return originalImpl;
+ },
+ },
+ }
+ )
+ ),
+ };
+ };
+ OAuth2Provider.getInstanceOrThrow = function () {
+ if (OAuth2Provider.instance === undefined) {
+ var error =
+ "No instance of OAuth2Provider found. Make sure to call the OAuth2Provider.init method." +
+ "See https://supertokens.io/docs/oauth2/quick-setup/frontend";
+ // eslint-disable-next-line supertokens-auth-react/no-direct-window-object
+ if (typeof window === "undefined") {
+ error = error + genericComponentOverrideContext.SSR_ERROR;
+ }
+ throw Error(error);
+ }
+ return OAuth2Provider.instance;
+ };
+ OAuth2Provider.getInstance = function () {
+ return OAuth2Provider.instance;
+ };
+ OAuth2Provider.prototype.getDefaultRedirectionURL = function (ctx) {
+ return genericComponentOverrideContext.__awaiter(this, void 0, void 0, function () {
+ return genericComponentOverrideContext.__generator(this, function (_a) {
+ // We do not use the util here, because we are likely redirecting across domains here.
+ if (
+ ctx.action === "SUCCESS_OAUTH2" ||
+ ctx.action === "CONTINUE_OAUTH2_AFTER_REFRESH" ||
+ ctx.action === "POST_OAUTH2_LOGOUT_REDIRECT"
+ ) {
+ return [2 /*return*/, ctx.frontendRedirectTo];
+ } else {
+ throw new Error(
+ "Should never come here: unknown action in OAuth2Provider.getDefaultRedirectionURL"
+ );
+ }
+ });
+ });
+ };
+ /*
+ * Tests methods.
+ */
+ OAuth2Provider.reset = function () {
+ if (!genericComponentOverrideContext.isTest()) {
+ return;
+ }
+ OAuth2Provider.instance = undefined;
+ return;
+ };
+ OAuth2Provider.RECIPE_ID = "oauth2provider";
+ return OAuth2Provider;
+})(index.RecipeModule);
+
+exports.OAuth2Provider = OAuth2Provider;
diff --git a/lib/build/oauth2provider-shared2.js b/lib/build/oauth2provider-shared2.js
new file mode 100644
index 000000000..bd3b554b5
--- /dev/null
+++ b/lib/build/oauth2provider-shared2.js
@@ -0,0 +1,10 @@
+"use strict";
+
+var genericComponentOverrideContext = require("./genericComponentOverrideContext.js");
+
+var _a = genericComponentOverrideContext.createGenericComponentsOverrideContext(),
+ useContext = _a[0],
+ Provider = _a[1];
+
+exports.Provider = Provider;
+exports.useContext = useContext;
diff --git a/lib/build/oauth2provider.js b/lib/build/oauth2provider.js
new file mode 100644
index 000000000..aee148ac4
--- /dev/null
+++ b/lib/build/oauth2provider.js
@@ -0,0 +1,99 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", { value: true });
+
+var componentOverrideContext = require("./oauth2provider-shared2.js");
+var recipe = require("./oauth2provider-shared.js");
+require("./genericComponentOverrideContext.js");
+require("supertokens-web-js");
+require("supertokens-web-js/utils/cookieHandler");
+require("supertokens-web-js/utils/postSuperTokensInitCallbacks");
+require("supertokens-web-js/utils/windowHandler");
+require("supertokens-web-js/recipe/multitenancy");
+require("supertokens-web-js/utils");
+require("react");
+require("supertokens-web-js/utils/normalisedURLDomain");
+require("supertokens-web-js/utils/normalisedURLPath");
+require("react/jsx-runtime");
+require("supertokens-web-js/recipe/oauth2provider");
+require("./recipeModule-shared.js");
+
+/* Copyright (c) 2024, VRAI Labs and/or its affiliates. All rights reserved.
+ *
+ * This software is licensed under the Apache License, Version 2.0 (the
+ * "License") as published by the Apache Software Foundation.
+ *
+ * You may not use this file except in compliance with the License. You may
+ * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+var Wrapper = /** @class */ (function () {
+ function Wrapper() {}
+ Wrapper.init = function (config) {
+ return recipe.OAuth2Provider.init(config);
+ };
+ /**
+ * Returns information about an OAuth login in progress
+ *
+ * @param loginChallenge The login challenge from the url
+ *
+ * @param userContext (OPTIONAL) Refer to {@link https://supertokens.com/docs/emailpassword/advanced-customizations/user-context the documentation}
+ *
+ * @param options (OPTIONAL) Use this to configure additional properties (for example pre api hooks)
+ *
+ * @returns `{status: "OK", info: LoginInfo}`
+ *
+ * @throws STGeneralError if the API exposed by the backend SDKs returns `status: "GENERAL_ERROR"`
+ */
+ Wrapper.getLoginChallengeInfo = function (input) {
+ return recipe.OAuth2Provider.getInstanceOrThrow().webJSRecipe.getLoginChallengeInfo(input);
+ };
+ /**
+ * Accepts the OAuth2 Login request and returns the redirect URL to continue the OAuth flow.
+ *
+ * @param loginChallenge The login challenge from the url
+ *
+ * @param userContext (OPTIONAL) Refer to {@link https://supertokens.com/docs/emailpassword/advanced-customizations/user-context the documentation}
+ *
+ * @param options (OPTIONAL) Use this to configure additional properties (for example pre api hooks)
+ *
+ * @returns `{status: "OK", frontendRedirectTo: string}`
+ *
+ * @throws STGeneralError if the API exposed by the backend SDKs returns `status: "GENERAL_ERROR"`
+ */
+ Wrapper.getRedirectURLToContinueOAuthFlow = function (input) {
+ return recipe.OAuth2Provider.getInstanceOrThrow().webJSRecipe.getRedirectURLToContinueOAuthFlow(input);
+ };
+ /**
+ * Accepts the OAuth2 Logout request, clears the SuperTokens session and returns post logout redirect URL.
+ *
+ * @param logoutChallenge The logout challenge from the url
+ *
+ * @param userContext (OPTIONAL) Refer to {@link https://supertokens.com/docs/emailpassword/advanced-customizations/user-context the documentation}
+ *
+ * @param options (OPTIONAL) Use this to configure additional properties (for example pre api hooks)
+ *
+ * @returns `{status: "OK", frontendRedirectTo: string}`
+ *
+ * @throws STGeneralError if the API exposed by the backend SDKs returns `status: "GENERAL_ERROR"`
+ */
+ Wrapper.logOut = function (input) {
+ return recipe.OAuth2Provider.getInstanceOrThrow().webJSRecipe.logOut(input);
+ };
+ Wrapper.ComponentsOverrideProvider = componentOverrideContext.Provider;
+ return Wrapper;
+})();
+var init = Wrapper.init;
+var getLoginChallengeInfo = Wrapper.getLoginChallengeInfo;
+var logOut = Wrapper.logOut;
+
+exports.RecipeComponentsOverrideContextProvider = componentOverrideContext.Provider;
+exports.default = Wrapper;
+exports.getLoginChallengeInfo = getLoginChallengeInfo;
+exports.init = init;
+exports.logOut = logOut;
diff --git a/lib/build/oauth2providerprebuiltui.js b/lib/build/oauth2providerprebuiltui.js
new file mode 100644
index 000000000..dca66706f
--- /dev/null
+++ b/lib/build/oauth2providerprebuiltui.js
@@ -0,0 +1,616 @@
+"use strict";
+
+var genericComponentOverrideContext = require("./genericComponentOverrideContext.js");
+var jsxRuntime = require("react/jsx-runtime");
+var NormalisedURLPath = require("supertokens-web-js/utils/normalisedURLPath");
+var uiEntry = require("./index2.js");
+var session = require("./session.js");
+var componentOverrideContext = require("./oauth2provider-shared2.js");
+var React = require("react");
+var recipe = require("./oauth2provider-shared.js");
+var translationContext = require("./translationContext.js");
+var button = require("./emailpassword-shared.js");
+require("supertokens-web-js");
+require("supertokens-web-js/utils/cookieHandler");
+require("supertokens-web-js/utils/postSuperTokensInitCallbacks");
+require("supertokens-web-js/utils/windowHandler");
+require("supertokens-web-js/recipe/multitenancy");
+require("supertokens-web-js/utils");
+require("supertokens-web-js/utils/normalisedURLDomain");
+require("react-dom");
+require("./multitenancy-shared.js");
+require("./multifactorauth-shared2.js");
+require("supertokens-web-js/recipe/multifactorauth");
+require("supertokens-web-js/utils/sessionClaimValidatorStore");
+require("./recipeModule-shared.js");
+require("./multifactorauth-shared.js");
+require("supertokens-web-js/recipe/session");
+require("./authRecipe-shared.js");
+require("supertokens-web-js/lib/build/normalisedURLPath");
+require("./session-shared.js");
+require("supertokens-web-js/recipe/oauth2provider");
+
+function _interopDefault(e) {
+ return e && e.__esModule ? e : { default: e };
+}
+
+function _interopNamespace(e) {
+ if (e && e.__esModule) return e;
+ var n = Object.create(null);
+ if (e) {
+ Object.keys(e).forEach(function (k) {
+ if (k !== "default") {
+ var d = Object.getOwnPropertyDescriptor(e, k);
+ Object.defineProperty(
+ n,
+ k,
+ d.get
+ ? d
+ : {
+ enumerable: true,
+ get: function () {
+ return e[k];
+ },
+ }
+ );
+ }
+ });
+ }
+ n.default = e;
+ return Object.freeze(n);
+}
+
+var NormalisedURLPath__default = /*#__PURE__*/ _interopDefault(NormalisedURLPath);
+var React__namespace = /*#__PURE__*/ _interopNamespace(React);
+
+var styles =
+ '/* Copyright (c) 2024, VRAI Labs and/or its affiliates. All rights reserved.\n *\n * This software is licensed under the Apache License, Version 2.0 (the\n * "License") as published by the Apache Software Foundation.\n *\n * You may not use this file except in compliance with the License. You may\n * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\n[data-supertokens~="container"] {\n --palette-background: 255, 255, 255;\n --palette-inputBackground: 250, 250, 250;\n --palette-inputBorder: 224, 224, 224;\n --palette-primary: 28, 34, 42;\n --palette-primaryBorder: 45, 54, 68;\n --palette-success: 65, 167, 0;\n --palette-successBackground: 217, 255, 191;\n --palette-error: 255, 23, 23;\n --palette-errorBackground: 255, 241, 235;\n --palette-textTitle: 0, 0, 0;\n --palette-textLabel: 0, 0, 0;\n --palette-textInput: 0, 0, 0;\n --palette-textPrimary: 128, 128, 128;\n --palette-textLink: 0, 122, 255;\n --palette-buttonText: 255, 255, 255;\n --palette-textGray: 54, 54, 54;\n --palette-superTokensBrandingBackground: 242, 245, 246;\n --palette-superTokensBrandingText: 173, 189, 196;\n\n --font-size-0: 12px;\n --font-size-1: 14px;\n --font-size-2: 16px;\n --font-size-3: 19px;\n --font-size-4: 24px;\n --font-size-5: 28px;\n}\n\n/*\n * Default styles.\n */\n\n@keyframes slideTop {\n 0% {\n transform: translateY(-5px);\n }\n 100% {\n transform: translateY(0px);\n }\n}\n\n@keyframes swing-in-top-fwd {\n 0% {\n transform: rotateX(-100deg);\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n transform: rotateX(0deg);\n transform-origin: top;\n opacity: 1;\n }\n}\n\n[data-supertokens~="container"] {\n font-family: "Arial", sans-serif;\n margin: 12px auto;\n margin-top: 26px;\n margin-bottom: 26px;\n width: 420px;\n text-align: center;\n border-radius: 8px;\n box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.16);\n background-color: rgb(var(--palette-background));\n}\n\n@media (max-width: 440px) {\n [data-supertokens~="container"] {\n width: 95vw;\n }\n}\n\n[data-supertokens~="row"] {\n margin: 0 auto;\n width: 76%;\n padding-top: 30px;\n padding-bottom: 10px;\n}\n\n[data-supertokens~="superTokensBranding"] {\n display: block;\n margin: 10px auto 0;\n background: rgb(var(--palette-superTokensBrandingBackground));\n color: rgb(var(--palette-superTokensBrandingText));\n text-decoration: none;\n width: -webkit-fit-content;\n width: -moz-fit-content;\n width: fit-content;\n border-radius: 6px 6px 0 0;\n padding: 4px 9px;\n font-weight: 400;\n font-size: var(--font-size-0);\n letter-spacing: 0.4px;\n}\n\n[data-supertokens~="generalError"] {\n background: rgb(var(--palette-errorBackground));\n padding-top: 10px;\n padding-bottom: 10px;\n margin-bottom: 10px;\n margin-top: 24px;\n padding-left: 18px;\n padding-right: 18px;\n letter-spacing: 0.2px;\n font-size: var(--font-size-1);\n border-radius: 8px;\n color: rgb(var(--palette-error));\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n word-wrap: break-word;\n}\n\n[data-supertokens~="headerTitle"] {\n font-size: var(--font-size-4);\n line-height: 27.6px;\n letter-spacing: 0.58px;\n font-weight: 700;\n margin-bottom: 20px;\n color: rgb(var(--palette-textTitle));\n}\n\n[data-supertokens~="headerSubtitle"] {\n font-weight: 400;\n color: rgb(var(--palette-textGray));\n margin-bottom: 21px;\n}\n\n[data-supertokens~="headerSubtitle"][data-supertokens~="secondaryText"] {\n color: rgb(var(--palette-textGray));\n font-weight: 400;\n}\n\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] {\n max-width: 300px;\n margin-top: 10px;\n}\n\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] a {\n line-height: 21px;\n}\n\n/* TODO: split the link style into separate things*/\n\n/* We add this before primary and secondary text, because if they are applied to the same element the other ones take priority */\n\n[data-supertokens~="link"] {\n padding-left: 3px;\n padding-right: 3px;\n color: rgb(var(--palette-textLink));\n font-size: var(--font-size-1);\n cursor: pointer;\n letter-spacing: 0.16px;\n line-height: 26px;\n}\n\n[data-supertokens~="primaryText"] {\n font-size: var(--font-size-2);\n font-weight: 400;\n letter-spacing: 0.4px;\n line-height: 21px;\n color: rgb(var(--palette-textLabel));\n}\n\n[data-supertokens~="secondaryText"] {\n font-size: var(--font-size-1);\n font-weight: 400;\n letter-spacing: 0.4px;\n color: rgb(var(--palette-textPrimary));\n}\n\n[data-supertokens~="secondaryText"] strong {\n font-weight: 600;\n}\n\n[data-supertokens~="divider"] {\n margin-top: 1.5em;\n margin-bottom: 1.5em;\n border-bottom: 0.3px solid #dddddd;\n align-items: center;\n padding-bottom: 5px;\n flex: 3 3;\n}\n\n[data-supertokens~="headerTinyTitle"] {\n margin-top: 24px;\n font-size: var(--font-size-5);\n letter-spacing: 1.1px;\n font-weight: 700;\n line-height: 28px;\n}\n\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n}\n\n[data-supertokens~="secondaryLinkWithArrow"]:hover {\n position: relative;\n left: 2px;\n word-spacing: 4px;\n}\n\n[data-supertokens~="generalSuccess"] {\n color: rgb(var(--palette-success));\n font-size: var(--font-size-1);\n background: rgb(var(--palette-successBackground));\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n padding: 9px 15px 9px 15px;\n border-radius: 6px;\n display: inline-block;\n}\n\n[data-supertokens~="spinner"] {\n width: 80px;\n height: auto;\n padding-top: 20px;\n padding-bottom: 40px;\n margin: 0 auto;\n}\n\n[data-supertokens~="error"] {\n color: rgb(var(--palette-error));\n}\n\n[data-supertokens~="linkButton"] {\n font-family: "Arial", sans-serif;\n background-color: transparent;\n border: 0;\n}\n\n[data-supertokens~="secondaryLinkWithLeftArrow"] {\n color: rgb(var(--palette-textGray));\n font-weight: 400;\n margin-top: 10px;\n margin-bottom: 40px;\n cursor: pointer;\n}\n\n[data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n margin-right: 0.3em;\n}\n\n[data-supertokens~="secondaryLinkWithLeftArrow"]:hover svg {\n position: relative;\n left: -4px;\n}\n\n[data-supertokens~="button"] {\n font-family: "Arial", sans-serif;\n background-color: rgb(var(--palette-primary));\n color: rgb(var(--palette-buttonText));\n width: 100%;\n height: 34px;\n font-weight: 600;\n border-width: 1px;\n border-style: solid;\n border-radius: 6px;\n border-color: rgb(var(--palette-primaryBorder));\n background-position: center;\n transition: all 0.4s;\n background-size: 12000%;\n cursor: pointer;\n}\n\n[data-supertokens~="button"]:disabled {\n border: none;\n cursor: no-drop;\n}\n\n[data-supertokens~="button"]:active {\n outline: none;\n transition: all 0s;\n background-size: 100%;\n filter: brightness(0.85);\n}\n\n[data-supertokens~="button"]:focus {\n outline: none;\n}\n\n[data-supertokens~="backButtonCommon"] {\n width: 16px;\n height: 13px;\n}\n\n[data-supertokens~="backButton"] {\n cursor: pointer;\n border: none;\n background-color: transparent;\n padding: 0px;\n}\n\n[data-supertokens~="backButtonPlaceholder"] {\n display: block;\n}\n\n[data-supertokens~="delayedRender"] {\n animation-duration: 0.1s;\n animation-name: animate-fade;\n animation-delay: 0.2s;\n animation-fill-mode: backwards;\n}\n\n@keyframes animate-fade {\n 0% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n}\n\n[data-supertokens~="footerLinkGroupVert"] {\n display: flex;\n flex-direction: column;\n margin-top: 10px;\n gap: 24px;\n}\n\n[data-supertokens~="footerLinkGroupVert"] > div {\n cursor: pointer;\n margin: 0;\n}\n\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryText"] {\n font-weight: 400;\n}\n\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n font-weight: 400;\n position: relative;\n left: -6px; /* half the width of the left arrow */\n}\n\n@media (max-width: 360px) {\n [data-supertokens~="footerLinkGroupVert"] {\n flex-direction: column;\n }\n [data-supertokens~="footerLinkGroupVert"] > div {\n margin: 0 auto;\n }\n}\n\n[data-supertokens~="footerLinkGroupVert"] div:only-child {\n margin-left: auto;\n margin-right: auto;\n margin-top: 14px;\n}\n\n[data-supertokens~="withBackButton"] {\n position: relative;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n[data-supertokens~="dividerWithOr"] {\n padding-top: 5px;\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n color: rgb(var(--palette-textPrimary));\n}\n\n[data-supertokens~="dividerText"] {\n flex: 1 1;\n font-weight: 400;\n font-size: var(--font-size-1);\n}\n\n[data-supertokens~="formLabelWithLinkWrapper"] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n[data-supertokens~="formLabelLinkBtn"] {\n width: auto;\n margin-top: 0;\n line-height: 24px;\n font-size: var(--font-size-0);\n}\n\n[data-supertokens~="formLabelLinkBtn"]:hover {\n text-decoration: underline;\n}\n\n[data-supertokens~="formLabelLinkBtn"]:disabled {\n color: rgb(var(--palette-textPrimary));\n cursor: default;\n text-decoration: none;\n}\n\n[data-supertokens~="authComponentList"] {\n padding-bottom: 20px;\n}\n\n[data-supertokens~="authPageTitleOAuthClient"] {\n color: rgb(var(--palette-textGray));\n font-size: var(--font-size-1);\n font-weight: 400;\n margin: 10px 0 25px;\n}\n\n[data-supertokens~="authPageTitleOAuthClientUrl"] {\n text-decoration: none;\n}\n\n[data-supertokens~="authPageTitleOAuthClientLogo"] {\n width: 44px;\n height: 44px;\n margin-bottom: 10px;\n}\n\n[data-supertokens~="authPageTitleOAuthClient"] [data-supertokens~="authPageTitleOAuthClientName"] {\n color: rgb(var(--palette-textTitle));\n}\n\n[data-supertokens~="buttonWithArrow"] {\n border-radius: 6px;\n border: 1px solid #d0d5dd;\n width: 100%;\n color: rgb(var(--palette-textGray));\n display: flex;\n justify-content: center;\n align-items: center;\n gap: 5px;\n margin: 24px 0;\n min-height: 48px;\n cursor: pointer;\n}\n\n[data-supertokens~="buttonWithArrow"]:hover {\n background-color: rgb(var(--palette-inputBackground));\n}\n\n[data-supertokens~="buttonWithArrow"] [data-supertokens~="secondaryText"] {\n font-weight: 700;\n font-size: var(--font-size-2);\n color: rgb(var(--palette-textGray));\n margin: 0;\n}\n\n[data-supertokens~="buttonWithArrow"]:hover [data-supertokens~="secondaryLinkWithRightArrow"] ~ svg {\n position: relative;\n left: 2px;\n}\n\n[data-supertokens~="buttonWithArrow"]:hover [data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n position: relative;\n left: -2px;\n}\n\n[data-supertokens~="buttonWithArrow"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n display: flex;\n align-items: center;\n}\n\n[data-supertokens~="logoutIcon"] {\n padding: 18px 20px 18px 24px;\n background-color: rgba(var(--palette-textGray), 0.1);\n border-radius: 12px;\n}\n\n[data-supertokens~="oauth2Logout"] [data-supertokens~="headerTitle"] {\n margin-top: 24px;\n margin-bottom: 24px;\n}\n\n[data-supertokens~="oauth2Logout"] [data-supertokens~="button"] {\n margin-bottom: 24px;\n}\n';
+
+var ThemeBase = function (_a) {
+ var children = _a.children,
+ userStyles = _a.userStyles;
+ return jsxRuntime.jsxs(React.Fragment, {
+ children: [children, jsxRuntime.jsxs("style", { children: [styles, userStyles.join("\n")] })],
+ });
+};
+
+/* Copyright (c) 2024, VRAI Labs and/or its affiliates. All rights reserved.
+ *
+ * This software is licensed under the Apache License, Version 2.0 (the
+ * "License") as published by the Apache Software Foundation.
+ *
+ * You may not use this file except in compliance with the License. You may
+ * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+function LogoutIcon() {
+ return jsxRuntime.jsx(
+ "svg",
+ genericComponentOverrideContext.__assign(
+ {
+ "data-supertokens": "logoutIcon",
+ xmlns: "http://www.w3.org/2000/svg",
+ width: "40",
+ height: "38",
+ fill: "none",
+ },
+ {
+ children: jsxRuntime.jsx("path", {
+ fill: "rgb(var(--palette-textGray))",
+ "fill-rule": "evenodd",
+ d: "M2.972.022a.874.874 0 0 1-.23.062c-.234.042-.926.362-1.148.53a4.638 4.638 0 0 0-.656.63c-.178.228-.415.681-.495.948l-.116.378C.272 2.742.27 32.075.326 32.251l.111.37c.165.559.636 1.207 1.133 1.558a3.9 3.9 0 0 1 .195.145c.048.046.368.206.588.292l.196.08c.036.016.183.063.326.105.144.042.295.093.337.113.041.02.11.037.154.037s.098.015.12.034c.023.019.218.087.434.15.215.065.43.133.478.153.048.019.254.085.457.146.204.06.404.128.446.148.041.021.11.038.154.038s.098.015.12.034c.023.02.16.069.303.11.144.041.295.092.337.112.041.02.11.037.154.037s.098.015.12.034c.023.018.218.086.434.15.215.065.43.133.478.152.048.02.254.086.457.148.204.062.404.129.446.148a.45.45 0 0 0 .163.037c.048 0 .088.018.088.041 0 .023.034.043.076.043.042 0 .213.048.38.104.168.057.34.104.381.104.042 0 .076.02.076.042 0 .023.04.042.088.042.048 0 .122.017.163.038.042.02.193.07.337.11.274.076.366.106.544.176.06.024.285.096.5.16.216.064.41.132.433.15a.224.224 0 0 0 .12.035.4.4 0 0 1 .155.04c.042.02.193.07.337.108.144.038.3.084.348.103.178.07.613.125.954.122.365-.004.908-.078.965-.133a.16.16 0 0 1 .096-.031c.08 0 .707-.291.784-.364.032-.03.073-.054.09-.054.053 0 .632-.55.748-.71.195-.27.432-.71.432-.803 0-.04.02-.083.044-.097.024-.014.043-.077.043-.14 0-.063.023-.137.05-.163.034-.033.059-.404.077-1.148l.026-1.1 2.894-.023c2.31-.02 2.939-.037 3.119-.084.123-.033.24-.074.257-.091.018-.017.077-.031.132-.031.054 0 .11-.02.125-.042.015-.023.055-.042.089-.042.19 0 1.14-.54 1.493-.849.456-.398.898-.926 1.095-1.304a.916.916 0 0 1 .088-.147c.02-.018.06-.104.219-.48.02-.047.059-.16.088-.252.029-.091.069-.214.09-.271.125-.356.146-.97.146-4.265 0-3.563-.003-3.626-.205-3.987-.204-.364-.756-.78-1.036-.78-.045 0-.093-.019-.108-.042-.035-.054-.661-.054-.696 0-.015.023-.066.042-.113.042-.256 0-.85.449-1.002.757-.253.514-.256.568-.256 4.24v3.287l-.11.222c-.06.123-.186.306-.28.408-.171.188-.551.41-.7.41-.044 0-.092.02-.107.042-.018.027-.943.042-2.635.042h-2.608l-.011-12.165c-.01-9.665-.023-12.176-.066-12.218a.236.236 0 0 1-.055-.149.426.426 0 0 0-.039-.169 4.357 4.357 0 0 1-.118-.26c-.201-.477-.692-1.057-1.127-1.332a2.216 2.216 0 0 1-.196-.134c-.054-.058-.664-.307-.848-.346-.048-.01 1.66-.021 3.795-.024 2.546-.003 3.89.01 3.908.037.015.023.064.042.11.042.19 0 .646.313.82.561.274.39.267.31.267 3.032 0 2.402.02 2.851.14 3.139.245.59.71.966 1.318 1.068.33.055.642.012.979-.134.242-.105.696-.489.696-.588 0-.03.015-.054.033-.054.042 0 .166-.305.213-.522.058-.272.046-5.251-.015-5.666a4.778 4.778 0 0 0-.27-1.066 9.014 9.014 0 0 0-.397-.773 2.902 2.902 0 0 1-.161-.23 3.223 3.223 0 0 0-.298-.377 7.831 7.831 0 0 1-.23-.25c-.149-.175-.564-.502-.91-.717a5.197 5.197 0 0 0-.38-.224c-.011 0-.133-.05-.271-.11a4.346 4.346 0 0 0-.98-.319C22.442.018 3.025-.029 2.973.022Zm28.17 7.903c-.364.092-.514.172-.764.407-.225.21-.38.445-.487.737-.04.11-.054.77-.055 2.645v2.498h-3.457c-2.258 0-3.467.015-3.485.042-.014.023-.063.042-.107.042-.138 0-.449.18-.655.379-.194.187-.38.497-.474.794-.06.187-.062.653-.004.687.024.015.044.06.044.102 0 .17.198.495.443.724.141.132.285.24.32.24.035 0 .063.02.063.042 0 .023.036.042.08.042.044 0 .094.014.111.03.125.12.504.134 3.78.136l3.34.001.014 2.52c.015 2.39.032 2.79.122 2.79.021 0 .039.038.039.084 0 .046.02.084.043.084.024 0 .044.026.044.058 0 .073.476.527.552.527.032 0 .057.016.057.036 0 .02.108.069.24.109.35.106 1.009.076 1.305-.059.175-.08.895-.75 3.656-3.406 1.89-1.82 3.487-3.373 3.548-3.454.278-.37.388-.944.256-1.342-.15-.456-.165-.47-3.737-3.915-1.915-1.846-3.511-3.356-3.547-3.356-.037 0-.067-.014-.067-.031 0-.074-.636-.261-.87-.256-.06.001-.217.03-.349.063Z",
+ "clip-rule": "evenodd",
+ }),
+ }
+ )
+ );
+}
+
+var OAuth2LogoutScreenInner = uiEntry.withOverride("OAuth2LogoutScreenInner", function OAuth2LogoutScreenInner(props) {
+ var t = translationContext.useTranslation();
+ return jsxRuntime.jsxs(jsxRuntime.Fragment, {
+ children: [
+ jsxRuntime.jsx(LogoutIcon, {}),
+ jsxRuntime.jsx(
+ "div",
+ genericComponentOverrideContext.__assign(
+ { "data-supertokens": "headerTitle" },
+ { children: t("LOGGING_OUT") }
+ )
+ ),
+ jsxRuntime.jsx(
+ "div",
+ genericComponentOverrideContext.__assign(
+ { "data-supertokens": "headerSubtitle" },
+ { children: t("LOGOUT_CONFIRMATION") }
+ )
+ ),
+ jsxRuntime.jsx("div", { "data-supertokens": "divider" }),
+ jsxRuntime.jsx(button.Button, {
+ disabled: props.isLoggingOut,
+ isLoading: props.isLoggingOut,
+ type: "button",
+ label: t("LOGOUT"),
+ onClick: props.onLogoutClicked,
+ }),
+ ],
+ });
+});
+
+var OAuth2LogoutScreen$1 = function (props) {
+ if (props.showSpinner) {
+ return jsxRuntime.jsx(uiEntry.DynamicLoginMethodsSpinner, {});
+ }
+ return jsxRuntime.jsxs(
+ "div",
+ genericComponentOverrideContext.__assign(
+ { "data-supertokens": "oauth2Logout container" },
+ {
+ children: [
+ jsxRuntime.jsx(
+ "div",
+ genericComponentOverrideContext.__assign(
+ { "data-supertokens": "row" },
+ {
+ children: jsxRuntime.jsx(OAuth2LogoutScreenInner, {
+ isLoggingOut: props.isLoggingOut,
+ onLogoutClicked: props.onLogoutClicked,
+ }),
+ }
+ )
+ ),
+ jsxRuntime.jsx(uiEntry.SuperTokensBranding, {}),
+ ],
+ }
+ )
+ );
+};
+var OAuth2LogoutScreenTheme = function (props) {
+ var rootStyle = genericComponentOverrideContext.SuperTokens.getInstanceOrThrow().rootStyle;
+ return jsxRuntime.jsx(
+ ThemeBase,
+ genericComponentOverrideContext.__assign(
+ { userStyles: [rootStyle, props.config.recipeRootStyle, props.config.oauth2LogoutScreen.style] },
+ { children: jsxRuntime.jsx(OAuth2LogoutScreen$1, genericComponentOverrideContext.__assign({}, props)) }
+ )
+ );
+};
+
+var defaultTranslationsOAuth2Provider = {
+ en: genericComponentOverrideContext.__assign(
+ genericComponentOverrideContext.__assign({}, uiEntry.defaultTranslationsCommon.en),
+ { LOGGING_OUT: "Logging Out", LOGOUT_CONFIRMATION: "Are you sure you want to log out?", LOGOUT: "LOG OUT" }
+ ),
+};
+
+var OAuth2LogoutScreen = function (props) {
+ var _a, _b, _c;
+ var rethrowInRender = genericComponentOverrideContext.useRethrowInRender();
+ var sessionContext = React__namespace.useContext(uiEntry.SessionContext);
+ var _d = React__namespace.useState(false),
+ isLoggingOut = _d[0],
+ setIsLoggingOut = _d[1];
+ var recipeComponentOverrides = props.useComponentOverrides();
+ var userContext = uiEntry.useUserContext();
+ if (props.userContext !== undefined) {
+ userContext = props.userContext;
+ }
+ var logoutChallenge =
+ (_a = genericComponentOverrideContext.getQueryParams("logoutChallenge")) !== null && _a !== void 0
+ ? _a
+ : undefined;
+ var navigate =
+ (_b = props.navigate) !== null && _b !== void 0
+ ? _b
+ : (_c = uiEntry.UI.getReactRouterDomWithCustomHistory()) === null || _c === void 0
+ ? void 0
+ : _c.useHistoryCustom();
+ var onLogout = React__namespace.useCallback(
+ function () {
+ return genericComponentOverrideContext.__awaiter(void 0, void 0, void 0, function () {
+ var frontendRedirectTo, err_1;
+ return genericComponentOverrideContext.__generator(this, function (_a) {
+ switch (_a.label) {
+ case 0:
+ if (logoutChallenge === undefined) {
+ return [2 /*return*/];
+ }
+ setIsLoggingOut(true);
+ _a.label = 1;
+ case 1:
+ _a.trys.push([1, 4, , 5]);
+ return [
+ 4 /*yield*/,
+ recipe.OAuth2Provider.getInstanceOrThrow().webJSRecipe.logOut({
+ logoutChallenge: logoutChallenge,
+ userContext: userContext,
+ }),
+ ];
+ case 2:
+ frontendRedirectTo = _a.sent().frontendRedirectTo;
+ return [
+ 4 /*yield*/,
+ props.recipe.redirect(
+ {
+ recipeId: "oauth2provider",
+ action: "POST_OAUTH2_LOGOUT_REDIRECT",
+ tenantIdFromQueryParams:
+ genericComponentOverrideContext.getTenantIdFromQueryParams(),
+ frontendRedirectTo: frontendRedirectTo,
+ },
+ navigate,
+ {},
+ userContext
+ ),
+ ];
+ case 3:
+ _a.sent();
+ return [3 /*break*/, 5];
+ case 4:
+ err_1 = _a.sent();
+ rethrowInRender(err_1);
+ return [3 /*break*/, 5];
+ case 5:
+ return [2 /*return*/];
+ }
+ });
+ });
+ },
+ [logoutChallenge, navigate, props.recipe, userContext, rethrowInRender]
+ );
+ React__namespace.useEffect(
+ function () {
+ // We wait for session loading to finish
+ if (sessionContext.loading === false) {
+ // Redirect to the auth page if there is no logoutChallenge
+ if (logoutChallenge === undefined) {
+ void genericComponentOverrideContext.SuperTokens.getInstanceOrThrow()
+ .redirectToAuth({
+ userContext: userContext,
+ redirectBack: false,
+ })
+ .catch(rethrowInRender);
+ } else {
+ // Call logOut directly if there is no session
+ if (sessionContext.doesSessionExist === false) {
+ void onLogout();
+ }
+ }
+ }
+ },
+ [userContext, logoutChallenge, sessionContext, onLogout]
+ );
+ var childProps = {
+ config: props.recipe.config,
+ showSpinner: sessionContext.loading || sessionContext.doesSessionExist === false,
+ onLogoutClicked: onLogout,
+ isLoggingOut: isLoggingOut,
+ };
+ if (logoutChallenge === undefined) {
+ return null;
+ }
+ return jsxRuntime.jsx(
+ uiEntry.ComponentOverrideContext.Provider,
+ genericComponentOverrideContext.__assign(
+ { value: recipeComponentOverrides },
+ {
+ children: jsxRuntime.jsx(
+ uiEntry.FeatureWrapper,
+ genericComponentOverrideContext.__assign(
+ {
+ useShadowDom: genericComponentOverrideContext.SuperTokens.getInstanceOrThrow().useShadowDom,
+ defaultStore: defaultTranslationsOAuth2Provider,
+ },
+ {
+ children: jsxRuntime.jsxs(React.Fragment, {
+ children: [
+ props.children === undefined &&
+ jsxRuntime.jsx(
+ OAuth2LogoutScreenTheme,
+ genericComponentOverrideContext.__assign({}, childProps)
+ ),
+ props.children &&
+ React__namespace.Children.map(props.children, function (child) {
+ if (React__namespace.isValidElement(child)) {
+ return React__namespace.cloneElement(child, childProps);
+ }
+ return child;
+ }),
+ ],
+ }),
+ }
+ )
+ ),
+ }
+ )
+ );
+};
+
+var TryRefreshPage$1 = function (props) {
+ var _a;
+ var rethrowInRender = genericComponentOverrideContext.useRethrowInRender();
+ var sessionContext = React.useContext(uiEntry.SessionContext);
+ var loginChallenge =
+ (_a = genericComponentOverrideContext.getQueryParams("loginChallenge")) !== null && _a !== void 0
+ ? _a
+ : undefined;
+ var userContext = uiEntry.useUserContext();
+ if (props.userContext !== undefined) {
+ userContext = props.userContext;
+ }
+ React__namespace.useEffect(
+ function () {
+ if (sessionContext.loading === false) {
+ if (loginChallenge) {
+ (function () {
+ return genericComponentOverrideContext.__awaiter(this, void 0, void 0, function () {
+ var frontendRedirectTo;
+ return genericComponentOverrideContext.__generator(this, function (_a) {
+ switch (_a.label) {
+ case 0:
+ return [
+ 4 /*yield*/,
+ props.recipe.webJSRecipe.getRedirectURLToContinueOAuthFlow({
+ loginChallenge: loginChallenge,
+ userContext: userContext,
+ }),
+ ];
+ case 1:
+ frontendRedirectTo = _a.sent().frontendRedirectTo;
+ return [
+ 2 /*return*/,
+ props.recipe.redirect(
+ {
+ action: "CONTINUE_OAUTH2_AFTER_REFRESH",
+ frontendRedirectTo: frontendRedirectTo,
+ tenantIdFromQueryParams:
+ genericComponentOverrideContext.getTenantIdFromQueryParams(),
+ recipeId: "oauth2provider",
+ },
+ props.navigate,
+ {},
+ userContext
+ ),
+ ];
+ }
+ });
+ });
+ })().catch(rethrowInRender);
+ } else {
+ void genericComponentOverrideContext.SuperTokens.getInstanceOrThrow()
+ .redirectToAuth({
+ userContext: userContext,
+ redirectBack: false,
+ })
+ .catch(rethrowInRender);
+ }
+ }
+ },
+ [loginChallenge, props.recipe, props.navigate, userContext, sessionContext]
+ );
+ var childProps = {
+ config: props.recipe.config,
+ };
+ return jsxRuntime.jsx(
+ uiEntry.FeatureWrapper,
+ genericComponentOverrideContext.__assign(
+ {
+ useShadowDom: genericComponentOverrideContext.SuperTokens.getInstanceOrThrow().useShadowDom,
+ defaultStore: defaultTranslationsOAuth2Provider,
+ },
+ {
+ children: jsxRuntime.jsxs(React.Fragment, {
+ children: [
+ props.children === undefined && jsxRuntime.jsx(uiEntry.DynamicLoginMethodsSpinner, {}),
+ props.children &&
+ React__namespace.Children.map(props.children, function (child) {
+ if (React__namespace.isValidElement(child)) {
+ return React__namespace.cloneElement(child, childProps);
+ }
+ return child;
+ }),
+ ],
+ }),
+ }
+ )
+ );
+};
+
+/* Copyright (c) 2024, VRAI Labs and/or its affiliates. All rights reserved.
+ *
+ * This software is licensed under the Apache License, Version 2.0 (the
+ * "License") as published by the Apache Software Foundation.
+ *
+ * You may not use this file except in compliance with the License. You may
+ * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+var DEFAULT_TRY_REFRESH_PATH = "/try-refresh";
+var DEFAULT_OAUTH2_LOGOUT_PATH = "/oauth/logout";
+
+var OAuth2ProviderPreBuiltUI = /** @class */ (function (_super) {
+ genericComponentOverrideContext.__extends(OAuth2ProviderPreBuiltUI, _super);
+ function OAuth2ProviderPreBuiltUI(recipeInstance) {
+ var _this = _super.call(this) || this;
+ _this.recipeInstance = recipeInstance;
+ _this.languageTranslations = defaultTranslationsOAuth2Provider;
+ // Instance methods
+ _this.getFeatures = function (useComponentOverrides) {
+ if (useComponentOverrides === void 0) {
+ useComponentOverrides = componentOverrideContext.useContext;
+ }
+ if (_this.recipeInstance.config.disableDefaultUI) {
+ return {};
+ }
+ var features = {};
+ if (_this.recipeInstance.config.tryRefreshPage.disableDefaultUI !== true) {
+ var normalisedFullPath = _this.recipeInstance.config.appInfo.websiteBasePath.appendPath(
+ new NormalisedURLPath__default.default(DEFAULT_TRY_REFRESH_PATH)
+ );
+ features[normalisedFullPath.getAsStringDangerous()] = {
+ matches: genericComponentOverrideContext.matchRecipeIdUsingQueryParams(
+ _this.recipeInstance.config.recipeId
+ ),
+ component: function (props) {
+ return _this.getFeatureComponent("try-refresh-page", props, useComponentOverrides);
+ },
+ recipeID: recipe.OAuth2Provider.RECIPE_ID,
+ };
+ }
+ if (_this.recipeInstance.config.oauth2LogoutScreen.disableDefaultUI !== true) {
+ var normalisedFullPath = _this.recipeInstance.config.appInfo.websiteBasePath.appendPath(
+ new NormalisedURLPath__default.default(DEFAULT_OAUTH2_LOGOUT_PATH)
+ );
+ features[normalisedFullPath.getAsStringDangerous()] = {
+ matches: genericComponentOverrideContext.matchRecipeIdUsingQueryParams(
+ _this.recipeInstance.config.recipeId
+ ),
+ component: function (props) {
+ return _this.getFeatureComponent("oauth2-logout-screen", props, useComponentOverrides);
+ },
+ recipeID: recipe.OAuth2Provider.RECIPE_ID,
+ };
+ }
+ return features;
+ };
+ _this.getFeatureComponent = function (
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ componentName,
+ props,
+ useComponentOverrides
+ ) {
+ if (useComponentOverrides === void 0) {
+ useComponentOverrides = componentOverrideContext.useContext;
+ }
+ if (componentName === "try-refresh-page") {
+ return jsxRuntime.jsx(
+ uiEntry.UserContextWrapper,
+ genericComponentOverrideContext.__assign(
+ { userContext: props.userContext },
+ {
+ children: jsxRuntime.jsx(
+ session.SessionAuth,
+ genericComponentOverrideContext.__assign(
+ {
+ requireAuth: false,
+ overrideGlobalClaimValidators: function () {
+ return [];
+ },
+ },
+ {
+ children: jsxRuntime.jsx(
+ TryRefreshPage$1,
+ genericComponentOverrideContext.__assign(
+ {
+ recipe: _this.recipeInstance,
+ useComponentOverrides: useComponentOverrides,
+ },
+ props
+ )
+ ),
+ }
+ )
+ ),
+ }
+ )
+ );
+ } else if (componentName === "oauth2-logout-screen") {
+ return jsxRuntime.jsx(
+ uiEntry.UserContextWrapper,
+ genericComponentOverrideContext.__assign(
+ { userContext: props.userContext },
+ {
+ children: jsxRuntime.jsx(
+ session.SessionAuth,
+ genericComponentOverrideContext.__assign(
+ {
+ requireAuth: false,
+ overrideGlobalClaimValidators: function () {
+ return [];
+ },
+ },
+ {
+ children: jsxRuntime.jsx(
+ OAuth2LogoutScreen,
+ genericComponentOverrideContext.__assign(
+ {
+ recipe: _this.recipeInstance,
+ useComponentOverrides: useComponentOverrides,
+ },
+ props
+ )
+ ),
+ }
+ )
+ ),
+ }
+ )
+ );
+ }
+ throw new Error("Should never come here.");
+ };
+ return _this;
+ }
+ // Static methods
+ OAuth2ProviderPreBuiltUI.getInstanceOrInitAndGetInstance = function () {
+ if (OAuth2ProviderPreBuiltUI.instance === undefined) {
+ var recipeInstance = recipe.OAuth2Provider.getInstanceOrThrow();
+ OAuth2ProviderPreBuiltUI.instance = new OAuth2ProviderPreBuiltUI(recipeInstance);
+ }
+ return OAuth2ProviderPreBuiltUI.instance;
+ };
+ OAuth2ProviderPreBuiltUI.getFeatures = function (useComponentOverrides) {
+ if (useComponentOverrides === void 0) {
+ useComponentOverrides = componentOverrideContext.useContext;
+ }
+ return OAuth2ProviderPreBuiltUI.getInstanceOrInitAndGetInstance().getFeatures(useComponentOverrides);
+ };
+ OAuth2ProviderPreBuiltUI.getFeatureComponent = function (componentName, props, useComponentOverrides) {
+ if (useComponentOverrides === void 0) {
+ useComponentOverrides = componentOverrideContext.useContext;
+ }
+ return OAuth2ProviderPreBuiltUI.getInstanceOrInitAndGetInstance().getFeatureComponent(
+ componentName,
+ props,
+ useComponentOverrides
+ );
+ };
+ OAuth2ProviderPreBuiltUI.prototype.getAuthComponents = function () {
+ return [];
+ };
+ // For tests
+ OAuth2ProviderPreBuiltUI.reset = function () {
+ if (!genericComponentOverrideContext.isTest()) {
+ return;
+ }
+ OAuth2ProviderPreBuiltUI.instance = undefined;
+ return;
+ };
+ OAuth2ProviderPreBuiltUI.TryRefreshPage = function (props) {
+ return OAuth2ProviderPreBuiltUI.getInstanceOrInitAndGetInstance().getFeatureComponent(
+ "try-refresh-page",
+ props
+ );
+ };
+ OAuth2ProviderPreBuiltUI.OAuth2LogoutScreen = function (props) {
+ return OAuth2ProviderPreBuiltUI.getInstanceOrInitAndGetInstance().getFeatureComponent(
+ "oauth2-logout-screen",
+ props
+ );
+ };
+ return OAuth2ProviderPreBuiltUI;
+})(uiEntry.RecipeRouter);
+var TryRefreshPage = OAuth2ProviderPreBuiltUI.TryRefreshPage;
+
+exports.OAuth2ProviderPreBuiltUI = OAuth2ProviderPreBuiltUI;
+exports.TryRefreshPage = TryRefreshPage;
diff --git a/lib/build/passwordless.js b/lib/build/passwordless.js
index da90f1017..1b2c514be 100644
--- a/lib/build/passwordless.js
+++ b/lib/build/passwordless.js
@@ -19,6 +19,8 @@ require("./authRecipe-shared2.js");
require("./recipeModule-shared.js");
require("./multifactorauth-shared.js");
require("supertokens-web-js/recipe/session");
+require("./oauth2provider-shared.js");
+require("supertokens-web-js/recipe/oauth2provider");
require("./multifactorauth-shared2.js");
require("supertokens-web-js/recipe/multifactorauth");
require("supertokens-web-js/utils/sessionClaimValidatorStore");
diff --git a/lib/build/passwordlessprebuiltui.js b/lib/build/passwordlessprebuiltui.js
index 74352f7a8..1d2c93364 100644
--- a/lib/build/passwordlessprebuiltui.js
+++ b/lib/build/passwordlessprebuiltui.js
@@ -31,11 +31,13 @@ require("supertokens-web-js/utils");
require("supertokens-web-js/utils/normalisedURLDomain");
require("react-dom");
require("./multitenancy-shared.js");
+require("./oauth2provider-shared.js");
+require("supertokens-web-js/recipe/oauth2provider");
+require("./recipeModule-shared.js");
require("./authRecipe-shared.js");
require("supertokens-web-js/lib/build/normalisedURLPath");
require("supertokens-web-js/recipe/emailpassword");
require("./authRecipe-shared2.js");
-require("./recipeModule-shared.js");
require("./emailpassword-shared4.js");
require("./multifactorauth-shared3.js");
require("supertokens-web-js/recipe/session");
@@ -81,7 +83,7 @@ var STGeneralError__default = /*#__PURE__*/ _interopDefault(STGeneralError);
var STGeneralError__default$1 = /*#__PURE__*/ _interopDefault(STGeneralError$1);
var styles =
- '/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved.\n *\n * This software is licensed under the Apache License, Version 2.0 (the\n * "License") as published by the Apache Software Foundation.\n *\n * You may not use this file except in compliance with the License. You may\n * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\n[data-supertokens~="container"] {\n --palette-background: 255, 255, 255;\n --palette-inputBackground: 250, 250, 250;\n --palette-inputBorder: 224, 224, 224;\n --palette-primary: 28, 34, 42;\n --palette-primaryBorder: 45, 54, 68;\n --palette-success: 65, 167, 0;\n --palette-successBackground: 217, 255, 191;\n --palette-error: 255, 23, 23;\n --palette-errorBackground: 255, 241, 235;\n --palette-textTitle: 0, 0, 0;\n --palette-textLabel: 0, 0, 0;\n --palette-textInput: 0, 0, 0;\n --palette-textPrimary: 128, 128, 128;\n --palette-textLink: 0, 122, 255;\n --palette-buttonText: 255, 255, 255;\n --palette-textGray: 54, 54, 54;\n --palette-superTokensBrandingBackground: 242, 245, 246;\n --palette-superTokensBrandingText: 173, 189, 196;\n\n --font-size-0: 12px;\n --font-size-1: 14px;\n --font-size-2: 16px;\n --font-size-3: 19px;\n --font-size-4: 24px;\n --font-size-5: 28px;\n}\n\n/*\n * Default styles.\n */\n\n@keyframes slideTop {\n 0% {\n transform: translateY(-5px);\n }\n 100% {\n transform: translateY(0px);\n }\n}\n\n@keyframes swing-in-top-fwd {\n 0% {\n transform: rotateX(-100deg);\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n transform: rotateX(0deg);\n transform-origin: top;\n opacity: 1;\n }\n}\n\n[data-supertokens~="container"] {\n font-family: "Arial", sans-serif;\n margin: 12px auto;\n margin-top: 26px;\n margin-bottom: 26px;\n width: 420px;\n text-align: center;\n border-radius: 8px;\n box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.16);\n background-color: rgb(var(--palette-background));\n}\n\n@media (max-width: 440px) {\n [data-supertokens~="container"] {\n width: 95vw;\n }\n}\n\n[data-supertokens~="row"] {\n margin: 0 auto;\n width: 76%;\n padding-top: 30px;\n padding-bottom: 10px;\n}\n\n[data-supertokens~="superTokensBranding"] {\n display: block;\n margin: 10px auto 0;\n background: rgb(var(--palette-superTokensBrandingBackground));\n color: rgb(var(--palette-superTokensBrandingText));\n text-decoration: none;\n width: -webkit-fit-content;\n width: -moz-fit-content;\n width: fit-content;\n border-radius: 6px 6px 0 0;\n padding: 4px 9px;\n font-weight: 400;\n font-size: var(--font-size-0);\n letter-spacing: 0.4px;\n}\n\n[data-supertokens~="generalError"] {\n background: rgb(var(--palette-errorBackground));\n padding-top: 10px;\n padding-bottom: 10px;\n margin-bottom: 10px;\n margin-top: 24px;\n padding-left: 18px;\n padding-right: 18px;\n letter-spacing: 0.2px;\n font-size: var(--font-size-1);\n border-radius: 8px;\n color: rgb(var(--palette-error));\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n word-wrap: break-word;\n}\n\n[data-supertokens~="headerTitle"] {\n font-size: var(--font-size-4);\n line-height: 27.6px;\n letter-spacing: 0.58px;\n font-weight: 700;\n margin-bottom: 20px;\n color: rgb(var(--palette-textTitle));\n}\n\n[data-supertokens~="headerSubtitle"] {\n font-weight: 400;\n color: rgb(var(--palette-textGray));\n margin-bottom: 21px;\n}\n\n[data-supertokens~="headerSubtitle"][data-supertokens~="secondaryText"] {\n color: rgb(var(--palette-textGray));\n font-weight: 400;\n}\n\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] {\n max-width: 300px;\n margin-top: 10px;\n}\n\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] a {\n line-height: 21px;\n}\n\n/* TODO: split the link style into separate things*/\n\n/* We add this before primary and secondary text, because if they are applied to the same element the other ones take priority */\n\n[data-supertokens~="link"] {\n padding-left: 3px;\n padding-right: 3px;\n color: rgb(var(--palette-textLink));\n font-size: var(--font-size-1);\n cursor: pointer;\n letter-spacing: 0.16px;\n line-height: 26px;\n}\n\n[data-supertokens~="primaryText"] {\n font-size: var(--font-size-2);\n font-weight: 400;\n letter-spacing: 0.4px;\n line-height: 21px;\n color: rgb(var(--palette-textLabel));\n}\n\n[data-supertokens~="secondaryText"] {\n font-size: var(--font-size-1);\n font-weight: 400;\n letter-spacing: 0.4px;\n color: rgb(var(--palette-textPrimary));\n}\n\n[data-supertokens~="secondaryText"] strong {\n font-weight: 600;\n}\n\n[data-supertokens~="divider"] {\n margin-top: 1.5em;\n margin-bottom: 1.5em;\n border-bottom: 0.3px solid #dddddd;\n align-items: center;\n padding-bottom: 5px;\n flex: 3 3;\n}\n\n[data-supertokens~="headerTinyTitle"] {\n margin-top: 24px;\n font-size: var(--font-size-5);\n letter-spacing: 1.1px;\n font-weight: 700;\n line-height: 28px;\n}\n\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n}\n\n[data-supertokens~="secondaryLinkWithArrow"]:hover {\n position: relative;\n left: 2px;\n word-spacing: 4px;\n}\n\n[data-supertokens~="generalSuccess"] {\n color: rgb(var(--palette-success));\n font-size: var(--font-size-1);\n background: rgb(var(--palette-successBackground));\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n padding: 9px 15px 9px 15px;\n border-radius: 6px;\n display: inline-block;\n}\n\n[data-supertokens~="spinner"] {\n width: 80px;\n height: auto;\n padding-top: 20px;\n padding-bottom: 40px;\n margin: 0 auto;\n}\n\n[data-supertokens~="error"] {\n color: rgb(var(--palette-error));\n}\n\n[data-supertokens~="linkButton"] {\n font-family: "Arial", sans-serif;\n background-color: transparent;\n border: 0;\n}\n\n[data-supertokens~="secondaryLinkWithLeftArrow"] {\n color: rgb(var(--palette-textGray));\n font-weight: 400;\n margin-top: 10px;\n margin-bottom: 40px;\n cursor: pointer;\n}\n\n[data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n margin-right: 0.3em;\n}\n\n[data-supertokens~="secondaryLinkWithLeftArrow"]:hover svg {\n position: relative;\n left: -4px;\n}\n\n[data-supertokens~="button"] {\n font-family: "Arial", sans-serif;\n background-color: rgb(var(--palette-primary));\n color: rgb(var(--palette-buttonText));\n width: 100%;\n height: 34px;\n font-weight: 600;\n border-width: 1px;\n border-style: solid;\n border-radius: 6px;\n border-color: rgb(var(--palette-primaryBorder));\n background-position: center;\n transition: all 0.4s;\n background-size: 12000%;\n cursor: pointer;\n}\n\n[data-supertokens~="button"]:disabled {\n border: none;\n cursor: no-drop;\n}\n\n[data-supertokens~="button"]:active {\n outline: none;\n transition: all 0s;\n background-size: 100%;\n filter: brightness(0.85);\n}\n\n[data-supertokens~="button"]:focus {\n outline: none;\n}\n\n[data-supertokens~="backButtonCommon"] {\n width: 16px;\n height: 13px;\n}\n\n[data-supertokens~="backButton"] {\n cursor: pointer;\n border: none;\n background-color: transparent;\n padding: 0px;\n}\n\n[data-supertokens~="backButtonPlaceholder"] {\n display: block;\n}\n\n[data-supertokens~="delayedRender"] {\n animation-duration: 0.1s;\n animation-name: animate-fade;\n animation-delay: 0.2s;\n animation-fill-mode: backwards;\n}\n\n@keyframes animate-fade {\n 0% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n}\n\n[data-supertokens~="footerLinkGroupVert"] {\n display: flex;\n flex-direction: column;\n margin-top: 10px;\n gap: 24px;\n}\n\n[data-supertokens~="footerLinkGroupVert"] > div {\n cursor: pointer;\n margin: 0;\n}\n\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryText"] {\n font-weight: 400;\n}\n\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n font-weight: 400;\n position: relative;\n left: -6px; /* half the width of the left arrow */\n}\n\n@media (max-width: 360px) {\n [data-supertokens~="footerLinkGroupVert"] {\n flex-direction: column;\n }\n [data-supertokens~="footerLinkGroupVert"] > div {\n margin: 0 auto;\n }\n}\n\n[data-supertokens~="footerLinkGroupVert"] div:only-child {\n margin-left: auto;\n margin-right: auto;\n margin-top: 14px;\n}\n\n[data-supertokens~="withBackButton"] {\n position: relative;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n[data-supertokens~="dividerWithOr"] {\n padding-top: 5px;\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n color: rgb(var(--palette-textPrimary));\n}\n\n[data-supertokens~="dividerText"] {\n flex: 1 1;\n font-weight: 400;\n font-size: var(--font-size-1);\n}\n\n[data-supertokens~="formLabelWithLinkWrapper"] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n[data-supertokens~="formLabelLinkBtn"] {\n width: auto;\n margin-top: 0;\n line-height: 24px;\n font-size: var(--font-size-0);\n}\n\n[data-supertokens~="formLabelLinkBtn"]:hover {\n text-decoration: underline;\n}\n\n[data-supertokens~="formLabelLinkBtn"]:disabled {\n color: rgb(var(--palette-textPrimary));\n cursor: default;\n text-decoration: none;\n}\n\n[data-supertokens~="authComponentList"] {\n padding-bottom: 20px;\n}\n\n[data-supertokens~="buttonWithArrow"] {\n border-radius: 6px;\n border: 1px solid #d0d5dd;\n width: 100%;\n color: rgb(var(--palette-textGray));\n display: flex;\n justify-content: center;\n align-items: center;\n gap: 5px;\n margin: 24px 0;\n min-height: 48px;\n cursor: pointer;\n}\n\n[data-supertokens~="buttonWithArrow"]:hover {\n background-color: rgb(var(--palette-inputBackground));\n}\n\n[data-supertokens~="buttonWithArrow"] [data-supertokens~="secondaryText"] {\n font-weight: 700;\n font-size: var(--font-size-2);\n color: rgb(var(--palette-textGray));\n margin: 0;\n}\n\n[data-supertokens~="buttonWithArrow"]:hover [data-supertokens~="secondaryLinkWithRightArrow"] ~ svg {\n position: relative;\n left: 2px;\n}\n\n[data-supertokens~="buttonWithArrow"]:hover [data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n position: relative;\n left: -2px;\n}\n\n[data-supertokens~="buttonWithArrow"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n display: flex;\n align-items: center;\n}\n\n/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved.\n *\n * This software is licensed under the Apache License, Version 2.0 (the\n * "License") as published by the Apache Software Foundation.\n *\n * You may not use this file except in compliance with the License. You may\n * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\n[data-supertokens~="inputContainer"] {\n margin-top: 6px;\n}\n\n[data-supertokens~="inputWrapper"] {\n box-sizing: border-box;\n width: 100%;\n display: flex;\n align-items: center;\n background-color: rgb(var(--palette-inputBackground));\n height: 34px;\n border-radius: 6px;\n border: 1px solid rgb(var(--palette-inputBorder));\n}\n\n[data-supertokens~="inputWrapper"][focus-within] {\n background-color: rgba(var(--palette-inputBackground), 0.25);\n border: 1px solid rgb(var(--palette-primary));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-primary), 0.25);\n outline: none;\n}\n\n[data-supertokens~="inputWrapper"]:focus-within {\n background-color: rgba(var(--palette-inputBackground), 0.25);\n border: 1px solid rgb(var(--palette-primary));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-primary), 0.25);\n outline: none;\n}\n\n[data-supertokens~="inputError"] {\n border: 1px solid rgb(var(--palette-error));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-error), 0.25);\n outline: none;\n}\n\n[data-supertokens~="inputError"][focus-within] {\n border: 1px solid rgb(var(--palette-error));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-error), 0.25);\n outline: none;\n}\n\n[data-supertokens~="inputError"]:focus-within {\n border: 1px solid rgb(var(--palette-error));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-error), 0.25);\n outline: none;\n}\n\n[data-supertokens~="input"] {\n box-sizing: border-box;\n padding-left: 15px;\n filter: none;\n color: rgb(var(--palette-textInput));\n background-color: transparent;\n border-radius: 6px;\n font-size: var(--font-size-1);\n border: none;\n padding-right: 25px;\n letter-spacing: 1.2px;\n flex: 9 1 75%;\n width: 75%;\n height: 32px;\n}\n\n[data-supertokens~="input"]:focus {\n border: none;\n outline: none;\n}\n\n[data-supertokens~="input"]:-webkit-autofill,\n[data-supertokens~="input"]:-webkit-autofill:hover,\n[data-supertokens~="input"]:-webkit-autofill:focus,\n[data-supertokens~="input"]:-webkit-autofill:active {\n -webkit-text-fill-color: rgb(var(--palette-textInput));\n box-shadow: 0 0 0 30px rgb(var(--palette-inputBackground)) inset;\n}\n\n[data-supertokens~="inputAdornment"] {\n justify-content: center;\n margin-right: 5px;\n}\n\n[data-supertokens~="showPassword"] {\n cursor: pointer;\n}\n\n[data-supertokens~="enterEmailSuccessMessage"] {\n margin-top: 15px;\n margin-bottom: 15px;\n word-break: break-word;\n}\n\n[data-supertokens~="submitNewPasswordSuccessMessage"] {\n margin-top: 15px;\n margin-bottom: 15px;\n}\n\n[data-supertokens~="inputErrorMessage"] {\n padding-top: 5px;\n padding-bottom: 5px;\n color: rgb(var(--palette-error));\n line-height: 24px;\n font-weight: 400;\n font-size: var(--font-size-1);\n text-align: left;\n animation: slideTop 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;\n max-width: 330px;\n}\n\n@media (max-width: 440px) {\n [data-supertokens~="inputErrorMessage"] {\n max-width: 250px;\n }\n}\n\n[data-supertokens~="inputErrorSymbol"] {\n margin-right: 5px;\n top: 1px;\n position: relative;\n left: 2px;\n}\n\n[data-supertokens~="label"] {\n text-align: left;\n font-weight: 700;\n font-size: var(--font-size-0);\n line-height: 24px;\n color: rgb(var(--palette-textLabel));\n}\n\n[data-supertokens~="formRow"] {\n display: flex;\n flex-direction: column;\n padding-top: 0px;\n padding-bottom: 20px;\n}\n\n[data-supertokens~="formRow"][data-supertokens~="hasError"] {\n padding-bottom: 0;\n}\n\n[data-supertokens~="formRow"]:last-child {\n padding-bottom: 0;\n}\n\n[data-supertokens~="sendVerifyEmailIcon"] {\n margin-top: 11px;\n}\n\n[data-supertokens~="primaryText"][data-supertokens~="sendVerifyEmailText"] {\n text-align: center;\n letter-spacing: 0.8px;\n color: rgb(var(--palette-textPrimary));\n}\n\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n font-weight: 700;\n}\n\n[data-supertokens~="sendVerifyEmailResend"] {\n margin-top: 13px;\n font-weight: 400;\n}\n\n[data-supertokens~="sendVerifyEmailResend"]:hover {\n text-decoration: underline;\n}\n\n[data-supertokens~="noFormRow"] {\n padding-bottom: 25px;\n}\n\n[data-supertokens~="emailVerificationButtonWrapper"] {\n padding-top: 25px;\n max-width: 96px;\n margin: 0 auto;\n}\n\n[data-supertokens~="resendEmailLink"] {\n display: inline-block;\n}\n\n[data-supertokens~="resetPasswordEmailForm"] {\n padding-bottom: 20px;\n}\n\n[data-supertokens~="resetPasswordPasswordForm"] {\n padding-bottom: 20px;\n}\n\n[data-supertokens~="generalSuccess"] {\n margin-bottom: 20px;\n animation: swingIn 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) alternate 2 both;\n}\n\n[data-supertokens~="headerSubtitle"] strong {\n max-width: 100%;\n display: inline-block;\n vertical-align: bottom;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n[data-supertokens~="primaryText"][data-supertokens~="sendCodeText"] {\n margin-top: 15px;\n margin-bottom: 20px;\n color: rgb(var(--palette-textPrimary));\n}\n\n[data-supertokens~="sendCodeText"] strong {\n max-width: 100%;\n display: inline-block;\n vertical-align: bottom;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n[data-supertokens~="phoneInputLibRoot"] {\n display: flex;\n align-items: center;\n}\n\n[data-supertokens~="phoneInputWrapper"] {\n display: flex;\n align-items: center;\n}\n\ninput[type="tel"][data-supertokens~="input-phoneNumber"] {\n padding-left: 15px;\n}\n\n[data-supertokens~="phoneInputWrapper"] .iti {\n flex: 1 1;\n min-width: 0;\n width: 100%;\n background: transparent;\n border: none;\n color: inherit;\n outline: none;\n}\n\n[data-supertokens~="continueButtonWrapper"] {\n margin-top: 10px;\n margin-bottom: 30px;\n}\n\n.iti__country-list {\n border: 0;\n top: 40px;\n width: min(72.2vw, 320px);\n border-radius: 6;\n box-shadow: 0px 0px 3px 0px rgba(0, 0, 0, 0.16);\n}\n\n.iti__country {\n display: flex;\n align-items: center;\n height: 34px;\n cursor: pointer;\n\n padding: 0 8px;\n}\n\n.iti__country-name {\n color: var(--palette-textLabel);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n margin: "0 16px";\n}\n\n[data-supertokens~="continueWithPasswordlessButtonWrapper"] {\n margin: 9px 0;\n}\n\n[data-supertokens~="continueWithPasswordlessLink"] {\n margin-top: 9px;\n}\n';
+ '/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved.\n *\n * This software is licensed under the Apache License, Version 2.0 (the\n * "License") as published by the Apache Software Foundation.\n *\n * You may not use this file except in compliance with the License. You may\n * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\n[data-supertokens~="container"] {\n --palette-background: 255, 255, 255;\n --palette-inputBackground: 250, 250, 250;\n --palette-inputBorder: 224, 224, 224;\n --palette-primary: 28, 34, 42;\n --palette-primaryBorder: 45, 54, 68;\n --palette-success: 65, 167, 0;\n --palette-successBackground: 217, 255, 191;\n --palette-error: 255, 23, 23;\n --palette-errorBackground: 255, 241, 235;\n --palette-textTitle: 0, 0, 0;\n --palette-textLabel: 0, 0, 0;\n --palette-textInput: 0, 0, 0;\n --palette-textPrimary: 128, 128, 128;\n --palette-textLink: 0, 122, 255;\n --palette-buttonText: 255, 255, 255;\n --palette-textGray: 54, 54, 54;\n --palette-superTokensBrandingBackground: 242, 245, 246;\n --palette-superTokensBrandingText: 173, 189, 196;\n\n --font-size-0: 12px;\n --font-size-1: 14px;\n --font-size-2: 16px;\n --font-size-3: 19px;\n --font-size-4: 24px;\n --font-size-5: 28px;\n}\n\n/*\n * Default styles.\n */\n\n@keyframes slideTop {\n 0% {\n transform: translateY(-5px);\n }\n 100% {\n transform: translateY(0px);\n }\n}\n\n@keyframes swing-in-top-fwd {\n 0% {\n transform: rotateX(-100deg);\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n transform: rotateX(0deg);\n transform-origin: top;\n opacity: 1;\n }\n}\n\n[data-supertokens~="container"] {\n font-family: "Arial", sans-serif;\n margin: 12px auto;\n margin-top: 26px;\n margin-bottom: 26px;\n width: 420px;\n text-align: center;\n border-radius: 8px;\n box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.16);\n background-color: rgb(var(--palette-background));\n}\n\n@media (max-width: 440px) {\n [data-supertokens~="container"] {\n width: 95vw;\n }\n}\n\n[data-supertokens~="row"] {\n margin: 0 auto;\n width: 76%;\n padding-top: 30px;\n padding-bottom: 10px;\n}\n\n[data-supertokens~="superTokensBranding"] {\n display: block;\n margin: 10px auto 0;\n background: rgb(var(--palette-superTokensBrandingBackground));\n color: rgb(var(--palette-superTokensBrandingText));\n text-decoration: none;\n width: -webkit-fit-content;\n width: -moz-fit-content;\n width: fit-content;\n border-radius: 6px 6px 0 0;\n padding: 4px 9px;\n font-weight: 400;\n font-size: var(--font-size-0);\n letter-spacing: 0.4px;\n}\n\n[data-supertokens~="generalError"] {\n background: rgb(var(--palette-errorBackground));\n padding-top: 10px;\n padding-bottom: 10px;\n margin-bottom: 10px;\n margin-top: 24px;\n padding-left: 18px;\n padding-right: 18px;\n letter-spacing: 0.2px;\n font-size: var(--font-size-1);\n border-radius: 8px;\n color: rgb(var(--palette-error));\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n word-wrap: break-word;\n}\n\n[data-supertokens~="headerTitle"] {\n font-size: var(--font-size-4);\n line-height: 27.6px;\n letter-spacing: 0.58px;\n font-weight: 700;\n margin-bottom: 20px;\n color: rgb(var(--palette-textTitle));\n}\n\n[data-supertokens~="headerSubtitle"] {\n font-weight: 400;\n color: rgb(var(--palette-textGray));\n margin-bottom: 21px;\n}\n\n[data-supertokens~="headerSubtitle"][data-supertokens~="secondaryText"] {\n color: rgb(var(--palette-textGray));\n font-weight: 400;\n}\n\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] {\n max-width: 300px;\n margin-top: 10px;\n}\n\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] a {\n line-height: 21px;\n}\n\n/* TODO: split the link style into separate things*/\n\n/* We add this before primary and secondary text, because if they are applied to the same element the other ones take priority */\n\n[data-supertokens~="link"] {\n padding-left: 3px;\n padding-right: 3px;\n color: rgb(var(--palette-textLink));\n font-size: var(--font-size-1);\n cursor: pointer;\n letter-spacing: 0.16px;\n line-height: 26px;\n}\n\n[data-supertokens~="primaryText"] {\n font-size: var(--font-size-2);\n font-weight: 400;\n letter-spacing: 0.4px;\n line-height: 21px;\n color: rgb(var(--palette-textLabel));\n}\n\n[data-supertokens~="secondaryText"] {\n font-size: var(--font-size-1);\n font-weight: 400;\n letter-spacing: 0.4px;\n color: rgb(var(--palette-textPrimary));\n}\n\n[data-supertokens~="secondaryText"] strong {\n font-weight: 600;\n}\n\n[data-supertokens~="divider"] {\n margin-top: 1.5em;\n margin-bottom: 1.5em;\n border-bottom: 0.3px solid #dddddd;\n align-items: center;\n padding-bottom: 5px;\n flex: 3 3;\n}\n\n[data-supertokens~="headerTinyTitle"] {\n margin-top: 24px;\n font-size: var(--font-size-5);\n letter-spacing: 1.1px;\n font-weight: 700;\n line-height: 28px;\n}\n\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n}\n\n[data-supertokens~="secondaryLinkWithArrow"]:hover {\n position: relative;\n left: 2px;\n word-spacing: 4px;\n}\n\n[data-supertokens~="generalSuccess"] {\n color: rgb(var(--palette-success));\n font-size: var(--font-size-1);\n background: rgb(var(--palette-successBackground));\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n padding: 9px 15px 9px 15px;\n border-radius: 6px;\n display: inline-block;\n}\n\n[data-supertokens~="spinner"] {\n width: 80px;\n height: auto;\n padding-top: 20px;\n padding-bottom: 40px;\n margin: 0 auto;\n}\n\n[data-supertokens~="error"] {\n color: rgb(var(--palette-error));\n}\n\n[data-supertokens~="linkButton"] {\n font-family: "Arial", sans-serif;\n background-color: transparent;\n border: 0;\n}\n\n[data-supertokens~="secondaryLinkWithLeftArrow"] {\n color: rgb(var(--palette-textGray));\n font-weight: 400;\n margin-top: 10px;\n margin-bottom: 40px;\n cursor: pointer;\n}\n\n[data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n margin-right: 0.3em;\n}\n\n[data-supertokens~="secondaryLinkWithLeftArrow"]:hover svg {\n position: relative;\n left: -4px;\n}\n\n[data-supertokens~="button"] {\n font-family: "Arial", sans-serif;\n background-color: rgb(var(--palette-primary));\n color: rgb(var(--palette-buttonText));\n width: 100%;\n height: 34px;\n font-weight: 600;\n border-width: 1px;\n border-style: solid;\n border-radius: 6px;\n border-color: rgb(var(--palette-primaryBorder));\n background-position: center;\n transition: all 0.4s;\n background-size: 12000%;\n cursor: pointer;\n}\n\n[data-supertokens~="button"]:disabled {\n border: none;\n cursor: no-drop;\n}\n\n[data-supertokens~="button"]:active {\n outline: none;\n transition: all 0s;\n background-size: 100%;\n filter: brightness(0.85);\n}\n\n[data-supertokens~="button"]:focus {\n outline: none;\n}\n\n[data-supertokens~="backButtonCommon"] {\n width: 16px;\n height: 13px;\n}\n\n[data-supertokens~="backButton"] {\n cursor: pointer;\n border: none;\n background-color: transparent;\n padding: 0px;\n}\n\n[data-supertokens~="backButtonPlaceholder"] {\n display: block;\n}\n\n[data-supertokens~="delayedRender"] {\n animation-duration: 0.1s;\n animation-name: animate-fade;\n animation-delay: 0.2s;\n animation-fill-mode: backwards;\n}\n\n@keyframes animate-fade {\n 0% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n}\n\n[data-supertokens~="footerLinkGroupVert"] {\n display: flex;\n flex-direction: column;\n margin-top: 10px;\n gap: 24px;\n}\n\n[data-supertokens~="footerLinkGroupVert"] > div {\n cursor: pointer;\n margin: 0;\n}\n\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryText"] {\n font-weight: 400;\n}\n\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n font-weight: 400;\n position: relative;\n left: -6px; /* half the width of the left arrow */\n}\n\n@media (max-width: 360px) {\n [data-supertokens~="footerLinkGroupVert"] {\n flex-direction: column;\n }\n [data-supertokens~="footerLinkGroupVert"] > div {\n margin: 0 auto;\n }\n}\n\n[data-supertokens~="footerLinkGroupVert"] div:only-child {\n margin-left: auto;\n margin-right: auto;\n margin-top: 14px;\n}\n\n[data-supertokens~="withBackButton"] {\n position: relative;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n[data-supertokens~="dividerWithOr"] {\n padding-top: 5px;\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n color: rgb(var(--palette-textPrimary));\n}\n\n[data-supertokens~="dividerText"] {\n flex: 1 1;\n font-weight: 400;\n font-size: var(--font-size-1);\n}\n\n[data-supertokens~="formLabelWithLinkWrapper"] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n[data-supertokens~="formLabelLinkBtn"] {\n width: auto;\n margin-top: 0;\n line-height: 24px;\n font-size: var(--font-size-0);\n}\n\n[data-supertokens~="formLabelLinkBtn"]:hover {\n text-decoration: underline;\n}\n\n[data-supertokens~="formLabelLinkBtn"]:disabled {\n color: rgb(var(--palette-textPrimary));\n cursor: default;\n text-decoration: none;\n}\n\n[data-supertokens~="authComponentList"] {\n padding-bottom: 20px;\n}\n\n[data-supertokens~="authPageTitleOAuthClient"] {\n color: rgb(var(--palette-textGray));\n font-size: var(--font-size-1);\n font-weight: 400;\n margin: 10px 0 25px;\n}\n\n[data-supertokens~="authPageTitleOAuthClientUrl"] {\n text-decoration: none;\n}\n\n[data-supertokens~="authPageTitleOAuthClientLogo"] {\n width: 44px;\n height: 44px;\n margin-bottom: 10px;\n}\n\n[data-supertokens~="authPageTitleOAuthClient"] [data-supertokens~="authPageTitleOAuthClientName"] {\n color: rgb(var(--palette-textTitle));\n}\n\n[data-supertokens~="buttonWithArrow"] {\n border-radius: 6px;\n border: 1px solid #d0d5dd;\n width: 100%;\n color: rgb(var(--palette-textGray));\n display: flex;\n justify-content: center;\n align-items: center;\n gap: 5px;\n margin: 24px 0;\n min-height: 48px;\n cursor: pointer;\n}\n\n[data-supertokens~="buttonWithArrow"]:hover {\n background-color: rgb(var(--palette-inputBackground));\n}\n\n[data-supertokens~="buttonWithArrow"] [data-supertokens~="secondaryText"] {\n font-weight: 700;\n font-size: var(--font-size-2);\n color: rgb(var(--palette-textGray));\n margin: 0;\n}\n\n[data-supertokens~="buttonWithArrow"]:hover [data-supertokens~="secondaryLinkWithRightArrow"] ~ svg {\n position: relative;\n left: 2px;\n}\n\n[data-supertokens~="buttonWithArrow"]:hover [data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n position: relative;\n left: -2px;\n}\n\n[data-supertokens~="buttonWithArrow"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n display: flex;\n align-items: center;\n}\n\n/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved.\n *\n * This software is licensed under the Apache License, Version 2.0 (the\n * "License") as published by the Apache Software Foundation.\n *\n * You may not use this file except in compliance with the License. You may\n * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\n[data-supertokens~="inputContainer"] {\n margin-top: 6px;\n}\n\n[data-supertokens~="inputWrapper"] {\n box-sizing: border-box;\n width: 100%;\n display: flex;\n align-items: center;\n background-color: rgb(var(--palette-inputBackground));\n height: 34px;\n border-radius: 6px;\n border: 1px solid rgb(var(--palette-inputBorder));\n}\n\n[data-supertokens~="inputWrapper"][focus-within] {\n background-color: rgba(var(--palette-inputBackground), 0.25);\n border: 1px solid rgb(var(--palette-primary));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-primary), 0.25);\n outline: none;\n}\n\n[data-supertokens~="inputWrapper"]:focus-within {\n background-color: rgba(var(--palette-inputBackground), 0.25);\n border: 1px solid rgb(var(--palette-primary));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-primary), 0.25);\n outline: none;\n}\n\n[data-supertokens~="inputError"] {\n border: 1px solid rgb(var(--palette-error));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-error), 0.25);\n outline: none;\n}\n\n[data-supertokens~="inputError"][focus-within] {\n border: 1px solid rgb(var(--palette-error));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-error), 0.25);\n outline: none;\n}\n\n[data-supertokens~="inputError"]:focus-within {\n border: 1px solid rgb(var(--palette-error));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-error), 0.25);\n outline: none;\n}\n\n[data-supertokens~="input"] {\n box-sizing: border-box;\n padding-left: 15px;\n filter: none;\n color: rgb(var(--palette-textInput));\n background-color: transparent;\n border-radius: 6px;\n font-size: var(--font-size-1);\n border: none;\n padding-right: 25px;\n letter-spacing: 1.2px;\n flex: 9 1 75%;\n width: 75%;\n height: 32px;\n}\n\n[data-supertokens~="input"]:focus {\n border: none;\n outline: none;\n}\n\n[data-supertokens~="input"]:-webkit-autofill,\n[data-supertokens~="input"]:-webkit-autofill:hover,\n[data-supertokens~="input"]:-webkit-autofill:focus,\n[data-supertokens~="input"]:-webkit-autofill:active {\n -webkit-text-fill-color: rgb(var(--palette-textInput));\n box-shadow: 0 0 0 30px rgb(var(--palette-inputBackground)) inset;\n}\n\n[data-supertokens~="inputAdornment"] {\n justify-content: center;\n margin-right: 5px;\n}\n\n[data-supertokens~="showPassword"] {\n cursor: pointer;\n}\n\n[data-supertokens~="enterEmailSuccessMessage"] {\n margin-top: 15px;\n margin-bottom: 15px;\n word-break: break-word;\n}\n\n[data-supertokens~="submitNewPasswordSuccessMessage"] {\n margin-top: 15px;\n margin-bottom: 15px;\n}\n\n[data-supertokens~="inputErrorMessage"] {\n padding-top: 5px;\n padding-bottom: 5px;\n color: rgb(var(--palette-error));\n line-height: 24px;\n font-weight: 400;\n font-size: var(--font-size-1);\n text-align: left;\n animation: slideTop 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;\n max-width: 330px;\n}\n\n@media (max-width: 440px) {\n [data-supertokens~="inputErrorMessage"] {\n max-width: 250px;\n }\n}\n\n[data-supertokens~="inputErrorSymbol"] {\n margin-right: 5px;\n top: 1px;\n position: relative;\n left: 2px;\n}\n\n[data-supertokens~="label"] {\n text-align: left;\n font-weight: 700;\n font-size: var(--font-size-0);\n line-height: 24px;\n color: rgb(var(--palette-textLabel));\n}\n\n[data-supertokens~="formRow"] {\n display: flex;\n flex-direction: column;\n padding-top: 0px;\n padding-bottom: 20px;\n}\n\n[data-supertokens~="formRow"][data-supertokens~="hasError"] {\n padding-bottom: 0;\n}\n\n[data-supertokens~="formRow"]:last-child {\n padding-bottom: 0;\n}\n\n[data-supertokens~="sendVerifyEmailIcon"] {\n margin-top: 11px;\n}\n\n[data-supertokens~="primaryText"][data-supertokens~="sendVerifyEmailText"] {\n text-align: center;\n letter-spacing: 0.8px;\n color: rgb(var(--palette-textPrimary));\n}\n\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n font-weight: 700;\n}\n\n[data-supertokens~="sendVerifyEmailResend"] {\n margin-top: 13px;\n font-weight: 400;\n}\n\n[data-supertokens~="sendVerifyEmailResend"]:hover {\n text-decoration: underline;\n}\n\n[data-supertokens~="noFormRow"] {\n padding-bottom: 25px;\n}\n\n[data-supertokens~="emailVerificationButtonWrapper"] {\n padding-top: 25px;\n max-width: 96px;\n margin: 0 auto;\n}\n\n[data-supertokens~="resendEmailLink"] {\n display: inline-block;\n}\n\n[data-supertokens~="resetPasswordEmailForm"] {\n padding-bottom: 20px;\n}\n\n[data-supertokens~="resetPasswordPasswordForm"] {\n padding-bottom: 20px;\n}\n\n[data-supertokens~="generalSuccess"] {\n margin-bottom: 20px;\n animation: swingIn 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) alternate 2 both;\n}\n\n[data-supertokens~="headerSubtitle"] strong {\n max-width: 100%;\n display: inline-block;\n vertical-align: bottom;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n[data-supertokens~="primaryText"][data-supertokens~="sendCodeText"] {\n margin-top: 15px;\n margin-bottom: 20px;\n color: rgb(var(--palette-textPrimary));\n}\n\n[data-supertokens~="sendCodeText"] strong {\n max-width: 100%;\n display: inline-block;\n vertical-align: bottom;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n[data-supertokens~="phoneInputLibRoot"] {\n display: flex;\n align-items: center;\n}\n\n[data-supertokens~="phoneInputWrapper"] {\n display: flex;\n align-items: center;\n}\n\ninput[type="tel"][data-supertokens~="input-phoneNumber"] {\n padding-left: 15px;\n}\n\n[data-supertokens~="phoneInputWrapper"] .iti {\n flex: 1 1;\n min-width: 0;\n width: 100%;\n background: transparent;\n border: none;\n color: inherit;\n outline: none;\n}\n\n[data-supertokens~="continueButtonWrapper"] {\n margin-top: 10px;\n margin-bottom: 30px;\n}\n\n.iti__country-list {\n border: 0;\n top: 40px;\n width: min(72.2vw, 320px);\n border-radius: 6;\n box-shadow: 0px 0px 3px 0px rgba(0, 0, 0, 0.16);\n}\n\n.iti__country {\n display: flex;\n align-items: center;\n height: 34px;\n cursor: pointer;\n\n padding: 0 8px;\n}\n\n.iti__country-name {\n color: var(--palette-textLabel);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n margin: "0 16px";\n}\n\n[data-supertokens~="continueWithPasswordlessButtonWrapper"] {\n margin: 9px 0;\n}\n\n[data-supertokens~="continueWithPasswordlessLink"] {\n margin-top: 9px;\n}\n';
var ThemeBase = function (_a) {
var children = _a.children,
@@ -482,6 +484,8 @@ var LinkClickedScreen = function (props) {
(payloadBeforeCall === undefined ||
payloadBeforeCall.sessionHandle !== payloadAfterCall.sessionHandle),
recipeId: props.recipe.recipeID,
+ tenantIdFromQueryParams:
+ genericComponentOverrideContext.getTenantIdFromQueryParams(),
},
props.recipe.recipeID,
loginAttemptInfo === null || loginAttemptInfo === void 0
@@ -1005,6 +1009,8 @@ function useChildProps$4(
session$1.accessTokenPayload.sessionHandle !==
payloadAfterCall.sessionHandle),
recipeId: recipe$1.recipeID,
+ tenantIdFromQueryParams:
+ genericComponentOverrideContext.getTenantIdFromQueryParams(),
},
recipe$1.recipeID,
genericComponentOverrideContext.getRedirectToPathFromURL(),
@@ -1053,6 +1059,8 @@ function useChildProps$4(
4 /*yield*/,
evInstance.redirect(
{
+ tenantIdFromQueryParams:
+ genericComponentOverrideContext.getTenantIdFromQueryParams(),
action: "VERIFY_EMAIL",
},
navigate,
@@ -1131,12 +1139,13 @@ function getModifiedRecipeImplementation$4(originalImpl, setError, rebuildAuthPa
resendCode: function (input) {
return genericComponentOverrideContext.__awaiter(_this, void 0, void 0, function () {
var res, loginAttemptInfo, timestamp;
- return genericComponentOverrideContext.__generator(this, function (_a) {
- switch (_a.label) {
+ var _a;
+ return genericComponentOverrideContext.__generator(this, function (_b) {
+ switch (_b.label) {
case 0:
return [4 /*yield*/, originalImpl.resendCode(input)];
case 1:
- res = _a.sent();
+ res = _b.sent();
if (!(res.status === "OK")) return [3 /*break*/, 5];
return [
4 /*yield*/,
@@ -1145,7 +1154,7 @@ function getModifiedRecipeImplementation$4(originalImpl, setError, rebuildAuthPa
}),
];
case 2:
- loginAttemptInfo = _a.sent();
+ loginAttemptInfo = _b.sent();
if (!(loginAttemptInfo !== undefined)) return [3 /*break*/, 4];
timestamp = Date.now();
return [
@@ -1154,13 +1163,20 @@ function getModifiedRecipeImplementation$4(originalImpl, setError, rebuildAuthPa
userContext: input.userContext,
attemptInfo: genericComponentOverrideContext.__assign(
genericComponentOverrideContext.__assign({}, loginAttemptInfo),
- { lastResend: timestamp }
+ {
+ shouldTryLinkingWithSessionUser:
+ (_a = loginAttemptInfo.shouldTryLinkingWithSessionUser) !== null &&
+ _a !== void 0
+ ? _a
+ : false,
+ lastResend: timestamp,
+ }
),
}),
];
case 3:
- _a.sent();
- _a.label = 4;
+ _b.sent();
+ _b.label = 4;
case 4:
return [3 /*break*/, 7];
case 5:
@@ -1172,10 +1188,10 @@ function getModifiedRecipeImplementation$4(originalImpl, setError, rebuildAuthPa
}),
];
case 6:
- _a.sent();
+ _b.sent();
setError("ERROR_SIGN_IN_UP_RESEND_RESTART_FLOW");
rebuildAuthPage();
- _a.label = 7;
+ _b.label = 7;
case 7:
return [2 /*return*/, res];
}
@@ -1355,6 +1371,7 @@ var EmailForm = uiEntry.withOverride("PasswordlessEmailForm", function Passwordl
4 /*yield*/,
props.recipeImplementation.createCode({
email: email,
+ // shouldTryLinkingWithSessionUser is set by the fn override
userContext: userContext,
}),
];
@@ -3515,6 +3532,7 @@ var PhoneForm = uiEntry.withOverride("PasswordlessPhoneForm", function Passwordl
4 /*yield*/,
props.recipeImplementation.createCode({
phoneNumber: phoneNumber,
+ // shouldTryLinkingWithSessionUser is set by the fn override
userContext: userContext,
}),
];
@@ -4408,6 +4426,8 @@ function useChildProps$3(recipe$1, recipeImplementation, state, contactMethod, d
evInstance.redirect(
{
action: "VERIFY_EMAIL",
+ tenantIdFromQueryParams:
+ genericComponentOverrideContext.getTenantIdFromQueryParams(),
},
navigate,
undefined,
@@ -4664,7 +4684,7 @@ function useOnLoad(props, recipeImplementation, dispatch, userContext) {
recipeImplementation.createCode(
genericComponentOverrideContext.__assign(
genericComponentOverrideContext.__assign({}, createCodeInfo),
- { userContext: userContext }
+ { shouldTryLinkingWithSessionUser: true, userContext: userContext }
)
),
];
@@ -4701,6 +4721,8 @@ function useOnLoad(props, recipeImplementation, dispatch, userContext) {
4 /*yield*/,
evInstance.redirect(
{
+ tenantIdFromQueryParams:
+ genericComponentOverrideContext.getTenantIdFromQueryParams(),
action: "VERIFY_EMAIL",
},
props.navigate,
@@ -4804,6 +4826,7 @@ function getModifiedRecipeImplementation$3(originalImpl, config, dispatch) {
genericComponentOverrideContext.__assign(
genericComponentOverrideContext.__assign({}, input),
{
+ shouldTryLinkingWithSessionUser: true,
userContext: genericComponentOverrideContext.__assign(
genericComponentOverrideContext.__assign({}, input.userContext),
{ additionalAttemptInfo: additionalAttemptInfo }
@@ -4834,12 +4857,13 @@ function getModifiedRecipeImplementation$3(originalImpl, config, dispatch) {
resendCode: function (input) {
return genericComponentOverrideContext.__awaiter(_this, void 0, void 0, function () {
var res, loginAttemptInfo, timestamp;
- return genericComponentOverrideContext.__generator(this, function (_a) {
- switch (_a.label) {
+ var _a;
+ return genericComponentOverrideContext.__generator(this, function (_b) {
+ switch (_b.label) {
case 0:
return [4 /*yield*/, originalImpl.resendCode(input)];
case 1:
- res = _a.sent();
+ res = _b.sent();
if (!(res.status === "OK")) return [3 /*break*/, 5];
return [
4 /*yield*/,
@@ -4848,7 +4872,7 @@ function getModifiedRecipeImplementation$3(originalImpl, config, dispatch) {
}),
];
case 2:
- loginAttemptInfo = _a.sent();
+ loginAttemptInfo = _b.sent();
if (!(loginAttemptInfo !== undefined)) return [3 /*break*/, 4];
timestamp = Date.now();
return [
@@ -4857,14 +4881,21 @@ function getModifiedRecipeImplementation$3(originalImpl, config, dispatch) {
userContext: input.userContext,
attemptInfo: genericComponentOverrideContext.__assign(
genericComponentOverrideContext.__assign({}, loginAttemptInfo),
- { lastResend: timestamp }
+ {
+ shouldTryLinkingWithSessionUser:
+ (_a = loginAttemptInfo.shouldTryLinkingWithSessionUser) !== null &&
+ _a !== void 0
+ ? _a
+ : true,
+ lastResend: timestamp,
+ }
),
}),
];
case 3:
- _a.sent();
+ _b.sent();
dispatch({ type: "resendCode", timestamp: timestamp });
- _a.label = 4;
+ _b.label = 4;
case 4:
return [3 /*break*/, 7];
case 5:
@@ -4876,9 +4907,9 @@ function getModifiedRecipeImplementation$3(originalImpl, config, dispatch) {
}),
];
case 6:
- _a.sent();
+ _b.sent();
dispatch({ type: "restartFlow", error: "ERROR_SIGN_IN_UP_RESEND_RESTART_FLOW" });
- _a.label = 7;
+ _b.label = 7;
case 7:
return [2 /*return*/, res];
}
@@ -4891,7 +4922,15 @@ function getModifiedRecipeImplementation$3(originalImpl, config, dispatch) {
return genericComponentOverrideContext.__generator(this, function (_a) {
switch (_a.label) {
case 0:
- return [4 /*yield*/, originalImpl.consumeCode(input)];
+ return [
+ 4 /*yield*/,
+ originalImpl.consumeCode(
+ genericComponentOverrideContext.__assign(
+ genericComponentOverrideContext.__assign({}, input),
+ { shouldTryLinkingWithSessionUser: true }
+ )
+ ),
+ ];
case 1:
res = _a.sent();
if (!(res.status === "RESTART_FLOW_ERROR")) return [3 /*break*/, 3];
@@ -5115,7 +5154,10 @@ var EmailOrPhoneForm = uiEntry.withOverride(
props.recipeImplementation.createCode(
genericComponentOverrideContext.__assign(
genericComponentOverrideContext.__assign({}, contactInfo),
- { userContext: userContext }
+ {
+ // shouldTryLinkingWithSessionUser is set by the fn override
+ userContext: userContext,
+ }
)
),
];
@@ -5209,7 +5251,17 @@ function getActiveScreen$1(factorIds) {
}
}
-function useChildProps$2(recipe$1, factorIds, error, onError, clearError, rebuildAuthPage, userContext, navigate) {
+function useChildProps$2(
+ recipe$1,
+ factorIds,
+ onAuthSuccess,
+ error,
+ onError,
+ clearError,
+ rebuildAuthPage,
+ userContext,
+ navigate
+) {
var _this = this;
var session$1 = uiEntry.useSessionContext();
var recipeImplementation = React__namespace.useMemo(
@@ -5249,28 +5301,18 @@ function useChildProps$2(recipe$1, factorIds, error, onError, clearError, rebuil
case 3:
return [
2 /*return*/,
- types.Session.getInstanceOrThrow()
- .validateGlobalClaimsAndHandleSuccessRedirection(
- {
- action: "SUCCESS",
- createdNewUser:
- result.createdNewRecipeUser &&
- result.user.loginMethods.length === 1,
- isNewRecipeUser: result.createdNewRecipeUser,
- newSessionCreated:
- session$1.loading ||
- !session$1.doesSessionExist ||
- (payloadAfterCall !== undefined &&
- session$1.accessTokenPayload.sessionHandle !==
- payloadAfterCall.sessionHandle),
- recipeId: recipe$1.recipeID,
- },
- recipe$1.recipeID,
- genericComponentOverrideContext.getRedirectToPathFromURL(),
- userContext,
- navigate
- )
- .catch(rethrowInRender),
+ onAuthSuccess({
+ createdNewUser:
+ result.createdNewRecipeUser && result.user.loginMethods.length === 1,
+ isNewRecipeUser: result.createdNewRecipeUser,
+ newSessionCreated:
+ session$1.loading ||
+ !session$1.doesSessionExist ||
+ (payloadAfterCall !== undefined &&
+ session$1.accessTokenPayload.sessionHandle !==
+ payloadAfterCall.sessionHandle),
+ recipeId: "passwordless",
+ }).catch(rethrowInRender),
];
}
});
@@ -5316,6 +5358,8 @@ function useChildProps$2(recipe$1, factorIds, error, onError, clearError, rebuil
evInstance.redirect(
{
action: "VERIFY_EMAIL",
+ tenantIdFromQueryParams:
+ genericComponentOverrideContext.getTenantIdFromQueryParams(),
},
navigate,
undefined,
@@ -5355,6 +5399,7 @@ var SignInUpFeatureInner = function (props) {
var childProps = useChildProps$2(
props.recipe,
props.factorIds,
+ props.onAuthSuccess,
props.error,
props.onError,
props.clearError,
@@ -5423,6 +5468,7 @@ function getModifiedRecipeImplementation$2(originalImpl, config, rebuildAuthPage
genericComponentOverrideContext.__assign(
genericComponentOverrideContext.__assign({}, input),
{
+ shouldTryLinkingWithSessionUser: false,
userContext: genericComponentOverrideContext.__assign(
genericComponentOverrideContext.__assign({}, input.userContext),
{ additionalAttemptInfo: additionalAttemptInfo }
@@ -5559,6 +5605,8 @@ var EPComboEmailForm = uiEntry.withOverride(
onClick: function () {
return recipe$1.EmailPassword.getInstanceOrThrow().redirect({
action: "RESET_PASSWORD",
+ tenantIdFromQueryParams:
+ genericComponentOverrideContext.getTenantIdFromQueryParams(),
});
},
"data-supertokens": "link linkButton formLabelLinkBtn forgotPasswordLink",
@@ -5740,6 +5788,8 @@ var EPComboEmailOrPhoneForm = uiEntry.withOverride(
onClick: function () {
return recipe$1.EmailPassword.getInstanceOrThrow().redirect({
action: "RESET_PASSWORD",
+ tenantIdFromQueryParams:
+ genericComponentOverrideContext.getTenantIdFromQueryParams(),
});
},
"data-supertokens": "link linkButton formLabelLinkBtn forgotPasswordLink",
@@ -5877,7 +5927,17 @@ function getActiveScreen(factorIds) {
}
}
-function useChildProps$1(recipe$2, factorIds, error, onError, clearError, rebuildAuthPage, userContext, navigate) {
+function useChildProps$1(
+ recipe$2,
+ factorIds,
+ onAuthSuccess,
+ error,
+ onError,
+ clearError,
+ rebuildAuthPage,
+ userContext,
+ navigate
+) {
var _this = this;
var session$1 = uiEntry.useSessionContext();
var recipeImplementation = React__namespace.useMemo(
@@ -5929,6 +5989,7 @@ function useChildProps$1(recipe$2, factorIds, error, onError, clearError, rebuil
4 /*yield*/,
recipeImplementation.createCode({
phoneNumber: contactInfo,
+ shouldTryLinkingWithSessionUser: false,
userContext: userContext,
}),
];
@@ -5973,7 +6034,11 @@ function useChildProps$1(recipe$2, factorIds, error, onError, clearError, rebuil
if (!pwlessExists.doesExist) return [3 /*break*/, 6];
return [
4 /*yield*/,
- recipeImplementation.createCode({ email: email, userContext: userContext }),
+ recipeImplementation.createCode({
+ email: email,
+ shouldTryLinkingWithSessionUser: false,
+ userContext: userContext,
+ }),
];
case 5:
createRes = _b.sent();
@@ -6024,6 +6089,7 @@ function useChildProps$1(recipe$2, factorIds, error, onError, clearError, rebuil
4 /*yield*/,
recipe$1.EmailPassword.getInstanceOrThrow().webJSRecipe.signIn({
formFields: formFields,
+ shouldTryLinkingWithSessionUser: false,
userContext: userContext,
}),
];
@@ -6060,7 +6126,7 @@ function useChildProps$1(recipe$2, factorIds, error, onError, clearError, rebuil
recipeImplementation.createCode(
genericComponentOverrideContext.__assign(
genericComponentOverrideContext.__assign({}, createInfo),
- { userContext: userContext }
+ { shouldTryLinkingWithSessionUser: false, userContext: userContext }
)
),
];
@@ -6104,32 +6170,20 @@ function useChildProps$1(recipe$2, factorIds, error, onError, clearError, rebuil
case 4:
return [
2 /*return*/,
- types.Session.getInstanceOrThrow()
- .validateGlobalClaimsAndHandleSuccessRedirection(
- {
- action: "SUCCESS",
- createdNewUser:
- result.createdNewRecipeUser &&
- result.user.loginMethods.length === 1,
- isNewRecipeUser: result.createdNewRecipeUser,
- newSessionCreated:
- session$1.loading ||
- !session$1.doesSessionExist ||
- (payloadAfterCall !== undefined &&
- session$1.accessTokenPayload.sessionHandle !==
- payloadAfterCall.sessionHandle),
- recipeId: result.isEmailPassword
- ? recipe$1.EmailPassword.RECIPE_ID
- : recipe$2.recipeID,
- },
- result.isEmailPassword
- ? recipe$1.EmailPassword.RECIPE_ID
- : recipe$2.recipeID,
- genericComponentOverrideContext.getRedirectToPathFromURL(),
- userContext,
- navigate
- )
- .catch(rethrowInRender),
+ onAuthSuccess({
+ createdNewUser:
+ result.createdNewRecipeUser && result.user.loginMethods.length === 1,
+ isNewRecipeUser: result.createdNewRecipeUser,
+ newSessionCreated:
+ session$1.loading ||
+ !session$1.doesSessionExist ||
+ (payloadAfterCall !== undefined &&
+ session$1.accessTokenPayload.sessionHandle !==
+ payloadAfterCall.sessionHandle),
+ recipeId: result.isEmailPassword
+ ? recipe$1.EmailPassword.RECIPE_ID
+ : recipe$2.recipeID,
+ }).catch(rethrowInRender),
];
}
});
@@ -6175,6 +6229,8 @@ function useChildProps$1(recipe$2, factorIds, error, onError, clearError, rebuil
evInstance.redirect(
{
action: "VERIFY_EMAIL",
+ tenantIdFromQueryParams:
+ genericComponentOverrideContext.getTenantIdFromQueryParams(),
},
navigate,
undefined,
@@ -6222,6 +6278,7 @@ var SignInUpEPComboFeatureInner = function (props) {
var childProps = useChildProps$1(
props.recipe,
props.factorIds,
+ props.onAuthSuccess,
props.error,
props.onError,
props.clearError,
@@ -6295,6 +6352,7 @@ function getModifiedRecipeImplementation$1(originalImpl, config, rebuildAuthPage
genericComponentOverrideContext.__assign(
genericComponentOverrideContext.__assign({}, input),
{
+ shouldTryLinkingWithSessionUser: false,
userContext: genericComponentOverrideContext.__assign(
genericComponentOverrideContext.__assign({}, input.userContext),
{ additionalAttemptInfo: additionalAttemptInfo }
@@ -6316,7 +6374,17 @@ function getModifiedRecipeImplementation$1(originalImpl, config, rebuildAuthPage
});
}
-function useChildProps(recipe$1, loginAttemptInfo, error, onError, clearError, rebuildAuthPage, userContext, navigate) {
+function useChildProps(
+ recipe$1,
+ loginAttemptInfo,
+ onAuthSuccess,
+ error,
+ onError,
+ clearError,
+ rebuildAuthPage,
+ userContext,
+ navigate
+) {
var _this = this;
var session$1 = uiEntry.useSessionContext();
var recipeImplementation = React__namespace.useMemo(
@@ -6353,28 +6421,18 @@ function useChildProps(recipe$1, loginAttemptInfo, error, onError, clearError, r
case 3:
return [
2 /*return*/,
- types.Session.getInstanceOrThrow()
- .validateGlobalClaimsAndHandleSuccessRedirection(
- {
- action: "SUCCESS",
- createdNewUser:
- result.createdNewRecipeUser &&
- result.user.loginMethods.length === 1,
- isNewRecipeUser: result.createdNewRecipeUser,
- newSessionCreated:
- session$1.loading ||
- !session$1.doesSessionExist ||
- (payloadAfterCall !== undefined &&
- session$1.accessTokenPayload.sessionHandle !==
- payloadAfterCall.sessionHandle),
- recipeId: recipe$1.recipeID,
- },
- recipe$1.recipeID,
- genericComponentOverrideContext.getRedirectToPathFromURL(),
- userContext,
- navigate
- )
- .catch(rethrowInRender),
+ onAuthSuccess({
+ createdNewUser:
+ result.createdNewRecipeUser && result.user.loginMethods.length === 1,
+ isNewRecipeUser: result.createdNewRecipeUser,
+ newSessionCreated:
+ session$1.loading ||
+ !session$1.doesSessionExist ||
+ (payloadAfterCall !== undefined &&
+ session$1.accessTokenPayload.sessionHandle !==
+ payloadAfterCall.sessionHandle),
+ recipeId: "passwordless",
+ }).catch(rethrowInRender),
];
}
});
@@ -6417,6 +6475,8 @@ function useChildProps(recipe$1, loginAttemptInfo, error, onError, clearError, r
evInstance.redirect(
{
action: "VERIFY_EMAIL",
+ tenantIdFromQueryParams:
+ genericComponentOverrideContext.getTenantIdFromQueryParams(),
},
navigate,
undefined,
@@ -6451,6 +6511,7 @@ var UserInputCodeFeatureInner = function (props) {
var childProps = useChildProps(
props.recipe,
props.loginAttemptInfo,
+ props.onAuthSuccess,
props.error,
props.onError,
props.clearError,
@@ -6494,12 +6555,13 @@ function getModifiedRecipeImplementation(originalImpl, setError, rebuildAuthPage
resendCode: function (input) {
return genericComponentOverrideContext.__awaiter(_this, void 0, void 0, function () {
var res, loginAttemptInfo, timestamp;
- return genericComponentOverrideContext.__generator(this, function (_a) {
- switch (_a.label) {
+ var _a;
+ return genericComponentOverrideContext.__generator(this, function (_b) {
+ switch (_b.label) {
case 0:
return [4 /*yield*/, originalImpl.resendCode(input)];
case 1:
- res = _a.sent();
+ res = _b.sent();
if (!(res.status === "OK")) return [3 /*break*/, 5];
return [
4 /*yield*/,
@@ -6508,7 +6570,7 @@ function getModifiedRecipeImplementation(originalImpl, setError, rebuildAuthPage
}),
];
case 2:
- loginAttemptInfo = _a.sent();
+ loginAttemptInfo = _b.sent();
if (!(loginAttemptInfo !== undefined)) return [3 /*break*/, 4];
timestamp = Date.now();
return [
@@ -6517,13 +6579,20 @@ function getModifiedRecipeImplementation(originalImpl, setError, rebuildAuthPage
userContext: input.userContext,
attemptInfo: genericComponentOverrideContext.__assign(
genericComponentOverrideContext.__assign({}, loginAttemptInfo),
- { lastResend: timestamp }
+ {
+ shouldTryLinkingWithSessionUser:
+ (_a = loginAttemptInfo.shouldTryLinkingWithSessionUser) !== null &&
+ _a !== void 0
+ ? _a
+ : false,
+ lastResend: timestamp,
+ }
),
}),
];
case 3:
- _a.sent();
- _a.label = 4;
+ _b.sent();
+ _b.label = 4;
case 4:
return [3 /*break*/, 7];
case 5:
@@ -6535,10 +6604,10 @@ function getModifiedRecipeImplementation(originalImpl, setError, rebuildAuthPage
}),
];
case 6:
- _a.sent();
+ _b.sent();
setError("ERROR_SIGN_IN_UP_RESEND_RESTART_FLOW");
rebuildAuthPage();
- _a.label = 7;
+ _b.label = 7;
case 7:
return [2 /*return*/, res];
}
diff --git a/lib/build/recipe/authRecipe/components/theme/authPage/authPageHeader.d.ts b/lib/build/recipe/authRecipe/components/theme/authPage/authPageHeader.d.ts
index 60ed74fed..127a6536f 100644
--- a/lib/build/recipe/authRecipe/components/theme/authPage/authPageHeader.d.ts
+++ b/lib/build/recipe/authRecipe/components/theme/authPage/authPageHeader.d.ts
@@ -6,4 +6,11 @@ export declare const AuthPageHeader: import("react").ComponentType<{
onSignInUpSwitcherClick: (() => void) | undefined;
resetFactorList: () => void;
showBackButton: boolean;
+ oauth2ClientInfo?:
+ | {
+ logoUri?: string | undefined;
+ clientUri?: string | undefined;
+ clientName: string;
+ }
+ | undefined;
}>;
diff --git a/lib/build/recipe/authRecipe/types.d.ts b/lib/build/recipe/authRecipe/types.d.ts
index 4dbbf3131..2111f5f31 100644
--- a/lib/build/recipe/authRecipe/types.d.ts
+++ b/lib/build/recipe/authRecipe/types.d.ts
@@ -3,7 +3,13 @@ import type { AuthPageComponentList } from "./components/theme/authPage/authPage
import type { AuthPageFooter } from "./components/theme/authPage/authPageFooter";
import type { AuthPageHeader } from "./components/theme/authPage/authPageHeader";
import type { ComponentOverride } from "../../components/componentOverride/componentOverride";
-import type { AuthComponentProps, Navigate, PartialAuthComponentProps, UserContext } from "../../types";
+import type {
+ AuthComponentProps,
+ Navigate,
+ PartialAuthComponentProps,
+ SuccessRedirectContext,
+ UserContext,
+} from "../../types";
import type {
Config as RecipeModuleConfig,
NormalisedConfig as NormalisedRecipeModuleConfig,
@@ -26,7 +32,19 @@ declare type ComponentWithPreloadInfo = {
>;
preloadInfo: T;
};
+export declare type AuthSuccessContext = Omit<
+ SuccessRedirectContext,
+ "redirectToPath" | "action" | "loginChallenge" | "recipeId"
+> & {
+ recipeId: string;
+};
export declare type AuthPageThemeProps = {
+ oauth2ClientInfo?: {
+ clientLogo?: string;
+ clientUri?: string;
+ clientName: string;
+ };
+ onAuthSuccess: (successContext: AuthSuccessContext) => Promise;
showBackButton: boolean;
setFactorList: (factorIds: string[]) => void;
resetFactorList: () => void;
diff --git a/lib/build/recipe/emailpassword/components/features/signin/index.d.ts b/lib/build/recipe/emailpassword/components/features/signin/index.d.ts
index cc8a4adfa..89d1808a1 100644
--- a/lib/build/recipe/emailpassword/components/features/signin/index.d.ts
+++ b/lib/build/recipe/emailpassword/components/features/signin/index.d.ts
@@ -1,10 +1,12 @@
import * as React from "react";
import type { Navigate, UserContext, PartialAuthComponentProps } from "../../../../../types";
+import type { AuthSuccessContext } from "../../../../authRecipe/types";
import type Recipe from "../../../recipe";
import type { SignInThemeProps } from "../../../types";
import type { ComponentOverrideMap } from "../../../types";
export declare function useChildProps(
recipe: Recipe,
+ onAuthSuccess: (successContext: AuthSuccessContext) => Promise,
error: string | undefined,
onError: (err: string) => void,
clearError: () => void,
diff --git a/lib/build/recipe/emailpassword/components/features/signup/index.d.ts b/lib/build/recipe/emailpassword/components/features/signup/index.d.ts
index a0b3bc16d..08715c7a5 100644
--- a/lib/build/recipe/emailpassword/components/features/signup/index.d.ts
+++ b/lib/build/recipe/emailpassword/components/features/signup/index.d.ts
@@ -1,10 +1,12 @@
import * as React from "react";
import type { Navigate, UserContext, PartialAuthComponentProps } from "../../../../../types";
+import type { AuthSuccessContext } from "../../../../authRecipe/types";
import type Recipe from "../../../recipe";
import type { SignUpThemeProps } from "../../../types";
import type { ComponentOverrideMap } from "../../../types";
export declare function useChildProps(
recipe: Recipe,
+ onAuthSuccess: (successContext: AuthSuccessContext) => Promise,
error: string | undefined,
onError: (err: string) => void,
clearError: () => void,
diff --git a/lib/build/recipe/emailpassword/components/themes/translations.d.ts b/lib/build/recipe/emailpassword/components/themes/translations.d.ts
index 144c2c176..ec431cb0f 100644
--- a/lib/build/recipe/emailpassword/components/themes/translations.d.ts
+++ b/lib/build/recipe/emailpassword/components/themes/translations.d.ts
@@ -74,6 +74,7 @@ export declare const defaultTranslationsEmailPassword: {
AUTH_PAGE_HEADER_TITLE_SIGN_IN_AND_UP: string;
AUTH_PAGE_HEADER_TITLE_SIGN_IN: string;
AUTH_PAGE_HEADER_TITLE_SIGN_UP: string;
+ AUTH_PAGE_HEADER_TITLE_SIGN_IN_UP_TO_APP: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_START: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_SIGN_UP_LINK: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_END: string;
diff --git a/lib/build/recipe/emailpassword/index.d.ts b/lib/build/recipe/emailpassword/index.d.ts
index f5dbca606..9bff21ab9 100644
--- a/lib/build/recipe/emailpassword/index.d.ts
+++ b/lib/build/recipe/emailpassword/index.d.ts
@@ -66,6 +66,7 @@ export default class Wrapper {
id: string;
value: string;
}[];
+ shouldTryLinkingWithSessionUser?: boolean;
options?: RecipeFunctionOptions;
userContext?: UserContext;
}): Promise<
@@ -93,6 +94,7 @@ export default class Wrapper {
id: string;
value: string;
}[];
+ shouldTryLinkingWithSessionUser?: boolean;
options?: RecipeFunctionOptions;
userContext?: UserContext;
}): Promise<
diff --git a/lib/build/recipe/emailpassword/prebuiltui.d.ts b/lib/build/recipe/emailpassword/prebuiltui.d.ts
index 1865fe165..dde794f58 100644
--- a/lib/build/recipe/emailpassword/prebuiltui.d.ts
+++ b/lib/build/recipe/emailpassword/prebuiltui.d.ts
@@ -84,6 +84,7 @@ export declare class EmailPasswordPreBuiltUI extends RecipeRouter {
AUTH_PAGE_HEADER_TITLE_SIGN_IN_AND_UP: string;
AUTH_PAGE_HEADER_TITLE_SIGN_IN: string;
AUTH_PAGE_HEADER_TITLE_SIGN_UP: string;
+ AUTH_PAGE_HEADER_TITLE_SIGN_IN_UP_TO_APP: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_START: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_SIGN_UP_LINK: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_END: string;
diff --git a/lib/build/recipe/emailpassword/recipe.d.ts b/lib/build/recipe/emailpassword/recipe.d.ts
index a4c04ec3e..73be9e8f5 100644
--- a/lib/build/recipe/emailpassword/recipe.d.ts
+++ b/lib/build/recipe/emailpassword/recipe.d.ts
@@ -16,8 +16,8 @@ export default class EmailPassword extends AuthRecipe<
> {
readonly webJSRecipe: WebJSRecipeInterface;
static instance?: EmailPassword;
- static RECIPE_ID: string;
- recipeID: string;
+ static RECIPE_ID: "emailpassword";
+ recipeID: "emailpassword";
firstFactorIds: "emailpassword"[];
getFirstFactorsForAuthPage(): string[];
constructor(
diff --git a/lib/build/recipe/emailpassword/types.d.ts b/lib/build/recipe/emailpassword/types.d.ts
index 4198ad5dc..a6879a04d 100644
--- a/lib/build/recipe/emailpassword/types.d.ts
+++ b/lib/build/recipe/emailpassword/types.d.ts
@@ -12,6 +12,7 @@ import type {
FormFieldBaseConfig,
NormalisedBaseConfig,
NormalisedFormField,
+ NormalisedGetRedirectionURLContext,
ThemeBaseProps,
UserContext,
} from "../../types";
@@ -141,9 +142,9 @@ export declare type PreAPIHookContext = {
url: string;
userContext: UserContext;
};
-export declare type GetRedirectionURLContext = {
+export declare type GetRedirectionURLContext = NormalisedGetRedirectionURLContext<{
action: "RESET_PASSWORD";
-};
+}>;
export declare type OnHandleEventContext =
| AuthRecipeModuleOnHandleEventContext
| {
diff --git a/lib/build/recipe/emailverification/components/themes/translations.d.ts b/lib/build/recipe/emailverification/components/themes/translations.d.ts
index a41cb0c89..357f1f004 100644
--- a/lib/build/recipe/emailverification/components/themes/translations.d.ts
+++ b/lib/build/recipe/emailverification/components/themes/translations.d.ts
@@ -19,6 +19,7 @@ export declare const defaultTranslationsEmailVerification: {
AUTH_PAGE_HEADER_TITLE_SIGN_IN_AND_UP: string;
AUTH_PAGE_HEADER_TITLE_SIGN_IN: string;
AUTH_PAGE_HEADER_TITLE_SIGN_UP: string;
+ AUTH_PAGE_HEADER_TITLE_SIGN_IN_UP_TO_APP: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_START: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_SIGN_UP_LINK: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_END: string;
diff --git a/lib/build/recipe/emailverification/prebuiltui.d.ts b/lib/build/recipe/emailverification/prebuiltui.d.ts
index 5b548ded9..4ada857a7 100644
--- a/lib/build/recipe/emailverification/prebuiltui.d.ts
+++ b/lib/build/recipe/emailverification/prebuiltui.d.ts
@@ -29,6 +29,7 @@ export declare class EmailVerificationPreBuiltUI extends RecipeRouter {
AUTH_PAGE_HEADER_TITLE_SIGN_IN_AND_UP: string;
AUTH_PAGE_HEADER_TITLE_SIGN_IN: string;
AUTH_PAGE_HEADER_TITLE_SIGN_UP: string;
+ AUTH_PAGE_HEADER_TITLE_SIGN_IN_UP_TO_APP: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_START: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_SIGN_UP_LINK: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_END: string;
diff --git a/lib/build/recipe/emailverification/types.d.ts b/lib/build/recipe/emailverification/types.d.ts
index be135de75..673f4500c 100644
--- a/lib/build/recipe/emailverification/types.d.ts
+++ b/lib/build/recipe/emailverification/types.d.ts
@@ -1,7 +1,7 @@
import type { SendVerifyEmail } from "./components/themes/emailVerification/sendVerifyEmail";
import type { VerifyEmailLinkClicked } from "./components/themes/emailVerification/verifyEmailLinkClicked";
import type { ComponentOverride } from "../../components/componentOverride/componentOverride";
-import type { FeatureBaseConfig, ThemeBaseProps, UserContext } from "../../types";
+import type { FeatureBaseConfig, NormalisedGetRedirectionURLContext, ThemeBaseProps, UserContext } from "../../types";
import type {
Config as RecipeModuleConfig,
NormalisedConfig as NormalisedRecipeModuleConfig,
@@ -39,9 +39,9 @@ export declare type NormalisedConfig = {
) => RecipeInterface;
};
} & NormalisedRecipeModuleConfig;
-export declare type GetRedirectionURLContext = {
+export declare type GetRedirectionURLContext = NormalisedGetRedirectionURLContext<{
action: "VERIFY_EMAIL";
-};
+}>;
export declare type PreAndPostAPIHookAction = "VERIFY_EMAIL" | "SEND_VERIFY_EMAIL" | "IS_EMAIL_VERIFIED";
export declare type PreAPIHookContext = {
action: PreAndPostAPIHookAction;
diff --git a/lib/build/recipe/multifactorauth/components/themes/translations.d.ts b/lib/build/recipe/multifactorauth/components/themes/translations.d.ts
index d1a9adae9..b26ba3b86 100644
--- a/lib/build/recipe/multifactorauth/components/themes/translations.d.ts
+++ b/lib/build/recipe/multifactorauth/components/themes/translations.d.ts
@@ -13,6 +13,7 @@ export declare const defaultTranslationsMultiFactorAuth: {
AUTH_PAGE_HEADER_TITLE_SIGN_IN_AND_UP: string;
AUTH_PAGE_HEADER_TITLE_SIGN_IN: string;
AUTH_PAGE_HEADER_TITLE_SIGN_UP: string;
+ AUTH_PAGE_HEADER_TITLE_SIGN_IN_UP_TO_APP: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_START: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_SIGN_UP_LINK: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_END: string;
diff --git a/lib/build/recipe/multifactorauth/prebuiltui.d.ts b/lib/build/recipe/multifactorauth/prebuiltui.d.ts
index fc22c808a..796cdfa3d 100644
--- a/lib/build/recipe/multifactorauth/prebuiltui.d.ts
+++ b/lib/build/recipe/multifactorauth/prebuiltui.d.ts
@@ -23,6 +23,7 @@ export declare class MultiFactorAuthPreBuiltUI extends RecipeRouter {
AUTH_PAGE_HEADER_TITLE_SIGN_IN_AND_UP: string;
AUTH_PAGE_HEADER_TITLE_SIGN_IN: string;
AUTH_PAGE_HEADER_TITLE_SIGN_UP: string;
+ AUTH_PAGE_HEADER_TITLE_SIGN_IN_UP_TO_APP: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_START: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_SIGN_UP_LINK: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_END: string;
diff --git a/lib/build/recipe/multifactorauth/types.d.ts b/lib/build/recipe/multifactorauth/types.d.ts
index bf8837003..025aea3a2 100644
--- a/lib/build/recipe/multifactorauth/types.d.ts
+++ b/lib/build/recipe/multifactorauth/types.d.ts
@@ -3,7 +3,7 @@ import type { FactorChooserHeader } from "./components/themes/factorChooser/fact
import type { FactorList } from "./components/themes/factorChooser/factorList";
import type { FactorOption } from "./components/themes/factorChooser/factorOption";
import type { ComponentOverride } from "../../components/componentOverride/componentOverride";
-import type { FeatureBaseConfig, UserContext } from "../../types";
+import type { FeatureBaseConfig, NormalisedGetRedirectionURLContext, UserContext } from "../../types";
import type {
Config as RecipeModuleConfig,
NormalisedConfig as NormalisedRecipeModuleConfig,
@@ -51,7 +51,7 @@ export declare type NormalisedConfig = {
) => RecipeInterface;
};
} & NormalisedRecipeModuleConfig;
-export declare type GetRedirectionURLContext =
+export declare type GetRedirectionURLContext = NormalisedGetRedirectionURLContext<
| {
action: "FACTOR_CHOOSER";
nextFactorOptions?: string[];
@@ -62,7 +62,8 @@ export declare type GetRedirectionURLContext =
factorId: string;
forceSetup?: boolean;
stepUp?: boolean;
- };
+ }
+>;
export declare type PreAndPostAPIHookAction = "GET_MFA_INFO";
export declare type PreAPIHookContext = {
action: PreAndPostAPIHookAction;
diff --git a/lib/build/recipe/oauth2provider/componentOverrideContext.d.ts b/lib/build/recipe/oauth2provider/componentOverrideContext.d.ts
new file mode 100644
index 000000000..288fc18e7
--- /dev/null
+++ b/lib/build/recipe/oauth2provider/componentOverrideContext.d.ts
@@ -0,0 +1,9 @@
+///
+import type { ComponentOverrideMap } from "./types";
+declare const useContext: () => ComponentOverrideMap,
+ Provider: import("react").FC<
+ import("react").PropsWithChildren<{
+ components: ComponentOverrideMap;
+ }>
+ >;
+export { useContext as useRecipeComponentOverrideContext, Provider as RecipeComponentsOverrideContextProvider };
diff --git a/lib/build/recipe/oauth2provider/components/features/oauth2LogoutScreen/index.d.ts b/lib/build/recipe/oauth2provider/components/features/oauth2LogoutScreen/index.d.ts
new file mode 100644
index 000000000..6b278cc3f
--- /dev/null
+++ b/lib/build/recipe/oauth2provider/components/features/oauth2LogoutScreen/index.d.ts
@@ -0,0 +1,11 @@
+import * as React from "react";
+import type { FeatureBaseProps, UserContext } from "../../../../../types";
+import type Recipe from "../../../recipe";
+import type { ComponentOverrideMap } from "../../../types";
+declare type Prop = FeatureBaseProps<{
+ recipe: Recipe;
+ userContext?: UserContext;
+ useComponentOverrides: () => ComponentOverrideMap;
+}>;
+export declare const OAuth2LogoutScreen: React.FC;
+export default OAuth2LogoutScreen;
diff --git a/lib/build/recipe/oauth2provider/components/features/tryRefreshPage/index.d.ts b/lib/build/recipe/oauth2provider/components/features/tryRefreshPage/index.d.ts
new file mode 100644
index 000000000..dfde96e31
--- /dev/null
+++ b/lib/build/recipe/oauth2provider/components/features/tryRefreshPage/index.d.ts
@@ -0,0 +1,11 @@
+import * as React from "react";
+import type { FeatureBaseProps, UserContext } from "../../../../../types";
+import type Recipe from "../../../recipe";
+import type { ComponentOverrideMap } from "../../../types";
+declare type Prop = FeatureBaseProps<{
+ recipe: Recipe;
+ userContext?: UserContext;
+ useComponentOverrides: () => ComponentOverrideMap;
+}>;
+export declare const TryRefreshPage: React.FC;
+export default TryRefreshPage;
diff --git a/lib/build/recipe/oauth2provider/components/themes/oauth2LogoutScreen/OAuth2LogoutScreenInner.d.ts b/lib/build/recipe/oauth2provider/components/themes/oauth2LogoutScreen/OAuth2LogoutScreenInner.d.ts
new file mode 100644
index 000000000..222609ded
--- /dev/null
+++ b/lib/build/recipe/oauth2provider/components/themes/oauth2LogoutScreen/OAuth2LogoutScreenInner.d.ts
@@ -0,0 +1,5 @@
+///
+export declare const OAuth2LogoutScreenInner: import("react").ComponentType<{
+ isLoggingOut: boolean;
+ onLogoutClicked: () => void;
+}>;
diff --git a/lib/build/recipe/oauth2provider/components/themes/oauth2LogoutScreen/index.d.ts b/lib/build/recipe/oauth2provider/components/themes/oauth2LogoutScreen/index.d.ts
new file mode 100644
index 000000000..0fa32a566
--- /dev/null
+++ b/lib/build/recipe/oauth2provider/components/themes/oauth2LogoutScreen/index.d.ts
@@ -0,0 +1,3 @@
+import React from "react";
+import type { OAuth2LogoutScreenThemeProps } from "../../../types";
+export declare const OAuth2LogoutScreenTheme: React.FC;
diff --git a/lib/build/recipe/oauth2provider/components/themes/themeBase.d.ts b/lib/build/recipe/oauth2provider/components/themes/themeBase.d.ts
new file mode 100644
index 000000000..516a61754
--- /dev/null
+++ b/lib/build/recipe/oauth2provider/components/themes/themeBase.d.ts
@@ -0,0 +1,7 @@
+import React from "react";
+import type { PropsWithChildren } from "react";
+export declare const ThemeBase: React.FC<
+ PropsWithChildren<{
+ userStyles: Array;
+ }>
+>;
diff --git a/lib/build/recipe/oauth2provider/components/themes/translations.d.ts b/lib/build/recipe/oauth2provider/components/themes/translations.d.ts
new file mode 100644
index 000000000..f5122e036
--- /dev/null
+++ b/lib/build/recipe/oauth2provider/components/themes/translations.d.ts
@@ -0,0 +1,27 @@
+export declare const defaultTranslationsOAuth2Provider: {
+ en: {
+ LOGGING_OUT: string;
+ LOGOUT_CONFIRMATION: string;
+ LOGOUT: string;
+ AUTH_PAGE_HEADER_TITLE_SIGN_IN_AND_UP: string;
+ AUTH_PAGE_HEADER_TITLE_SIGN_IN: string;
+ AUTH_PAGE_HEADER_TITLE_SIGN_UP: string;
+ AUTH_PAGE_HEADER_TITLE_SIGN_IN_UP_TO_APP: string;
+ AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_START: string;
+ AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_SIGN_UP_LINK: string;
+ AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_END: string;
+ AUTH_PAGE_HEADER_SUBTITLE_SIGN_UP_START: string;
+ AUTH_PAGE_HEADER_SUBTITLE_SIGN_UP_SIGN_IN_LINK: string;
+ AUTH_PAGE_HEADER_SUBTITLE_SIGN_UP_END: string;
+ AUTH_PAGE_FOOTER_START: string;
+ AUTH_PAGE_FOOTER_TOS: string;
+ AUTH_PAGE_FOOTER_AND: string;
+ AUTH_PAGE_FOOTER_PP: string;
+ AUTH_PAGE_FOOTER_END: string;
+ DIVIDER_OR: string;
+ BRANDING_POWERED_BY_START: string;
+ BRANDING_POWERED_BY_END: string;
+ SOMETHING_WENT_WRONG_ERROR: string;
+ SOMETHING_WENT_WRONG_ERROR_RELOAD: string;
+ };
+};
diff --git a/lib/build/recipe/oauth2provider/constants.d.ts b/lib/build/recipe/oauth2provider/constants.d.ts
new file mode 100644
index 000000000..4ce4a8095
--- /dev/null
+++ b/lib/build/recipe/oauth2provider/constants.d.ts
@@ -0,0 +1,2 @@
+export declare const DEFAULT_TRY_REFRESH_PATH = "/try-refresh";
+export declare const DEFAULT_OAUTH2_LOGOUT_PATH = "/oauth/logout";
diff --git a/lib/build/recipe/oauth2provider/functionOverrides.d.ts b/lib/build/recipe/oauth2provider/functionOverrides.d.ts
new file mode 100644
index 000000000..f6163a931
--- /dev/null
+++ b/lib/build/recipe/oauth2provider/functionOverrides.d.ts
@@ -0,0 +1,6 @@
+import type { OnHandleEventContext } from "./types";
+import type { RecipeOnHandleEventFunction } from "../recipeModule/types";
+import type { RecipeInterface } from "supertokens-web-js/recipe/oauth2provider";
+export declare const getFunctionOverrides: (
+ onHandleEvent: RecipeOnHandleEventFunction
+) => (originalImp: RecipeInterface) => RecipeInterface;
diff --git a/lib/build/recipe/oauth2provider/index.d.ts b/lib/build/recipe/oauth2provider/index.d.ts
new file mode 100644
index 000000000..1a574d79b
--- /dev/null
+++ b/lib/build/recipe/oauth2provider/index.d.ts
@@ -0,0 +1,89 @@
+///
+import { RecipeComponentsOverrideContextProvider } from "./componentOverrideContext";
+import { UserInput, GetRedirectionURLContext, PreAPIHookContext, OnHandleEventContext } from "./types";
+import type { RecipeFunctionOptions, LoginInfo } from "supertokens-web-js/recipe/oauth2provider";
+import type { RecipeInterface } from "supertokens-web-js/recipe/oauth2provider";
+export default class Wrapper {
+ static init(config?: UserInput): import("../../types").RecipeInitResult;
+ /**
+ * Returns information about an OAuth login in progress
+ *
+ * @param loginChallenge The login challenge from the url
+ *
+ * @param userContext (OPTIONAL) Refer to {@link https://supertokens.com/docs/emailpassword/advanced-customizations/user-context the documentation}
+ *
+ * @param options (OPTIONAL) Use this to configure additional properties (for example pre api hooks)
+ *
+ * @returns `{status: "OK", info: LoginInfo}`
+ *
+ * @throws STGeneralError if the API exposed by the backend SDKs returns `status: "GENERAL_ERROR"`
+ */
+ static getLoginChallengeInfo(input: {
+ loginChallenge: string;
+ options?: RecipeFunctionOptions;
+ userContext?: any;
+ }): Promise<{
+ status: "OK";
+ info: LoginInfo;
+ fetchResponse: Response;
+ }>;
+ /**
+ * Accepts the OAuth2 Login request and returns the redirect URL to continue the OAuth flow.
+ *
+ * @param loginChallenge The login challenge from the url
+ *
+ * @param userContext (OPTIONAL) Refer to {@link https://supertokens.com/docs/emailpassword/advanced-customizations/user-context the documentation}
+ *
+ * @param options (OPTIONAL) Use this to configure additional properties (for example pre api hooks)
+ *
+ * @returns `{status: "OK", frontendRedirectTo: string}`
+ *
+ * @throws STGeneralError if the API exposed by the backend SDKs returns `status: "GENERAL_ERROR"`
+ */
+ static getRedirectURLToContinueOAuthFlow(input: {
+ loginChallenge: string;
+ options?: RecipeFunctionOptions;
+ userContext?: any;
+ }): Promise<{
+ status: "OK";
+ frontendRedirectTo: string;
+ fetchResponse: Response;
+ }>;
+ /**
+ * Accepts the OAuth2 Logout request, clears the SuperTokens session and returns post logout redirect URL.
+ *
+ * @param logoutChallenge The logout challenge from the url
+ *
+ * @param userContext (OPTIONAL) Refer to {@link https://supertokens.com/docs/emailpassword/advanced-customizations/user-context the documentation}
+ *
+ * @param options (OPTIONAL) Use this to configure additional properties (for example pre api hooks)
+ *
+ * @returns `{status: "OK", frontendRedirectTo: string}`
+ *
+ * @throws STGeneralError if the API exposed by the backend SDKs returns `status: "GENERAL_ERROR"`
+ */
+ static logOut(input: { logoutChallenge: string; options?: RecipeFunctionOptions; userContext?: any }): Promise<{
+ status: "OK";
+ frontendRedirectTo: string;
+ fetchResponse: Response;
+ }>;
+ static ComponentsOverrideProvider: import("react").FC<
+ import("react").PropsWithChildren<{
+ components: import("./types").ComponentOverrideMap;
+ }>
+ >;
+}
+declare const init: typeof Wrapper.init;
+declare const getLoginChallengeInfo: typeof Wrapper.getLoginChallengeInfo;
+declare const logOut: typeof Wrapper.logOut;
+export {
+ init,
+ getLoginChallengeInfo,
+ logOut,
+ GetRedirectionURLContext,
+ PreAPIHookContext,
+ OnHandleEventContext,
+ UserInput,
+ RecipeInterface,
+ RecipeComponentsOverrideContextProvider,
+};
diff --git a/lib/build/recipe/oauth2provider/prebuiltui.d.ts b/lib/build/recipe/oauth2provider/prebuiltui.d.ts
new file mode 100644
index 000000000..8b17b7fb5
--- /dev/null
+++ b/lib/build/recipe/oauth2provider/prebuiltui.d.ts
@@ -0,0 +1,71 @@
+///
+import { RecipeRouter } from "../recipeRouter";
+import OAuth2ProviderRecipe from "./recipe";
+import type { GenericComponentOverrideMap } from "../../components/componentOverride/componentOverrideContext";
+import type { FeatureBaseProps, RecipeFeatureComponentMap, UserContext } from "../../types";
+import type { AuthComponent } from "../../types";
+export declare class OAuth2ProviderPreBuiltUI extends RecipeRouter {
+ readonly recipeInstance: OAuth2ProviderRecipe;
+ static instance?: OAuth2ProviderPreBuiltUI;
+ languageTranslations: {
+ en: {
+ LOGGING_OUT: string;
+ LOGOUT_CONFIRMATION: string;
+ LOGOUT: string;
+ AUTH_PAGE_HEADER_TITLE_SIGN_IN_AND_UP: string;
+ AUTH_PAGE_HEADER_TITLE_SIGN_IN: string;
+ AUTH_PAGE_HEADER_TITLE_SIGN_UP: string;
+ AUTH_PAGE_HEADER_TITLE_SIGN_IN_UP_TO_APP: string;
+ AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_START: string;
+ AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_SIGN_UP_LINK: string;
+ AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_END: string;
+ AUTH_PAGE_HEADER_SUBTITLE_SIGN_UP_START: string;
+ AUTH_PAGE_HEADER_SUBTITLE_SIGN_UP_SIGN_IN_LINK: string;
+ AUTH_PAGE_HEADER_SUBTITLE_SIGN_UP_END: string;
+ AUTH_PAGE_FOOTER_START: string;
+ AUTH_PAGE_FOOTER_TOS: string;
+ AUTH_PAGE_FOOTER_AND: string;
+ AUTH_PAGE_FOOTER_PP: string;
+ AUTH_PAGE_FOOTER_END: string;
+ DIVIDER_OR: string;
+ BRANDING_POWERED_BY_START: string;
+ BRANDING_POWERED_BY_END: string;
+ SOMETHING_WENT_WRONG_ERROR: string;
+ SOMETHING_WENT_WRONG_ERROR_RELOAD: string;
+ };
+ };
+ constructor(recipeInstance: OAuth2ProviderRecipe);
+ static getInstanceOrInitAndGetInstance(): OAuth2ProviderPreBuiltUI;
+ static getFeatures(useComponentOverrides?: () => GenericComponentOverrideMap): RecipeFeatureComponentMap;
+ static getFeatureComponent(
+ componentName: "try-refresh-page" | "oauth2-logout-screen",
+ props: any,
+ useComponentOverrides?: () => GenericComponentOverrideMap
+ ): JSX.Element;
+ getFeatures: (useComponentOverrides?: () => GenericComponentOverrideMap) => RecipeFeatureComponentMap;
+ getFeatureComponent: (
+ componentName: "try-refresh-page" | "oauth2-logout-screen",
+ props: FeatureBaseProps<{
+ userContext?: UserContext;
+ }>,
+ useComponentOverrides?: () => GenericComponentOverrideMap
+ ) => JSX.Element;
+ getAuthComponents(): AuthComponent[];
+ static reset(): void;
+ static TryRefreshPage: (
+ props: FeatureBaseProps<{
+ userContext?: UserContext;
+ }>
+ ) => JSX.Element;
+ static OAuth2LogoutScreen: (
+ props: FeatureBaseProps<{
+ userContext?: UserContext;
+ }>
+ ) => JSX.Element;
+}
+declare const TryRefreshPage: (
+ props: FeatureBaseProps<{
+ userContext?: UserContext;
+ }>
+) => JSX.Element;
+export { TryRefreshPage };
diff --git a/lib/build/recipe/oauth2provider/recipe.d.ts b/lib/build/recipe/oauth2provider/recipe.d.ts
new file mode 100644
index 000000000..88f243b82
--- /dev/null
+++ b/lib/build/recipe/oauth2provider/recipe.d.ts
@@ -0,0 +1,30 @@
+import OAuth2WebJS from "supertokens-web-js/recipe/oauth2provider";
+import RecipeModule from "../recipeModule";
+import type {
+ GetRedirectionURLContext,
+ NormalisedConfig,
+ OnHandleEventContext,
+ PreAndPostAPIHookAction,
+ UserInput,
+} from "./types";
+import type { RecipeInitResult, NormalisedConfigWithAppInfoAndRecipeID, WebJSRecipeInterface } from "../../types";
+export default class OAuth2Provider extends RecipeModule<
+ GetRedirectionURLContext,
+ PreAndPostAPIHookAction,
+ OnHandleEventContext,
+ NormalisedConfig
+> {
+ readonly webJSRecipe: WebJSRecipeInterface;
+ static instance?: OAuth2Provider;
+ static readonly RECIPE_ID = "oauth2provider";
+ readonly recipeID = "oauth2provider";
+ constructor(
+ config: NormalisedConfigWithAppInfoAndRecipeID,
+ webJSRecipe?: WebJSRecipeInterface
+ );
+ static init(config?: UserInput): RecipeInitResult;
+ static getInstanceOrThrow(): OAuth2Provider;
+ static getInstance(): OAuth2Provider | undefined;
+ getDefaultRedirectionURL(ctx: GetRedirectionURLContext): Promise;
+ static reset(): void;
+}
diff --git a/lib/build/recipe/oauth2provider/types.d.ts b/lib/build/recipe/oauth2provider/types.d.ts
new file mode 100644
index 000000000..5296a489a
--- /dev/null
+++ b/lib/build/recipe/oauth2provider/types.d.ts
@@ -0,0 +1,90 @@
+import type { OAuth2LogoutScreenInner } from "./components/themes/oauth2LogoutScreen/OAuth2LogoutScreenInner";
+import type { ComponentOverride } from "../../components/componentOverride/componentOverride";
+import type {
+ NormalisedBaseConfig,
+ NormalisedGetRedirectionURLContext,
+ SuccessRedirectContextOAuth2,
+ UserContext,
+} from "../../types";
+import type {
+ UserInput as RecipeModuleUserInput,
+ NormalisedConfig as NormalisedRecipeModuleConfig,
+} from "../recipeModule/types";
+import type OverrideableBuilder from "supertokens-js-override";
+import type { LoginInfo, RecipeInterface } from "supertokens-web-js/recipe/oauth2provider/types";
+export declare type PreAndPostAPIHookAction =
+ | "GET_LOGIN_CHALLENGE_INFO"
+ | "GET_REDIRECT_URL_TO_CONTINUE_OAUTH_FLOW"
+ | "LOG_OUT";
+export declare type PreAPIHookContext = {
+ action: PreAndPostAPIHookAction;
+ requestInit: RequestInit;
+ url: string;
+ userContext: UserContext;
+};
+export declare type UserInput = {
+ disableDefaultUI?: boolean;
+ oauth2LogoutScreen?: Partial;
+ tryRefreshPage?: Partial;
+ override?: {
+ functions?: (
+ originalImplementation: RecipeInterface,
+ builder: OverrideableBuilder
+ ) => RecipeInterface;
+ };
+} & RecipeModuleUserInput;
+export declare type NormalisedConfig = NormalisedRecipeModuleConfig<
+ GetRedirectionURLContext,
+ PreAndPostAPIHookAction,
+ OnHandleEventContext
+> & {
+ disableDefaultUI: boolean;
+ oauth2LogoutScreen: OAuth2LogoutScreenConfig;
+ tryRefreshPage: OAuth2TryRefreshPageConfig;
+ override: {
+ functions: (
+ originalImplementation: RecipeInterface,
+ builder: OverrideableBuilder
+ ) => RecipeInterface;
+ };
+};
+export declare type OAuth2LogoutScreenConfig = NormalisedBaseConfig & {
+ disableDefaultUI: boolean;
+};
+export declare type OAuth2TryRefreshPageConfig = {
+ disableDefaultUI: boolean;
+};
+export declare type ContinueOAuth2AfterRefreshRedirectContext = {
+ recipeId: "oauth2provider";
+ action: "CONTINUE_OAUTH2_AFTER_REFRESH";
+ frontendRedirectTo: string;
+};
+export declare type PostOAuth2LogoutRedirectContext = {
+ recipeId: "oauth2provider";
+ action: "POST_OAUTH2_LOGOUT_REDIRECT";
+ frontendRedirectTo: string;
+};
+export declare type GetRedirectionURLContext = NormalisedGetRedirectionURLContext<
+ SuccessRedirectContextOAuth2 | ContinueOAuth2AfterRefreshRedirectContext | PostOAuth2LogoutRedirectContext
+>;
+export declare type OnHandleEventContext =
+ | {
+ action: "LOADED_LOGIN_CHALLENGE";
+ loginChallenge: string;
+ loginInfo: LoginInfo;
+ userContext: UserContext;
+ }
+ | {
+ action: "OAUTH2_LOGOUT_SUCCESS";
+ frontendRedirectTo: string;
+ userContext: UserContext;
+ };
+export declare type ComponentOverrideMap = {
+ OAuth2LogoutScreenInner_Override?: ComponentOverride;
+};
+export declare type OAuth2LogoutScreenThemeProps = {
+ config: NormalisedConfig;
+ isLoggingOut: boolean;
+ onLogoutClicked: () => void;
+ showSpinner: boolean;
+};
diff --git a/lib/build/recipe/oauth2provider/utils.d.ts b/lib/build/recipe/oauth2provider/utils.d.ts
new file mode 100644
index 000000000..1fbfafdf5
--- /dev/null
+++ b/lib/build/recipe/oauth2provider/utils.d.ts
@@ -0,0 +1,2 @@
+import type { UserInput, NormalisedConfig } from "./types";
+export declare function normaliseOAuth2Config(config?: UserInput): NormalisedConfig;
diff --git a/lib/build/recipe/passwordless/components/features/signInAndUp/index.d.ts b/lib/build/recipe/passwordless/components/features/signInAndUp/index.d.ts
index ac9b8560b..c04406f69 100644
--- a/lib/build/recipe/passwordless/components/features/signInAndUp/index.d.ts
+++ b/lib/build/recipe/passwordless/components/features/signInAndUp/index.d.ts
@@ -1,11 +1,13 @@
import * as React from "react";
import type { Navigate, UserContext, PartialAuthComponentProps } from "../../../../../types";
+import type { AuthSuccessContext } from "../../../../authRecipe/types";
import type Recipe from "../../../recipe";
import type { ComponentOverrideMap } from "../../../types";
import type { SignInUpChildProps } from "../../../types";
export declare function useChildProps(
recipe: Recipe,
factorIds: string[],
+ onAuthSuccess: (successContext: AuthSuccessContext) => Promise,
error: string | undefined,
onError: (err: string) => void,
clearError: () => void,
diff --git a/lib/build/recipe/passwordless/components/features/signInAndUpEPCombo/index.d.ts b/lib/build/recipe/passwordless/components/features/signInAndUpEPCombo/index.d.ts
index 4b6c409d5..ca36dd12e 100644
--- a/lib/build/recipe/passwordless/components/features/signInAndUpEPCombo/index.d.ts
+++ b/lib/build/recipe/passwordless/components/features/signInAndUpEPCombo/index.d.ts
@@ -1,11 +1,13 @@
import * as React from "react";
import type { Navigate, UserContext, PartialAuthComponentProps } from "../../../../../types";
+import type { AuthSuccessContext } from "../../../../authRecipe/types";
import type Recipe from "../../../recipe";
import type { ComponentOverrideMap } from "../../../types";
import type { SignInUpEPComboChildProps } from "../../../types";
export declare function useChildProps(
recipe: Recipe,
factorIds: string[],
+ onAuthSuccess: (successContext: AuthSuccessContext) => Promise,
error: string | undefined,
onError: (err: string) => void,
clearError: () => void,
diff --git a/lib/build/recipe/passwordless/components/features/userInputCode/index.d.ts b/lib/build/recipe/passwordless/components/features/userInputCode/index.d.ts
index 969a82dd9..438527b9c 100644
--- a/lib/build/recipe/passwordless/components/features/userInputCode/index.d.ts
+++ b/lib/build/recipe/passwordless/components/features/userInputCode/index.d.ts
@@ -1,10 +1,12 @@
import * as React from "react";
import type { Navigate, UserContext, AuthComponentProps } from "../../../../../types";
+import type { AuthSuccessContext } from "../../../../authRecipe/types";
import type Recipe from "../../../recipe";
import type { ComponentOverrideMap, LoginAttemptInfo, SignInUpUserInputCodeFormProps } from "../../../types";
export declare function useChildProps(
recipe: Recipe,
loginAttemptInfo: LoginAttemptInfo,
+ onAuthSuccess: (successContext: AuthSuccessContext) => Promise,
error: string | undefined,
onError: (err: string) => void,
clearError: () => void,
diff --git a/lib/build/recipe/passwordless/components/themes/translations.d.ts b/lib/build/recipe/passwordless/components/themes/translations.d.ts
index d60b40a2e..d1ddad9ec 100644
--- a/lib/build/recipe/passwordless/components/themes/translations.d.ts
+++ b/lib/build/recipe/passwordless/components/themes/translations.d.ts
@@ -58,6 +58,7 @@ export declare const defaultTranslationsPasswordless: {
AUTH_PAGE_HEADER_TITLE_SIGN_IN_AND_UP: string;
AUTH_PAGE_HEADER_TITLE_SIGN_IN: string;
AUTH_PAGE_HEADER_TITLE_SIGN_UP: string;
+ AUTH_PAGE_HEADER_TITLE_SIGN_IN_UP_TO_APP: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_START: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_SIGN_UP_LINK: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_END: string;
diff --git a/lib/build/recipe/passwordless/index.d.ts b/lib/build/recipe/passwordless/index.d.ts
index 0bf17133d..ca5a32715 100644
--- a/lib/build/recipe/passwordless/index.d.ts
+++ b/lib/build/recipe/passwordless/index.d.ts
@@ -20,11 +20,13 @@ export default class Wrapper {
input:
| {
email: string;
+ shouldTryLinkingWithSessionUser?: boolean;
userContext?: UserContext;
options?: RecipeFunctionOptions;
}
| {
phoneNumber: string;
+ shouldTryLinkingWithSessionUser?: boolean;
userContext?: UserContext;
options?: RecipeFunctionOptions;
}
diff --git a/lib/build/recipe/passwordless/prebuiltui.d.ts b/lib/build/recipe/passwordless/prebuiltui.d.ts
index 18238e194..10c96a0a5 100644
--- a/lib/build/recipe/passwordless/prebuiltui.d.ts
+++ b/lib/build/recipe/passwordless/prebuiltui.d.ts
@@ -69,6 +69,7 @@ export declare class PasswordlessPreBuiltUI extends RecipeRouter {
AUTH_PAGE_HEADER_TITLE_SIGN_IN_AND_UP: string;
AUTH_PAGE_HEADER_TITLE_SIGN_IN: string;
AUTH_PAGE_HEADER_TITLE_SIGN_UP: string;
+ AUTH_PAGE_HEADER_TITLE_SIGN_IN_UP_TO_APP: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_START: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_SIGN_UP_LINK: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_END: string;
diff --git a/lib/build/recipe/recipeModule/index.d.ts b/lib/build/recipe/recipeModule/index.d.ts
index ff126debf..c83e68e16 100644
--- a/lib/build/recipe/recipeModule/index.d.ts
+++ b/lib/build/recipe/recipeModule/index.d.ts
@@ -1,6 +1,6 @@
import { BaseRecipeModule } from "./baseRecipeModule";
import type { NormalisedConfig } from "./types";
-import type { Navigate, UserContext } from "../../types";
+import type { Navigate, NormalisedGetRedirectionURLContext, UserContext } from "../../types";
export default abstract class RecipeModule<
GetRedirectionURLContextType,
Action,
@@ -8,11 +8,17 @@ export default abstract class RecipeModule<
N extends NormalisedConfig
> extends BaseRecipeModule {
redirect: (
- context: GetRedirectionURLContextType,
+ context: NormalisedGetRedirectionURLContext,
navigate?: Navigate,
queryParams?: Record,
userContext?: UserContext
) => Promise;
- getRedirectUrl: (context: GetRedirectionURLContextType, userContext: UserContext) => Promise;
- getDefaultRedirectionURL(_: GetRedirectionURLContextType, _userContext: UserContext): Promise;
+ getRedirectUrl: (
+ context: NormalisedGetRedirectionURLContext,
+ userContext: UserContext
+ ) => Promise;
+ getDefaultRedirectionURL(
+ _: NormalisedGetRedirectionURLContext,
+ _userContext: UserContext
+ ): Promise;
}
diff --git a/lib/build/recipe/recipeModule/types.d.ts b/lib/build/recipe/recipeModule/types.d.ts
index 968d0008d..3df75b39f 100644
--- a/lib/build/recipe/recipeModule/types.d.ts
+++ b/lib/build/recipe/recipeModule/types.d.ts
@@ -1,4 +1,4 @@
-import type { UserContext } from "../../types";
+import type { NormalisedGetRedirectionURLContext, UserContext } from "../../types";
export declare type RecipePreAPIHookContext = {
requestInit: RequestInit;
url: string;
@@ -20,7 +20,7 @@ export declare type RecipePostAPIHookFunction = (context: RecipePostAPIH
export declare type RecipeOnHandleEventFunction = (context: EventType) => void;
export declare type UserInput = {
getRedirectionURL?: (
- context: GetRedirectionURLContextType,
+ context: NormalisedGetRedirectionURLContext,
userContext: UserContext
) => Promise;
preAPIHook?: RecipePreAPIHookFunction;
@@ -35,7 +35,7 @@ export declare type Config;
export declare type NormalisedConfig = {
getRedirectionURL: (
- context: GetRedirectionURLContextType,
+ context: NormalisedGetRedirectionURLContext,
userContext: UserContext
) => Promise;
onHandleEvent: RecipeOnHandleEventFunction;
diff --git a/lib/build/recipe/session/components/themes/translations.d.ts b/lib/build/recipe/session/components/themes/translations.d.ts
index 40c73700a..ba13878f9 100644
--- a/lib/build/recipe/session/components/themes/translations.d.ts
+++ b/lib/build/recipe/session/components/themes/translations.d.ts
@@ -6,6 +6,7 @@ export declare const defaultTranslationsSession: {
AUTH_PAGE_HEADER_TITLE_SIGN_IN_AND_UP: string;
AUTH_PAGE_HEADER_TITLE_SIGN_IN: string;
AUTH_PAGE_HEADER_TITLE_SIGN_UP: string;
+ AUTH_PAGE_HEADER_TITLE_SIGN_IN_UP_TO_APP: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_START: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_SIGN_UP_LINK: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_END: string;
diff --git a/lib/build/recipe/session/prebuiltui.d.ts b/lib/build/recipe/session/prebuiltui.d.ts
index fb829532d..85559c54b 100644
--- a/lib/build/recipe/session/prebuiltui.d.ts
+++ b/lib/build/recipe/session/prebuiltui.d.ts
@@ -16,6 +16,7 @@ export declare class SessionPreBuiltUI extends RecipeRouter {
AUTH_PAGE_HEADER_TITLE_SIGN_IN_AND_UP: string;
AUTH_PAGE_HEADER_TITLE_SIGN_IN: string;
AUTH_PAGE_HEADER_TITLE_SIGN_UP: string;
+ AUTH_PAGE_HEADER_TITLE_SIGN_IN_UP_TO_APP: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_START: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_SIGN_UP_LINK: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_END: string;
diff --git a/lib/build/recipe/session/recipe.d.ts b/lib/build/recipe/session/recipe.d.ts
index 536d3cae5..674e168a9 100644
--- a/lib/build/recipe/session/recipe.d.ts
+++ b/lib/build/recipe/session/recipe.d.ts
@@ -7,7 +7,8 @@ import type {
Navigate,
NormalisedConfigWithAppInfoAndRecipeID,
RecipeInitResult,
- SuccessRedirectContext,
+ SuccessRedirectContextInApp,
+ SuccessRedirectContextOAuth2,
UserContext,
} from "../../types";
import type { ClaimValidationError, SessionClaimValidator } from "supertokens-web-js/recipe/session";
@@ -52,14 +53,15 @@ export default class Session extends RecipeModule void) => () => void;
validateGlobalClaimsAndHandleSuccessRedirection: (
successRedirectContext:
- | (Omit & {
+ | ((Omit | Omit) & {
recipeId: string;
+ tenantIdFromQueryParams: string | undefined;
})
| undefined,
fallbackRecipeId: string,
- redirectToPath?: string,
- userContext?: UserContext,
- navigate?: Navigate
+ redirectToPath: string | undefined,
+ userContext: UserContext | undefined,
+ navigate: Navigate | undefined
) => Promise;
/**
* This should only get called if validateGlobalClaimsAndHandleSuccessRedirection couldn't get a redirectInfo
diff --git a/lib/build/recipe/thirdparty/components/features/signInAndUp/index.d.ts b/lib/build/recipe/thirdparty/components/features/signInAndUp/index.d.ts
index 55967b373..554676d75 100644
--- a/lib/build/recipe/thirdparty/components/features/signInAndUp/index.d.ts
+++ b/lib/build/recipe/thirdparty/components/features/signInAndUp/index.d.ts
@@ -1,9 +1,11 @@
import * as React from "react";
import type { Navigate, PartialAuthComponentProps, UserContext } from "../../../../../types";
+import type { AuthSuccessContext } from "../../../../authRecipe/types";
import type Recipe from "../../../recipe";
import type { ComponentOverrideMap, SignInAndUpThemeProps } from "../../../types";
export declare function useChildProps(
recipe: Recipe,
+ onAuthSuccess: (successContext: AuthSuccessContext) => Promise,
error: string | undefined,
onError: (err: string) => void,
clearError: () => void,
diff --git a/lib/build/recipe/thirdparty/components/themes/translations.d.ts b/lib/build/recipe/thirdparty/components/themes/translations.d.ts
index f42500509..426312d4d 100644
--- a/lib/build/recipe/thirdparty/components/themes/translations.d.ts
+++ b/lib/build/recipe/thirdparty/components/themes/translations.d.ts
@@ -13,6 +13,7 @@ export declare const defaultTranslationsThirdParty: {
AUTH_PAGE_HEADER_TITLE_SIGN_IN_AND_UP: string;
AUTH_PAGE_HEADER_TITLE_SIGN_IN: string;
AUTH_PAGE_HEADER_TITLE_SIGN_UP: string;
+ AUTH_PAGE_HEADER_TITLE_SIGN_IN_UP_TO_APP: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_START: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_SIGN_UP_LINK: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_END: string;
diff --git a/lib/build/recipe/thirdparty/index.d.ts b/lib/build/recipe/thirdparty/index.d.ts
index 6b8fb2194..6b2d6695f 100644
--- a/lib/build/recipe/thirdparty/index.d.ts
+++ b/lib/build/recipe/thirdparty/index.d.ts
@@ -31,7 +31,11 @@ export default class Wrapper {
import("./types").NormalisedConfig
>;
static signOut(input?: { userContext?: UserContext }): Promise;
- static redirectToThirdPartyLogin(input: { thirdPartyId: string; userContext?: UserContext }): Promise<{
+ static redirectToThirdPartyLogin(input: {
+ thirdPartyId: string;
+ shouldTryLinkingWithSessionUser?: boolean;
+ userContext?: UserContext;
+ }): Promise<{
status: "OK" | "ERROR";
}>;
static getStateAndOtherInfoFromStorage(input?: {
@@ -41,6 +45,7 @@ export default class Wrapper {
thirdPartyId: string;
frontendRedirectURI: string;
redirectURIOnProviderDashboard?: string;
+ shouldTryLinkingWithSessionUser?: boolean;
userContext?: UserContext;
options?: RecipeFunctionOptions;
}): Promise;
diff --git a/lib/build/recipe/thirdparty/prebuiltui.d.ts b/lib/build/recipe/thirdparty/prebuiltui.d.ts
index 0ae83b7e5..4c3899d89 100644
--- a/lib/build/recipe/thirdparty/prebuiltui.d.ts
+++ b/lib/build/recipe/thirdparty/prebuiltui.d.ts
@@ -23,6 +23,7 @@ export declare class ThirdPartyPreBuiltUI extends RecipeRouter {
AUTH_PAGE_HEADER_TITLE_SIGN_IN_AND_UP: string;
AUTH_PAGE_HEADER_TITLE_SIGN_IN: string;
AUTH_PAGE_HEADER_TITLE_SIGN_UP: string;
+ AUTH_PAGE_HEADER_TITLE_SIGN_IN_UP_TO_APP: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_START: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_SIGN_UP_LINK: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_END: string;
diff --git a/lib/build/recipe/thirdparty/types.d.ts b/lib/build/recipe/thirdparty/types.d.ts
index 91531ef39..68867e1c1 100644
--- a/lib/build/recipe/thirdparty/types.d.ts
+++ b/lib/build/recipe/thirdparty/types.d.ts
@@ -81,4 +81,5 @@ export declare type StateObject = WebJsStateObject & {
export declare type CustomStateProperties = {
rid: string;
redirectToPath: string;
+ oauth2LoginChallenge?: string;
};
diff --git a/lib/build/recipe/thirdparty/utils.d.ts b/lib/build/recipe/thirdparty/utils.d.ts
index b6324cf67..3611a90b9 100644
--- a/lib/build/recipe/thirdparty/utils.d.ts
+++ b/lib/build/recipe/thirdparty/utils.d.ts
@@ -17,6 +17,7 @@ export declare function redirectToThirdPartyLogin(input: {
thirdPartyId: string;
config: NormalisedConfig;
userContext: UserContext;
+ shouldTryLinkingWithSessionUser: boolean | undefined;
recipeImplementation: WebJSRecipeInterface;
}): Promise<{
status: "OK" | "ERROR";
diff --git a/lib/build/recipe/totp/components/themes/translations.d.ts b/lib/build/recipe/totp/components/themes/translations.d.ts
index 949499447..34fbb59e6 100644
--- a/lib/build/recipe/totp/components/themes/translations.d.ts
+++ b/lib/build/recipe/totp/components/themes/translations.d.ts
@@ -25,6 +25,7 @@ export declare const defaultTranslationsTOTP: {
AUTH_PAGE_HEADER_TITLE_SIGN_IN_AND_UP: string;
AUTH_PAGE_HEADER_TITLE_SIGN_IN: string;
AUTH_PAGE_HEADER_TITLE_SIGN_UP: string;
+ AUTH_PAGE_HEADER_TITLE_SIGN_IN_UP_TO_APP: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_START: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_SIGN_UP_LINK: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_END: string;
diff --git a/lib/build/recipe/totp/prebuiltui.d.ts b/lib/build/recipe/totp/prebuiltui.d.ts
index 7799b5f0a..690aa7282 100644
--- a/lib/build/recipe/totp/prebuiltui.d.ts
+++ b/lib/build/recipe/totp/prebuiltui.d.ts
@@ -35,6 +35,7 @@ export declare class TOTPPreBuiltUI extends RecipeRouter {
AUTH_PAGE_HEADER_TITLE_SIGN_IN_AND_UP: string;
AUTH_PAGE_HEADER_TITLE_SIGN_IN: string;
AUTH_PAGE_HEADER_TITLE_SIGN_UP: string;
+ AUTH_PAGE_HEADER_TITLE_SIGN_IN_UP_TO_APP: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_START: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_SIGN_UP_LINK: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_END: string;
diff --git a/lib/build/session.js b/lib/build/session.js
index ed2d033bb..9fb87e239 100644
--- a/lib/build/session.js
+++ b/lib/build/session.js
@@ -17,6 +17,8 @@ require("react");
require("supertokens-web-js/utils/normalisedURLDomain");
require("supertokens-web-js/utils/normalisedURLPath");
require("react/jsx-runtime");
+require("./oauth2provider-shared.js");
+require("supertokens-web-js/recipe/oauth2provider");
require("./recipeModule-shared.js");
require("./translationContext.js");
require("react-dom");
diff --git a/lib/build/sessionprebuiltui.js b/lib/build/sessionprebuiltui.js
index 027537737..8592885bb 100644
--- a/lib/build/sessionprebuiltui.js
+++ b/lib/build/sessionprebuiltui.js
@@ -22,6 +22,8 @@ require("./multifactorauth-shared2.js");
require("supertokens-web-js/recipe/multifactorauth");
require("supertokens-web-js/utils/sessionClaimValidatorStore");
require("./recipeModule-shared.js");
+require("./oauth2provider-shared.js");
+require("supertokens-web-js/recipe/oauth2provider");
require("./authRecipe-shared.js");
require("supertokens-web-js/lib/build/normalisedURLPath");
require("supertokens-web-js/recipe/session");
@@ -83,7 +85,7 @@ function LogoutButton(_a) {
}
var styles =
- '/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved.\n *\n * This software is licensed under the Apache License, Version 2.0 (the\n * "License") as published by the Apache Software Foundation.\n *\n * You may not use this file except in compliance with the License. You may\n * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\n[data-supertokens~="container"] {\n --palette-background: 255, 255, 255;\n --palette-inputBackground: 250, 250, 250;\n --palette-inputBorder: 224, 224, 224;\n --palette-primary: 28, 34, 42;\n --palette-primaryBorder: 45, 54, 68;\n --palette-success: 65, 167, 0;\n --palette-successBackground: 217, 255, 191;\n --palette-error: 255, 23, 23;\n --palette-errorBackground: 255, 241, 235;\n --palette-textTitle: 0, 0, 0;\n --palette-textLabel: 0, 0, 0;\n --palette-textInput: 0, 0, 0;\n --palette-textPrimary: 128, 128, 128;\n --palette-textLink: 0, 122, 255;\n --palette-buttonText: 255, 255, 255;\n --palette-textGray: 54, 54, 54;\n --palette-superTokensBrandingBackground: 242, 245, 246;\n --palette-superTokensBrandingText: 173, 189, 196;\n\n --font-size-0: 12px;\n --font-size-1: 14px;\n --font-size-2: 16px;\n --font-size-3: 19px;\n --font-size-4: 24px;\n --font-size-5: 28px;\n}\n\n/*\n * Default styles.\n */\n\n@keyframes slideTop {\n 0% {\n transform: translateY(-5px);\n }\n 100% {\n transform: translateY(0px);\n }\n}\n\n@keyframes swing-in-top-fwd {\n 0% {\n transform: rotateX(-100deg);\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n transform: rotateX(0deg);\n transform-origin: top;\n opacity: 1;\n }\n}\n\n[data-supertokens~="container"] {\n font-family: "Arial", sans-serif;\n margin: 12px auto;\n margin-top: 26px;\n margin-bottom: 26px;\n width: 420px;\n text-align: center;\n border-radius: 8px;\n box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.16);\n background-color: rgb(var(--palette-background));\n}\n\n@media (max-width: 440px) {\n [data-supertokens~="container"] {\n width: 95vw;\n }\n}\n\n[data-supertokens~="row"] {\n margin: 0 auto;\n width: 76%;\n padding-top: 30px;\n padding-bottom: 10px;\n}\n\n[data-supertokens~="superTokensBranding"] {\n display: block;\n margin: 10px auto 0;\n background: rgb(var(--palette-superTokensBrandingBackground));\n color: rgb(var(--palette-superTokensBrandingText));\n text-decoration: none;\n width: -webkit-fit-content;\n width: -moz-fit-content;\n width: fit-content;\n border-radius: 6px 6px 0 0;\n padding: 4px 9px;\n font-weight: 400;\n font-size: var(--font-size-0);\n letter-spacing: 0.4px;\n}\n\n[data-supertokens~="generalError"] {\n background: rgb(var(--palette-errorBackground));\n padding-top: 10px;\n padding-bottom: 10px;\n margin-bottom: 10px;\n margin-top: 24px;\n padding-left: 18px;\n padding-right: 18px;\n letter-spacing: 0.2px;\n font-size: var(--font-size-1);\n border-radius: 8px;\n color: rgb(var(--palette-error));\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n word-wrap: break-word;\n}\n\n[data-supertokens~="headerTitle"] {\n font-size: var(--font-size-4);\n line-height: 27.6px;\n letter-spacing: 0.58px;\n font-weight: 700;\n margin-bottom: 20px;\n color: rgb(var(--palette-textTitle));\n}\n\n[data-supertokens~="headerSubtitle"] {\n font-weight: 400;\n color: rgb(var(--palette-textGray));\n margin-bottom: 21px;\n}\n\n[data-supertokens~="headerSubtitle"][data-supertokens~="secondaryText"] {\n color: rgb(var(--palette-textGray));\n font-weight: 400;\n}\n\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] {\n max-width: 300px;\n margin-top: 10px;\n}\n\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] a {\n line-height: 21px;\n}\n\n/* TODO: split the link style into separate things*/\n\n/* We add this before primary and secondary text, because if they are applied to the same element the other ones take priority */\n\n[data-supertokens~="link"] {\n padding-left: 3px;\n padding-right: 3px;\n color: rgb(var(--palette-textLink));\n font-size: var(--font-size-1);\n cursor: pointer;\n letter-spacing: 0.16px;\n line-height: 26px;\n}\n\n[data-supertokens~="primaryText"] {\n font-size: var(--font-size-2);\n font-weight: 400;\n letter-spacing: 0.4px;\n line-height: 21px;\n color: rgb(var(--palette-textLabel));\n}\n\n[data-supertokens~="secondaryText"] {\n font-size: var(--font-size-1);\n font-weight: 400;\n letter-spacing: 0.4px;\n color: rgb(var(--palette-textPrimary));\n}\n\n[data-supertokens~="secondaryText"] strong {\n font-weight: 600;\n}\n\n[data-supertokens~="divider"] {\n margin-top: 1.5em;\n margin-bottom: 1.5em;\n border-bottom: 0.3px solid #dddddd;\n align-items: center;\n padding-bottom: 5px;\n flex: 3 3;\n}\n\n[data-supertokens~="headerTinyTitle"] {\n margin-top: 24px;\n font-size: var(--font-size-5);\n letter-spacing: 1.1px;\n font-weight: 700;\n line-height: 28px;\n}\n\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n}\n\n[data-supertokens~="secondaryLinkWithArrow"]:hover {\n position: relative;\n left: 2px;\n word-spacing: 4px;\n}\n\n[data-supertokens~="generalSuccess"] {\n color: rgb(var(--palette-success));\n font-size: var(--font-size-1);\n background: rgb(var(--palette-successBackground));\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n padding: 9px 15px 9px 15px;\n border-radius: 6px;\n display: inline-block;\n}\n\n[data-supertokens~="spinner"] {\n width: 80px;\n height: auto;\n padding-top: 20px;\n padding-bottom: 40px;\n margin: 0 auto;\n}\n\n[data-supertokens~="error"] {\n color: rgb(var(--palette-error));\n}\n\n[data-supertokens~="linkButton"] {\n font-family: "Arial", sans-serif;\n background-color: transparent;\n border: 0;\n}\n\n[data-supertokens~="secondaryLinkWithLeftArrow"] {\n color: rgb(var(--palette-textGray));\n font-weight: 400;\n margin-top: 10px;\n margin-bottom: 40px;\n cursor: pointer;\n}\n\n[data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n margin-right: 0.3em;\n}\n\n[data-supertokens~="secondaryLinkWithLeftArrow"]:hover svg {\n position: relative;\n left: -4px;\n}\n\n[data-supertokens~="button"] {\n font-family: "Arial", sans-serif;\n background-color: rgb(var(--palette-primary));\n color: rgb(var(--palette-buttonText));\n width: 100%;\n height: 34px;\n font-weight: 600;\n border-width: 1px;\n border-style: solid;\n border-radius: 6px;\n border-color: rgb(var(--palette-primaryBorder));\n background-position: center;\n transition: all 0.4s;\n background-size: 12000%;\n cursor: pointer;\n}\n\n[data-supertokens~="button"]:disabled {\n border: none;\n cursor: no-drop;\n}\n\n[data-supertokens~="button"]:active {\n outline: none;\n transition: all 0s;\n background-size: 100%;\n filter: brightness(0.85);\n}\n\n[data-supertokens~="button"]:focus {\n outline: none;\n}\n\n[data-supertokens~="backButtonCommon"] {\n width: 16px;\n height: 13px;\n}\n\n[data-supertokens~="backButton"] {\n cursor: pointer;\n border: none;\n background-color: transparent;\n padding: 0px;\n}\n\n[data-supertokens~="backButtonPlaceholder"] {\n display: block;\n}\n\n[data-supertokens~="delayedRender"] {\n animation-duration: 0.1s;\n animation-name: animate-fade;\n animation-delay: 0.2s;\n animation-fill-mode: backwards;\n}\n\n@keyframes animate-fade {\n 0% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n}\n\n[data-supertokens~="footerLinkGroupVert"] {\n display: flex;\n flex-direction: column;\n margin-top: 10px;\n gap: 24px;\n}\n\n[data-supertokens~="footerLinkGroupVert"] > div {\n cursor: pointer;\n margin: 0;\n}\n\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryText"] {\n font-weight: 400;\n}\n\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n font-weight: 400;\n position: relative;\n left: -6px; /* half the width of the left arrow */\n}\n\n@media (max-width: 360px) {\n [data-supertokens~="footerLinkGroupVert"] {\n flex-direction: column;\n }\n [data-supertokens~="footerLinkGroupVert"] > div {\n margin: 0 auto;\n }\n}\n\n[data-supertokens~="footerLinkGroupVert"] div:only-child {\n margin-left: auto;\n margin-right: auto;\n margin-top: 14px;\n}\n\n[data-supertokens~="withBackButton"] {\n position: relative;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n[data-supertokens~="dividerWithOr"] {\n padding-top: 5px;\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n color: rgb(var(--palette-textPrimary));\n}\n\n[data-supertokens~="dividerText"] {\n flex: 1 1;\n font-weight: 400;\n font-size: var(--font-size-1);\n}\n\n[data-supertokens~="formLabelWithLinkWrapper"] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n[data-supertokens~="formLabelLinkBtn"] {\n width: auto;\n margin-top: 0;\n line-height: 24px;\n font-size: var(--font-size-0);\n}\n\n[data-supertokens~="formLabelLinkBtn"]:hover {\n text-decoration: underline;\n}\n\n[data-supertokens~="formLabelLinkBtn"]:disabled {\n color: rgb(var(--palette-textPrimary));\n cursor: default;\n text-decoration: none;\n}\n\n[data-supertokens~="authComponentList"] {\n padding-bottom: 20px;\n}\n\n[data-supertokens~="buttonWithArrow"] {\n border-radius: 6px;\n border: 1px solid #d0d5dd;\n width: 100%;\n color: rgb(var(--palette-textGray));\n display: flex;\n justify-content: center;\n align-items: center;\n gap: 5px;\n margin: 24px 0;\n min-height: 48px;\n cursor: pointer;\n}\n\n[data-supertokens~="buttonWithArrow"]:hover {\n background-color: rgb(var(--palette-inputBackground));\n}\n\n[data-supertokens~="buttonWithArrow"] [data-supertokens~="secondaryText"] {\n font-weight: 700;\n font-size: var(--font-size-2);\n color: rgb(var(--palette-textGray));\n margin: 0;\n}\n\n[data-supertokens~="buttonWithArrow"]:hover [data-supertokens~="secondaryLinkWithRightArrow"] ~ svg {\n position: relative;\n left: 2px;\n}\n\n[data-supertokens~="buttonWithArrow"]:hover [data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n position: relative;\n left: -2px;\n}\n\n[data-supertokens~="buttonWithArrow"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n display: flex;\n align-items: center;\n}\n\n/* Override */\n\n[data-supertokens~="accessDenied"] [data-supertokens~="row"] {\n padding-bottom: 24px;\n}\n\n[data-supertokens~="accessDenied"] [data-supertokens~="divider"] {\n padding: 0;\n margin: 34px 0 18px 0;\n}\n\n[data-supertokens~="accessDenied"] [data-supertokens~="headerTitle"] {\n margin: 10px 0 0 0;\n font-style: normal;\n font-weight: 600;\n font-size: 20px;\n line-height: 30px;\n}\n\n/* Override end */\n\n[data-supertokens~="center"] {\n height: 100%;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n flex: 1 1 auto;\n}\n\n[data-supertokens~="buttonsGroup"] {\n margin-top: 34px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n[data-supertokens~="buttonBase"] {\n font-family: "Arial", sans-serif;\n font-size: var(--font-size-1);\n line-height: 21px;\n font-weight: 400;\n background: transparent;\n outline: none;\n border: none;\n cursor: pointer;\n}\n\n[data-supertokens~="backButton"] {\n color: rgb(var(--palette-textLink));\n}\n\n[data-supertokens~="logoutButton"] {\n display: flex;\n align-items: center;\n gap: 6px;\n color: rgb(var(--palette-textGray));\n}\n\n[data-supertokens~="primaryText"][data-supertokens~="accessDeniedError"] {\n font-weight: 400;\n}\n';
+ '/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved.\n *\n * This software is licensed under the Apache License, Version 2.0 (the\n * "License") as published by the Apache Software Foundation.\n *\n * You may not use this file except in compliance with the License. You may\n * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\n[data-supertokens~="container"] {\n --palette-background: 255, 255, 255;\n --palette-inputBackground: 250, 250, 250;\n --palette-inputBorder: 224, 224, 224;\n --palette-primary: 28, 34, 42;\n --palette-primaryBorder: 45, 54, 68;\n --palette-success: 65, 167, 0;\n --palette-successBackground: 217, 255, 191;\n --palette-error: 255, 23, 23;\n --palette-errorBackground: 255, 241, 235;\n --palette-textTitle: 0, 0, 0;\n --palette-textLabel: 0, 0, 0;\n --palette-textInput: 0, 0, 0;\n --palette-textPrimary: 128, 128, 128;\n --palette-textLink: 0, 122, 255;\n --palette-buttonText: 255, 255, 255;\n --palette-textGray: 54, 54, 54;\n --palette-superTokensBrandingBackground: 242, 245, 246;\n --palette-superTokensBrandingText: 173, 189, 196;\n\n --font-size-0: 12px;\n --font-size-1: 14px;\n --font-size-2: 16px;\n --font-size-3: 19px;\n --font-size-4: 24px;\n --font-size-5: 28px;\n}\n\n/*\n * Default styles.\n */\n\n@keyframes slideTop {\n 0% {\n transform: translateY(-5px);\n }\n 100% {\n transform: translateY(0px);\n }\n}\n\n@keyframes swing-in-top-fwd {\n 0% {\n transform: rotateX(-100deg);\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n transform: rotateX(0deg);\n transform-origin: top;\n opacity: 1;\n }\n}\n\n[data-supertokens~="container"] {\n font-family: "Arial", sans-serif;\n margin: 12px auto;\n margin-top: 26px;\n margin-bottom: 26px;\n width: 420px;\n text-align: center;\n border-radius: 8px;\n box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.16);\n background-color: rgb(var(--palette-background));\n}\n\n@media (max-width: 440px) {\n [data-supertokens~="container"] {\n width: 95vw;\n }\n}\n\n[data-supertokens~="row"] {\n margin: 0 auto;\n width: 76%;\n padding-top: 30px;\n padding-bottom: 10px;\n}\n\n[data-supertokens~="superTokensBranding"] {\n display: block;\n margin: 10px auto 0;\n background: rgb(var(--palette-superTokensBrandingBackground));\n color: rgb(var(--palette-superTokensBrandingText));\n text-decoration: none;\n width: -webkit-fit-content;\n width: -moz-fit-content;\n width: fit-content;\n border-radius: 6px 6px 0 0;\n padding: 4px 9px;\n font-weight: 400;\n font-size: var(--font-size-0);\n letter-spacing: 0.4px;\n}\n\n[data-supertokens~="generalError"] {\n background: rgb(var(--palette-errorBackground));\n padding-top: 10px;\n padding-bottom: 10px;\n margin-bottom: 10px;\n margin-top: 24px;\n padding-left: 18px;\n padding-right: 18px;\n letter-spacing: 0.2px;\n font-size: var(--font-size-1);\n border-radius: 8px;\n color: rgb(var(--palette-error));\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n word-wrap: break-word;\n}\n\n[data-supertokens~="headerTitle"] {\n font-size: var(--font-size-4);\n line-height: 27.6px;\n letter-spacing: 0.58px;\n font-weight: 700;\n margin-bottom: 20px;\n color: rgb(var(--palette-textTitle));\n}\n\n[data-supertokens~="headerSubtitle"] {\n font-weight: 400;\n color: rgb(var(--palette-textGray));\n margin-bottom: 21px;\n}\n\n[data-supertokens~="headerSubtitle"][data-supertokens~="secondaryText"] {\n color: rgb(var(--palette-textGray));\n font-weight: 400;\n}\n\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] {\n max-width: 300px;\n margin-top: 10px;\n}\n\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] a {\n line-height: 21px;\n}\n\n/* TODO: split the link style into separate things*/\n\n/* We add this before primary and secondary text, because if they are applied to the same element the other ones take priority */\n\n[data-supertokens~="link"] {\n padding-left: 3px;\n padding-right: 3px;\n color: rgb(var(--palette-textLink));\n font-size: var(--font-size-1);\n cursor: pointer;\n letter-spacing: 0.16px;\n line-height: 26px;\n}\n\n[data-supertokens~="primaryText"] {\n font-size: var(--font-size-2);\n font-weight: 400;\n letter-spacing: 0.4px;\n line-height: 21px;\n color: rgb(var(--palette-textLabel));\n}\n\n[data-supertokens~="secondaryText"] {\n font-size: var(--font-size-1);\n font-weight: 400;\n letter-spacing: 0.4px;\n color: rgb(var(--palette-textPrimary));\n}\n\n[data-supertokens~="secondaryText"] strong {\n font-weight: 600;\n}\n\n[data-supertokens~="divider"] {\n margin-top: 1.5em;\n margin-bottom: 1.5em;\n border-bottom: 0.3px solid #dddddd;\n align-items: center;\n padding-bottom: 5px;\n flex: 3 3;\n}\n\n[data-supertokens~="headerTinyTitle"] {\n margin-top: 24px;\n font-size: var(--font-size-5);\n letter-spacing: 1.1px;\n font-weight: 700;\n line-height: 28px;\n}\n\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n}\n\n[data-supertokens~="secondaryLinkWithArrow"]:hover {\n position: relative;\n left: 2px;\n word-spacing: 4px;\n}\n\n[data-supertokens~="generalSuccess"] {\n color: rgb(var(--palette-success));\n font-size: var(--font-size-1);\n background: rgb(var(--palette-successBackground));\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n padding: 9px 15px 9px 15px;\n border-radius: 6px;\n display: inline-block;\n}\n\n[data-supertokens~="spinner"] {\n width: 80px;\n height: auto;\n padding-top: 20px;\n padding-bottom: 40px;\n margin: 0 auto;\n}\n\n[data-supertokens~="error"] {\n color: rgb(var(--palette-error));\n}\n\n[data-supertokens~="linkButton"] {\n font-family: "Arial", sans-serif;\n background-color: transparent;\n border: 0;\n}\n\n[data-supertokens~="secondaryLinkWithLeftArrow"] {\n color: rgb(var(--palette-textGray));\n font-weight: 400;\n margin-top: 10px;\n margin-bottom: 40px;\n cursor: pointer;\n}\n\n[data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n margin-right: 0.3em;\n}\n\n[data-supertokens~="secondaryLinkWithLeftArrow"]:hover svg {\n position: relative;\n left: -4px;\n}\n\n[data-supertokens~="button"] {\n font-family: "Arial", sans-serif;\n background-color: rgb(var(--palette-primary));\n color: rgb(var(--palette-buttonText));\n width: 100%;\n height: 34px;\n font-weight: 600;\n border-width: 1px;\n border-style: solid;\n border-radius: 6px;\n border-color: rgb(var(--palette-primaryBorder));\n background-position: center;\n transition: all 0.4s;\n background-size: 12000%;\n cursor: pointer;\n}\n\n[data-supertokens~="button"]:disabled {\n border: none;\n cursor: no-drop;\n}\n\n[data-supertokens~="button"]:active {\n outline: none;\n transition: all 0s;\n background-size: 100%;\n filter: brightness(0.85);\n}\n\n[data-supertokens~="button"]:focus {\n outline: none;\n}\n\n[data-supertokens~="backButtonCommon"] {\n width: 16px;\n height: 13px;\n}\n\n[data-supertokens~="backButton"] {\n cursor: pointer;\n border: none;\n background-color: transparent;\n padding: 0px;\n}\n\n[data-supertokens~="backButtonPlaceholder"] {\n display: block;\n}\n\n[data-supertokens~="delayedRender"] {\n animation-duration: 0.1s;\n animation-name: animate-fade;\n animation-delay: 0.2s;\n animation-fill-mode: backwards;\n}\n\n@keyframes animate-fade {\n 0% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n}\n\n[data-supertokens~="footerLinkGroupVert"] {\n display: flex;\n flex-direction: column;\n margin-top: 10px;\n gap: 24px;\n}\n\n[data-supertokens~="footerLinkGroupVert"] > div {\n cursor: pointer;\n margin: 0;\n}\n\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryText"] {\n font-weight: 400;\n}\n\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n font-weight: 400;\n position: relative;\n left: -6px; /* half the width of the left arrow */\n}\n\n@media (max-width: 360px) {\n [data-supertokens~="footerLinkGroupVert"] {\n flex-direction: column;\n }\n [data-supertokens~="footerLinkGroupVert"] > div {\n margin: 0 auto;\n }\n}\n\n[data-supertokens~="footerLinkGroupVert"] div:only-child {\n margin-left: auto;\n margin-right: auto;\n margin-top: 14px;\n}\n\n[data-supertokens~="withBackButton"] {\n position: relative;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n[data-supertokens~="dividerWithOr"] {\n padding-top: 5px;\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n color: rgb(var(--palette-textPrimary));\n}\n\n[data-supertokens~="dividerText"] {\n flex: 1 1;\n font-weight: 400;\n font-size: var(--font-size-1);\n}\n\n[data-supertokens~="formLabelWithLinkWrapper"] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n[data-supertokens~="formLabelLinkBtn"] {\n width: auto;\n margin-top: 0;\n line-height: 24px;\n font-size: var(--font-size-0);\n}\n\n[data-supertokens~="formLabelLinkBtn"]:hover {\n text-decoration: underline;\n}\n\n[data-supertokens~="formLabelLinkBtn"]:disabled {\n color: rgb(var(--palette-textPrimary));\n cursor: default;\n text-decoration: none;\n}\n\n[data-supertokens~="authComponentList"] {\n padding-bottom: 20px;\n}\n\n[data-supertokens~="authPageTitleOAuthClient"] {\n color: rgb(var(--palette-textGray));\n font-size: var(--font-size-1);\n font-weight: 400;\n margin: 10px 0 25px;\n}\n\n[data-supertokens~="authPageTitleOAuthClientUrl"] {\n text-decoration: none;\n}\n\n[data-supertokens~="authPageTitleOAuthClientLogo"] {\n width: 44px;\n height: 44px;\n margin-bottom: 10px;\n}\n\n[data-supertokens~="authPageTitleOAuthClient"] [data-supertokens~="authPageTitleOAuthClientName"] {\n color: rgb(var(--palette-textTitle));\n}\n\n[data-supertokens~="buttonWithArrow"] {\n border-radius: 6px;\n border: 1px solid #d0d5dd;\n width: 100%;\n color: rgb(var(--palette-textGray));\n display: flex;\n justify-content: center;\n align-items: center;\n gap: 5px;\n margin: 24px 0;\n min-height: 48px;\n cursor: pointer;\n}\n\n[data-supertokens~="buttonWithArrow"]:hover {\n background-color: rgb(var(--palette-inputBackground));\n}\n\n[data-supertokens~="buttonWithArrow"] [data-supertokens~="secondaryText"] {\n font-weight: 700;\n font-size: var(--font-size-2);\n color: rgb(var(--palette-textGray));\n margin: 0;\n}\n\n[data-supertokens~="buttonWithArrow"]:hover [data-supertokens~="secondaryLinkWithRightArrow"] ~ svg {\n position: relative;\n left: 2px;\n}\n\n[data-supertokens~="buttonWithArrow"]:hover [data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n position: relative;\n left: -2px;\n}\n\n[data-supertokens~="buttonWithArrow"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n display: flex;\n align-items: center;\n}\n\n/* Override */\n\n[data-supertokens~="accessDenied"] [data-supertokens~="row"] {\n padding-bottom: 24px;\n}\n\n[data-supertokens~="accessDenied"] [data-supertokens~="divider"] {\n padding: 0;\n margin: 34px 0 18px 0;\n}\n\n[data-supertokens~="accessDenied"] [data-supertokens~="headerTitle"] {\n margin: 10px 0 0 0;\n font-style: normal;\n font-weight: 600;\n font-size: 20px;\n line-height: 30px;\n}\n\n/* Override end */\n\n[data-supertokens~="center"] {\n height: 100%;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n flex: 1 1 auto;\n}\n\n[data-supertokens~="buttonsGroup"] {\n margin-top: 34px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n[data-supertokens~="buttonBase"] {\n font-family: "Arial", sans-serif;\n font-size: var(--font-size-1);\n line-height: 21px;\n font-weight: 400;\n background: transparent;\n outline: none;\n border: none;\n cursor: pointer;\n}\n\n[data-supertokens~="backButton"] {\n color: rgb(var(--palette-textLink));\n}\n\n[data-supertokens~="logoutButton"] {\n display: flex;\n align-items: center;\n gap: 6px;\n color: rgb(var(--palette-textGray));\n}\n\n[data-supertokens~="primaryText"][data-supertokens~="accessDeniedError"] {\n font-weight: 400;\n}\n';
var ThemeBase = function (_a) {
var children = _a.children,
diff --git a/lib/build/superTokens.d.ts b/lib/build/superTokens.d.ts
index 6fa48b469..3d5293d6d 100644
--- a/lib/build/superTokens.d.ts
+++ b/lib/build/superTokens.d.ts
@@ -3,7 +3,14 @@ import type RecipeModule from "./recipe/recipeModule";
import type { BaseRecipeModule } from "./recipe/recipeModule/baseRecipeModule";
import type { NormalisedConfig as NormalisedRecipeModuleConfig } from "./recipe/recipeModule/types";
import type { TranslationFunc, TranslationStore } from "./translation/translationHelpers";
-import type { Navigate, GetRedirectionURLContext, NormalisedAppInfo, SuperTokensConfig, UserContext } from "./types";
+import type {
+ Navigate,
+ GetRedirectionURLContext,
+ NormalisedAppInfo,
+ SuperTokensConfig,
+ UserContext,
+ NormalisedGetRedirectionURLContext,
+} from "./types";
export default class SuperTokens {
private static instance?;
static usesDynamicLoginMethods: boolean;
@@ -31,7 +38,10 @@ export default class SuperTokens {
): RecipeModule;
changeLanguage: (lang: string) => Promise;
loadTranslation(store: TranslationStore): void;
- getRedirectUrl(context: GetRedirectionURLContext, userContext: UserContext): Promise;
+ getRedirectUrl(
+ context: NormalisedGetRedirectionURLContext,
+ userContext: UserContext
+ ): Promise;
redirectToAuth: (options: {
show?: "signin" | "signup" | undefined;
navigate?: Navigate | undefined;
@@ -41,7 +51,7 @@ export default class SuperTokens {
}) => Promise;
redirectToUrl: (redirectUrl: string, navigate?: Navigate) => Promise;
redirect: (
- context: GetRedirectionURLContext,
+ context: NormalisedGetRedirectionURLContext,
navigate?: Navigate,
queryParams?: Record,
userContext?: UserContext
diff --git a/lib/build/thirdparty-shared.js b/lib/build/thirdparty-shared.js
index 7f41ec363..c46ce4926 100644
--- a/lib/build/thirdparty-shared.js
+++ b/lib/build/thirdparty-shared.js
@@ -1690,10 +1690,19 @@ var getFunctionOverrides = function (recipeId, onHandleEvent) {
});
},
setStateAndOtherInfoToStorage: function (input) {
+ var _a;
+ var loginChallenge =
+ (_a = genericComponentOverrideContext.getQueryParams("loginChallenge")) !== null && _a !== void 0
+ ? _a
+ : undefined;
return originalImp.setStateAndOtherInfoToStorage({
state: genericComponentOverrideContext.__assign(
genericComponentOverrideContext.__assign({}, input.state),
- { rid: recipeId, redirectToPath: genericComponentOverrideContext.getRedirectToPathFromURL() }
+ {
+ rid: recipeId,
+ oauth2LoginChallenge: loginChallenge,
+ redirectToPath: genericComponentOverrideContext.getRedirectToPathFromURL(),
+ }
),
userContext: input.userContext,
});
@@ -1856,6 +1865,7 @@ function redirectToThirdPartyLogin(input) {
thirdPartyId: input.thirdPartyId,
frontendRedirectURI: provider.getRedirectURL(),
redirectURIOnProviderDashboard: provider.getRedirectURIOnProviderDashboard(),
+ shouldTryLinkingWithSessionUser: input.shouldTryLinkingWithSessionUser,
userContext: input.userContext,
}),
];
diff --git a/lib/build/thirdparty.js b/lib/build/thirdparty.js
index 287ebc3ca..028c8b170 100644
--- a/lib/build/thirdparty.js
+++ b/lib/build/thirdparty.js
@@ -19,6 +19,8 @@ require("./authRecipe-shared2.js");
require("./recipeModule-shared.js");
require("./multifactorauth-shared.js");
require("supertokens-web-js/recipe/session");
+require("./oauth2provider-shared.js");
+require("supertokens-web-js/recipe/oauth2provider");
require("./authRecipe-shared.js");
require("./translationContext.js");
require("supertokens-web-js/lib/build/normalisedURLPath");
@@ -70,6 +72,7 @@ var Wrapper = /** @class */ (function () {
thirdPartyId: input.thirdPartyId,
config: recipeInstance.config,
userContext: genericComponentOverrideContext.getNormalisedUserContext(input.userContext),
+ shouldTryLinkingWithSessionUser: input.shouldTryLinkingWithSessionUser,
recipeImplementation: recipeInstance.webJSRecipe,
}),
];
diff --git a/lib/build/thirdpartyprebuiltui.js b/lib/build/thirdpartyprebuiltui.js
index 994a44195..c6f19d687 100644
--- a/lib/build/thirdpartyprebuiltui.js
+++ b/lib/build/thirdpartyprebuiltui.js
@@ -12,7 +12,8 @@ var authCompWrapper = require("./authCompWrapper.js");
var types = require("./multifactorauth-shared.js");
var STGeneralError = require("supertokens-web-js/utils/error");
var emailverification = require("./emailverification.js");
-var recipe$1 = require("./emailverification-shared.js");
+var recipe$2 = require("./emailverification-shared.js");
+var recipe$1 = require("./oauth2provider-shared.js");
require("supertokens-web-js");
require("supertokens-web-js/utils/cookieHandler");
require("supertokens-web-js/utils/postSuperTokensInitCallbacks");
@@ -35,6 +36,7 @@ require("./session-shared.js");
require("supertokens-web-js/recipe/thirdparty");
require("./authRecipe-shared2.js");
require("supertokens-web-js/recipe/emailverification");
+require("supertokens-web-js/recipe/oauth2provider");
function _interopDefault(e) {
return e && e.__esModule ? e : { default: e };
@@ -71,7 +73,7 @@ var React__namespace = /*#__PURE__*/ _interopNamespace(React);
var STGeneralError__default = /*#__PURE__*/ _interopDefault(STGeneralError);
var styles =
- '[data-supertokens~="container"] {\n --palette-background: 255, 255, 255;\n --palette-inputBackground: 250, 250, 250;\n --palette-inputBorder: 224, 224, 224;\n --palette-primary: 28, 34, 42;\n --palette-primaryBorder: 45, 54, 68;\n --palette-success: 65, 167, 0;\n --palette-successBackground: 217, 255, 191;\n --palette-error: 255, 23, 23;\n --palette-errorBackground: 255, 241, 235;\n --palette-textTitle: 0, 0, 0;\n --palette-textLabel: 0, 0, 0;\n --palette-textInput: 0, 0, 0;\n --palette-textPrimary: 128, 128, 128;\n --palette-textLink: 0, 122, 255;\n --palette-buttonText: 255, 255, 255;\n --palette-textGray: 54, 54, 54;\n --palette-superTokensBrandingBackground: 242, 245, 246;\n --palette-superTokensBrandingText: 173, 189, 196;\n\n --font-size-0: 12px;\n --font-size-1: 14px;\n --font-size-2: 16px;\n --font-size-3: 19px;\n --font-size-4: 24px;\n --font-size-5: 28px;\n}\n/*\n * Default styles.\n */\n@keyframes slideTop {\n 0% {\n transform: translateY(-5px);\n }\n 100% {\n transform: translateY(0px);\n }\n}\n@keyframes swing-in-top-fwd {\n 0% {\n transform: rotateX(-100deg);\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n transform: rotateX(0deg);\n transform-origin: top;\n opacity: 1;\n }\n}\n[data-supertokens~="container"] {\n font-family: "Arial", sans-serif;\n margin: 12px auto;\n margin-top: 26px;\n margin-bottom: 26px;\n width: 420px;\n text-align: center;\n border-radius: 8px;\n box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.16);\n background-color: rgb(var(--palette-background));\n}\n@media (max-width: 440px) {\n [data-supertokens~="container"] {\n width: 95vw;\n }\n}\n[data-supertokens~="row"] {\n margin: 0 auto;\n width: 76%;\n padding-top: 30px;\n padding-bottom: 10px;\n}\n[data-supertokens~="superTokensBranding"] {\n display: block;\n margin: 10px auto 0;\n background: rgb(var(--palette-superTokensBrandingBackground));\n color: rgb(var(--palette-superTokensBrandingText));\n text-decoration: none;\n width: -webkit-fit-content;\n width: -moz-fit-content;\n width: fit-content;\n border-radius: 6px 6px 0 0;\n padding: 4px 9px;\n font-weight: 400;\n font-size: var(--font-size-0);\n letter-spacing: 0.4px;\n}\n[data-supertokens~="generalError"] {\n background: rgb(var(--palette-errorBackground));\n padding-top: 10px;\n padding-bottom: 10px;\n margin-bottom: 10px;\n margin-top: 24px;\n padding-left: 18px;\n padding-right: 18px;\n letter-spacing: 0.2px;\n font-size: var(--font-size-1);\n border-radius: 8px;\n color: rgb(var(--palette-error));\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n word-wrap: break-word;\n}\n[data-supertokens~="headerTitle"] {\n font-size: var(--font-size-4);\n line-height: 27.6px;\n letter-spacing: 0.58px;\n font-weight: 700;\n margin-bottom: 20px;\n color: rgb(var(--palette-textTitle));\n}\n[data-supertokens~="headerSubtitle"] {\n font-weight: 400;\n color: rgb(var(--palette-textGray));\n margin-bottom: 21px;\n}\n[data-supertokens~="headerSubtitle"][data-supertokens~="secondaryText"] {\n color: rgb(var(--palette-textGray));\n font-weight: 400;\n}\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] {\n max-width: 300px;\n margin-top: 10px;\n}\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] a {\n line-height: 21px;\n}\n/* TODO: split the link style into separate things*/\n/* We add this before primary and secondary text, because if they are applied to the same element the other ones take priority */\n[data-supertokens~="link"] {\n padding-left: 3px;\n padding-right: 3px;\n color: rgb(var(--palette-textLink));\n font-size: var(--font-size-1);\n cursor: pointer;\n letter-spacing: 0.16px;\n line-height: 26px;\n}\n[data-supertokens~="primaryText"] {\n font-size: var(--font-size-2);\n font-weight: 400;\n letter-spacing: 0.4px;\n line-height: 21px;\n color: rgb(var(--palette-textLabel));\n}\n[data-supertokens~="secondaryText"] {\n font-size: var(--font-size-1);\n font-weight: 400;\n letter-spacing: 0.4px;\n color: rgb(var(--palette-textPrimary));\n}\n[data-supertokens~="secondaryText"] strong {\n font-weight: 600;\n}\n[data-supertokens~="divider"] {\n margin-top: 1.5em;\n margin-bottom: 1.5em;\n border-bottom: 0.3px solid #dddddd;\n align-items: center;\n padding-bottom: 5px;\n flex: 3 3;\n}\n[data-supertokens~="headerTinyTitle"] {\n margin-top: 24px;\n font-size: var(--font-size-5);\n letter-spacing: 1.1px;\n font-weight: 700;\n line-height: 28px;\n}\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithArrow"]:hover {\n position: relative;\n left: 2px;\n word-spacing: 4px;\n}\n[data-supertokens~="generalSuccess"] {\n color: rgb(var(--palette-success));\n font-size: var(--font-size-1);\n background: rgb(var(--palette-successBackground));\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n padding: 9px 15px 9px 15px;\n border-radius: 6px;\n display: inline-block;\n}\n[data-supertokens~="spinner"] {\n width: 80px;\n height: auto;\n padding-top: 20px;\n padding-bottom: 40px;\n margin: 0 auto;\n}\n[data-supertokens~="error"] {\n color: rgb(var(--palette-error));\n}\n[data-supertokens~="linkButton"] {\n font-family: "Arial", sans-serif;\n background-color: transparent;\n border: 0;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"] {\n color: rgb(var(--palette-textGray));\n font-weight: 400;\n margin-top: 10px;\n margin-bottom: 40px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n margin-right: 0.3em;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"]:hover svg {\n position: relative;\n left: -4px;\n}\n[data-supertokens~="button"] {\n font-family: "Arial", sans-serif;\n background-color: rgb(var(--palette-primary));\n color: rgb(var(--palette-buttonText));\n width: 100%;\n height: 34px;\n font-weight: 600;\n border-width: 1px;\n border-style: solid;\n border-radius: 6px;\n border-color: rgb(var(--palette-primaryBorder));\n background-position: center;\n transition: all 0.4s;\n background-size: 12000%;\n cursor: pointer;\n}\n[data-supertokens~="button"]:disabled {\n border: none;\n cursor: no-drop;\n}\n[data-supertokens~="button"]:active {\n outline: none;\n transition: all 0s;\n background-size: 100%;\n filter: brightness(0.85);\n}\n[data-supertokens~="button"]:focus {\n outline: none;\n}\n[data-supertokens~="backButtonCommon"] {\n width: 16px;\n height: 13px;\n}\n[data-supertokens~="backButton"] {\n cursor: pointer;\n border: none;\n background-color: transparent;\n padding: 0px;\n}\n[data-supertokens~="backButtonPlaceholder"] {\n display: block;\n}\n[data-supertokens~="delayedRender"] {\n animation-duration: 0.1s;\n animation-name: animate-fade;\n animation-delay: 0.2s;\n animation-fill-mode: backwards;\n}\n@keyframes animate-fade {\n 0% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n}\n[data-supertokens~="footerLinkGroupVert"] {\n display: flex;\n flex-direction: column;\n margin-top: 10px;\n gap: 24px;\n}\n[data-supertokens~="footerLinkGroupVert"] > div {\n cursor: pointer;\n margin: 0;\n}\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryText"] {\n font-weight: 400;\n}\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n font-weight: 400;\n position: relative;\n left: -6px; /* half the width of the left arrow */\n}\n@media (max-width: 360px) {\n [data-supertokens~="footerLinkGroupVert"] {\n flex-direction: column;\n }\n [data-supertokens~="footerLinkGroupVert"] > div {\n margin: 0 auto;\n }\n}\n[data-supertokens~="footerLinkGroupVert"] div:only-child {\n margin-left: auto;\n margin-right: auto;\n margin-top: 14px;\n}\n[data-supertokens~="withBackButton"] {\n position: relative;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n[data-supertokens~="dividerWithOr"] {\n padding-top: 5px;\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n color: rgb(var(--palette-textPrimary));\n}\n[data-supertokens~="dividerText"] {\n flex: 1 1;\n font-weight: 400;\n font-size: var(--font-size-1);\n}\n[data-supertokens~="formLabelWithLinkWrapper"] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n[data-supertokens~="formLabelLinkBtn"] {\n width: auto;\n margin-top: 0;\n line-height: 24px;\n font-size: var(--font-size-0);\n}\n[data-supertokens~="formLabelLinkBtn"]:hover {\n text-decoration: underline;\n}\n[data-supertokens~="formLabelLinkBtn"]:disabled {\n color: rgb(var(--palette-textPrimary));\n cursor: default;\n text-decoration: none;\n}\n[data-supertokens~="authComponentList"] {\n padding-bottom: 20px;\n}\n[data-supertokens~="buttonWithArrow"] {\n border-radius: 6px;\n border: 1px solid #d0d5dd;\n width: 100%;\n color: rgb(var(--palette-textGray));\n display: flex;\n justify-content: center;\n align-items: center;\n gap: 5px;\n margin: 24px 0;\n min-height: 48px;\n cursor: pointer;\n}\n[data-supertokens~="buttonWithArrow"]:hover {\n background-color: rgb(var(--palette-inputBackground));\n}\n[data-supertokens~="buttonWithArrow"] [data-supertokens~="secondaryText"] {\n font-weight: 700;\n font-size: var(--font-size-2);\n color: rgb(var(--palette-textGray));\n margin: 0;\n}\n[data-supertokens~="buttonWithArrow"]:hover [data-supertokens~="secondaryLinkWithRightArrow"] ~ svg {\n position: relative;\n left: 2px;\n}\n[data-supertokens~="buttonWithArrow"]:hover [data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n position: relative;\n left: -2px;\n}\n[data-supertokens~="buttonWithArrow"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n display: flex;\n align-items: center;\n}\n[data-supertokens~="providerContainer"] {\n padding-top: 9px;\n padding-bottom: 9px;\n\n --logo-size: 34px;\n --logo-horizontal-spacing: 8px;\n}\n[data-supertokens~="button"][data-supertokens~="providerButton"] {\n min-height: 32px;\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: center;\n padding: 2px calc(var(--logo-size) + 2 * var(--logo-horizontal-spacing));\n background-color: white;\n border-color: rgb(221, 221, 221);\n color: black;\n position: relative;\n}\n[data-supertokens~="button"][data-supertokens~="providerButton"]:hover {\n filter: none;\n background-color: #fafafa;\n}\n[data-supertokens~="providerButtonLeft"] {\n width: calc(var(--logo-size));\n position: absolute;\n left: calc(var(--logo-horizontal-spacing));\n}\n[data-supertokens~="providerButtonLogo"] {\n height: 30px;\n display: flex;\n align-items: center;\n}\n[data-supertokens~="providerButtonLogoCenter"] {\n display: flex;\n margin: auto;\n}\n[data-supertokens~="providerButtonText"] {\n font-weight: 400;\n text-align: center;\n justify-content: center;\n overflow: hidden;\n white-space: nowrap;\n display: inline-block;\n flex-grow: 1;\n max-width: 100%;\n font-size: var(--font-size-1);\n text-overflow: ellipsis;\n}\n.scroll-text-animation:hover span,\n.scroll-text-animation:focus span {\n display: inline-block;\n animation: scroll-left 2s linear forwards;\n position: relative;\n width: -webkit-fit-content;\n width: -moz-fit-content;\n width: fit-content;\n text-overflow: clip;\n}\n@keyframes scroll-left {\n 0% {\n transform: translateX(0);\n left: 0%;\n }\n 50% {\n transform: translateX(calc(-100% - 10px));\n left: 100%;\n }\n 100% {\n transform: translateX(calc(-100% - 10px));\n left: 100%;\n }\n}\n@media (max-width: 640px) {\n [data-supertokens~="providerButtonText"] {\n font-size: var(--font-size-0);\n }\n}\n';
+ '[data-supertokens~="container"] {\n --palette-background: 255, 255, 255;\n --palette-inputBackground: 250, 250, 250;\n --palette-inputBorder: 224, 224, 224;\n --palette-primary: 28, 34, 42;\n --palette-primaryBorder: 45, 54, 68;\n --palette-success: 65, 167, 0;\n --palette-successBackground: 217, 255, 191;\n --palette-error: 255, 23, 23;\n --palette-errorBackground: 255, 241, 235;\n --palette-textTitle: 0, 0, 0;\n --palette-textLabel: 0, 0, 0;\n --palette-textInput: 0, 0, 0;\n --palette-textPrimary: 128, 128, 128;\n --palette-textLink: 0, 122, 255;\n --palette-buttonText: 255, 255, 255;\n --palette-textGray: 54, 54, 54;\n --palette-superTokensBrandingBackground: 242, 245, 246;\n --palette-superTokensBrandingText: 173, 189, 196;\n\n --font-size-0: 12px;\n --font-size-1: 14px;\n --font-size-2: 16px;\n --font-size-3: 19px;\n --font-size-4: 24px;\n --font-size-5: 28px;\n}\n/*\n * Default styles.\n */\n@keyframes slideTop {\n 0% {\n transform: translateY(-5px);\n }\n 100% {\n transform: translateY(0px);\n }\n}\n@keyframes swing-in-top-fwd {\n 0% {\n transform: rotateX(-100deg);\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n transform: rotateX(0deg);\n transform-origin: top;\n opacity: 1;\n }\n}\n[data-supertokens~="container"] {\n font-family: "Arial", sans-serif;\n margin: 12px auto;\n margin-top: 26px;\n margin-bottom: 26px;\n width: 420px;\n text-align: center;\n border-radius: 8px;\n box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.16);\n background-color: rgb(var(--palette-background));\n}\n@media (max-width: 440px) {\n [data-supertokens~="container"] {\n width: 95vw;\n }\n}\n[data-supertokens~="row"] {\n margin: 0 auto;\n width: 76%;\n padding-top: 30px;\n padding-bottom: 10px;\n}\n[data-supertokens~="superTokensBranding"] {\n display: block;\n margin: 10px auto 0;\n background: rgb(var(--palette-superTokensBrandingBackground));\n color: rgb(var(--palette-superTokensBrandingText));\n text-decoration: none;\n width: -webkit-fit-content;\n width: -moz-fit-content;\n width: fit-content;\n border-radius: 6px 6px 0 0;\n padding: 4px 9px;\n font-weight: 400;\n font-size: var(--font-size-0);\n letter-spacing: 0.4px;\n}\n[data-supertokens~="generalError"] {\n background: rgb(var(--palette-errorBackground));\n padding-top: 10px;\n padding-bottom: 10px;\n margin-bottom: 10px;\n margin-top: 24px;\n padding-left: 18px;\n padding-right: 18px;\n letter-spacing: 0.2px;\n font-size: var(--font-size-1);\n border-radius: 8px;\n color: rgb(var(--palette-error));\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n word-wrap: break-word;\n}\n[data-supertokens~="headerTitle"] {\n font-size: var(--font-size-4);\n line-height: 27.6px;\n letter-spacing: 0.58px;\n font-weight: 700;\n margin-bottom: 20px;\n color: rgb(var(--palette-textTitle));\n}\n[data-supertokens~="headerSubtitle"] {\n font-weight: 400;\n color: rgb(var(--palette-textGray));\n margin-bottom: 21px;\n}\n[data-supertokens~="headerSubtitle"][data-supertokens~="secondaryText"] {\n color: rgb(var(--palette-textGray));\n font-weight: 400;\n}\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] {\n max-width: 300px;\n margin-top: 10px;\n}\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] a {\n line-height: 21px;\n}\n/* TODO: split the link style into separate things*/\n/* We add this before primary and secondary text, because if they are applied to the same element the other ones take priority */\n[data-supertokens~="link"] {\n padding-left: 3px;\n padding-right: 3px;\n color: rgb(var(--palette-textLink));\n font-size: var(--font-size-1);\n cursor: pointer;\n letter-spacing: 0.16px;\n line-height: 26px;\n}\n[data-supertokens~="primaryText"] {\n font-size: var(--font-size-2);\n font-weight: 400;\n letter-spacing: 0.4px;\n line-height: 21px;\n color: rgb(var(--palette-textLabel));\n}\n[data-supertokens~="secondaryText"] {\n font-size: var(--font-size-1);\n font-weight: 400;\n letter-spacing: 0.4px;\n color: rgb(var(--palette-textPrimary));\n}\n[data-supertokens~="secondaryText"] strong {\n font-weight: 600;\n}\n[data-supertokens~="divider"] {\n margin-top: 1.5em;\n margin-bottom: 1.5em;\n border-bottom: 0.3px solid #dddddd;\n align-items: center;\n padding-bottom: 5px;\n flex: 3 3;\n}\n[data-supertokens~="headerTinyTitle"] {\n margin-top: 24px;\n font-size: var(--font-size-5);\n letter-spacing: 1.1px;\n font-weight: 700;\n line-height: 28px;\n}\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithArrow"]:hover {\n position: relative;\n left: 2px;\n word-spacing: 4px;\n}\n[data-supertokens~="generalSuccess"] {\n color: rgb(var(--palette-success));\n font-size: var(--font-size-1);\n background: rgb(var(--palette-successBackground));\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n padding: 9px 15px 9px 15px;\n border-radius: 6px;\n display: inline-block;\n}\n[data-supertokens~="spinner"] {\n width: 80px;\n height: auto;\n padding-top: 20px;\n padding-bottom: 40px;\n margin: 0 auto;\n}\n[data-supertokens~="error"] {\n color: rgb(var(--palette-error));\n}\n[data-supertokens~="linkButton"] {\n font-family: "Arial", sans-serif;\n background-color: transparent;\n border: 0;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"] {\n color: rgb(var(--palette-textGray));\n font-weight: 400;\n margin-top: 10px;\n margin-bottom: 40px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n margin-right: 0.3em;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"]:hover svg {\n position: relative;\n left: -4px;\n}\n[data-supertokens~="button"] {\n font-family: "Arial", sans-serif;\n background-color: rgb(var(--palette-primary));\n color: rgb(var(--palette-buttonText));\n width: 100%;\n height: 34px;\n font-weight: 600;\n border-width: 1px;\n border-style: solid;\n border-radius: 6px;\n border-color: rgb(var(--palette-primaryBorder));\n background-position: center;\n transition: all 0.4s;\n background-size: 12000%;\n cursor: pointer;\n}\n[data-supertokens~="button"]:disabled {\n border: none;\n cursor: no-drop;\n}\n[data-supertokens~="button"]:active {\n outline: none;\n transition: all 0s;\n background-size: 100%;\n filter: brightness(0.85);\n}\n[data-supertokens~="button"]:focus {\n outline: none;\n}\n[data-supertokens~="backButtonCommon"] {\n width: 16px;\n height: 13px;\n}\n[data-supertokens~="backButton"] {\n cursor: pointer;\n border: none;\n background-color: transparent;\n padding: 0px;\n}\n[data-supertokens~="backButtonPlaceholder"] {\n display: block;\n}\n[data-supertokens~="delayedRender"] {\n animation-duration: 0.1s;\n animation-name: animate-fade;\n animation-delay: 0.2s;\n animation-fill-mode: backwards;\n}\n@keyframes animate-fade {\n 0% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n}\n[data-supertokens~="footerLinkGroupVert"] {\n display: flex;\n flex-direction: column;\n margin-top: 10px;\n gap: 24px;\n}\n[data-supertokens~="footerLinkGroupVert"] > div {\n cursor: pointer;\n margin: 0;\n}\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryText"] {\n font-weight: 400;\n}\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n font-weight: 400;\n position: relative;\n left: -6px; /* half the width of the left arrow */\n}\n@media (max-width: 360px) {\n [data-supertokens~="footerLinkGroupVert"] {\n flex-direction: column;\n }\n [data-supertokens~="footerLinkGroupVert"] > div {\n margin: 0 auto;\n }\n}\n[data-supertokens~="footerLinkGroupVert"] div:only-child {\n margin-left: auto;\n margin-right: auto;\n margin-top: 14px;\n}\n[data-supertokens~="withBackButton"] {\n position: relative;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n[data-supertokens~="dividerWithOr"] {\n padding-top: 5px;\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n color: rgb(var(--palette-textPrimary));\n}\n[data-supertokens~="dividerText"] {\n flex: 1 1;\n font-weight: 400;\n font-size: var(--font-size-1);\n}\n[data-supertokens~="formLabelWithLinkWrapper"] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n[data-supertokens~="formLabelLinkBtn"] {\n width: auto;\n margin-top: 0;\n line-height: 24px;\n font-size: var(--font-size-0);\n}\n[data-supertokens~="formLabelLinkBtn"]:hover {\n text-decoration: underline;\n}\n[data-supertokens~="formLabelLinkBtn"]:disabled {\n color: rgb(var(--palette-textPrimary));\n cursor: default;\n text-decoration: none;\n}\n[data-supertokens~="authComponentList"] {\n padding-bottom: 20px;\n}\n[data-supertokens~="authPageTitleOAuthClient"] {\n color: rgb(var(--palette-textGray));\n font-size: var(--font-size-1);\n font-weight: 400;\n margin: 10px 0 25px;\n}\n[data-supertokens~="authPageTitleOAuthClientUrl"] {\n text-decoration: none;\n}\n[data-supertokens~="authPageTitleOAuthClientLogo"] {\n width: 44px;\n height: 44px;\n margin-bottom: 10px;\n}\n[data-supertokens~="authPageTitleOAuthClient"] [data-supertokens~="authPageTitleOAuthClientName"] {\n color: rgb(var(--palette-textTitle));\n}\n[data-supertokens~="buttonWithArrow"] {\n border-radius: 6px;\n border: 1px solid #d0d5dd;\n width: 100%;\n color: rgb(var(--palette-textGray));\n display: flex;\n justify-content: center;\n align-items: center;\n gap: 5px;\n margin: 24px 0;\n min-height: 48px;\n cursor: pointer;\n}\n[data-supertokens~="buttonWithArrow"]:hover {\n background-color: rgb(var(--palette-inputBackground));\n}\n[data-supertokens~="buttonWithArrow"] [data-supertokens~="secondaryText"] {\n font-weight: 700;\n font-size: var(--font-size-2);\n color: rgb(var(--palette-textGray));\n margin: 0;\n}\n[data-supertokens~="buttonWithArrow"]:hover [data-supertokens~="secondaryLinkWithRightArrow"] ~ svg {\n position: relative;\n left: 2px;\n}\n[data-supertokens~="buttonWithArrow"]:hover [data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n position: relative;\n left: -2px;\n}\n[data-supertokens~="buttonWithArrow"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n display: flex;\n align-items: center;\n}\n[data-supertokens~="providerContainer"] {\n padding-top: 9px;\n padding-bottom: 9px;\n\n --logo-size: 34px;\n --logo-horizontal-spacing: 8px;\n}\n[data-supertokens~="button"][data-supertokens~="providerButton"] {\n min-height: 32px;\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: center;\n padding: 2px calc(var(--logo-size) + 2 * var(--logo-horizontal-spacing));\n background-color: white;\n border-color: rgb(221, 221, 221);\n color: black;\n position: relative;\n}\n[data-supertokens~="button"][data-supertokens~="providerButton"]:hover {\n filter: none;\n background-color: #fafafa;\n}\n[data-supertokens~="providerButtonLeft"] {\n width: calc(var(--logo-size));\n position: absolute;\n left: calc(var(--logo-horizontal-spacing));\n}\n[data-supertokens~="providerButtonLogo"] {\n height: 30px;\n display: flex;\n align-items: center;\n}\n[data-supertokens~="providerButtonLogoCenter"] {\n display: flex;\n margin: auto;\n}\n[data-supertokens~="providerButtonText"] {\n font-weight: 400;\n text-align: center;\n justify-content: center;\n overflow: hidden;\n white-space: nowrap;\n display: inline-block;\n flex-grow: 1;\n max-width: 100%;\n font-size: var(--font-size-1);\n text-overflow: ellipsis;\n}\n.scroll-text-animation:hover span,\n.scroll-text-animation:focus span {\n display: inline-block;\n animation: scroll-left 2s linear forwards;\n position: relative;\n width: -webkit-fit-content;\n width: -moz-fit-content;\n width: fit-content;\n text-overflow: clip;\n}\n@keyframes scroll-left {\n 0% {\n transform: translateX(0);\n left: 0%;\n }\n 50% {\n transform: translateX(calc(-100% - 10px));\n left: 100%;\n }\n 100% {\n transform: translateX(calc(-100% - 10px));\n left: 100%;\n }\n}\n@media (max-width: 640px) {\n [data-supertokens~="providerButtonText"] {\n font-size: var(--font-size-0);\n }\n}\n';
var ThemeBase = function (_a) {
var children = _a.children,
@@ -101,6 +103,7 @@ var ThirdPartySignInAndUpProvidersForm = function (props) {
recipeImplementation: props.recipeImplementation,
thirdPartyId: providerId,
config: props.config,
+ shouldTryLinkingWithSessionUser: false,
userContext: userContext,
}),
];
@@ -189,7 +192,17 @@ var SignInAndUpThemeWrapper = function (props) {
);
};
-function useChildProps(recipe$1, error, onError, clearError, rebuildAuthPage, setFactorList, navigate, userContext) {
+function useChildProps(
+ recipe$1,
+ onAuthSuccess,
+ error,
+ onError,
+ clearError,
+ rebuildAuthPage,
+ setFactorList,
+ navigate,
+ userContext
+) {
var recipeImplementation = React.useMemo(
function () {
return recipe$1 && getModifiedRecipeImplementation(recipe$1.webJSRecipe);
@@ -210,6 +223,7 @@ function useChildProps(recipe$1, error, onError, clearError, rebuildAuthPage, se
}
}
return {
+ onAuthSuccess: onAuthSuccess,
error: error,
onError: onError,
clearError: clearError,
@@ -232,6 +246,7 @@ function useChildProps(recipe$1, error, onError, clearError, rebuildAuthPage, se
var SignInAndUpFeature = function (props) {
var childProps = useChildProps(
props.recipe,
+ props.onAuthSuccess,
props.error,
props.onError,
props.clearError,
@@ -407,7 +422,14 @@ var SignInAndUpCallback$1 = function (props) {
var response = _a.response,
payloadBeforeCall = _a.payloadBeforeCall;
return genericComponentOverrideContext.__awaiter(void 0, void 0, void 0, function () {
- var payloadAfterCall, stateResponse, redirectToPath;
+ var payloadAfterCall,
+ stateResponse,
+ redirectToPath,
+ loginChallenge,
+ ctx,
+ oauth2Recipe,
+ frontendRedirectTo,
+ e_1;
return genericComponentOverrideContext.__generator(this, function (_c) {
switch (_c.label) {
case 0:
@@ -438,7 +460,7 @@ var SignInAndUpCallback$1 = function (props) {
}),
];
}
- if (!(response.status === "OK")) return [3 /*break*/, 5];
+ if (!(response.status === "OK")) return [3 /*break*/, 10];
payloadAfterCall = void 0;
_c.label = 1;
case 1:
@@ -461,22 +483,63 @@ var SignInAndUpCallback$1 = function (props) {
userContext: userContext,
});
redirectToPath = stateResponse === undefined ? undefined : stateResponse.redirectToPath;
+ loginChallenge =
+ stateResponse === null || stateResponse === void 0
+ ? void 0
+ : stateResponse.oauth2LoginChallenge;
+ ctx = {
+ createdNewUser:
+ response.createdNewRecipeUser && response.user.loginMethods.length === 1,
+ isNewRecipeUser: response.createdNewRecipeUser,
+ newSessionCreated:
+ payloadAfterCall !== undefined &&
+ (payloadBeforeCall === undefined ||
+ payloadBeforeCall.sessionHandle !== payloadAfterCall.sessionHandle),
+ recipeId: props.recipe.recipeID,
+ tenantIdFromQueryParams: genericComponentOverrideContext.getTenantIdFromQueryParams(),
+ };
+ oauth2Recipe = recipe$1.OAuth2Provider.getInstance();
+ if (!(loginChallenge !== undefined && oauth2Recipe !== undefined)) return [3 /*break*/, 9];
+ _c.label = 5;
+ case 5:
+ _c.trys.push([5, 7, , 8]);
+ return [
+ 4 /*yield*/,
+ oauth2Recipe.webJSRecipe.getRedirectURLToContinueOAuthFlow({
+ loginChallenge: loginChallenge,
+ userContext: userContext,
+ }),
+ ];
+ case 6:
+ frontendRedirectTo = _c.sent().frontendRedirectTo;
+ return [
+ 2 /*return*/,
+ types.Session.getInstanceOrThrow().validateGlobalClaimsAndHandleSuccessRedirection(
+ genericComponentOverrideContext.__assign(
+ genericComponentOverrideContext.__assign({}, ctx),
+ { action: "SUCCESS_OAUTH2", frontendRedirectTo: frontendRedirectTo }
+ ),
+ props.recipe.recipeID,
+ redirectToPath,
+ userContext,
+ props.navigate
+ ),
+ ];
+ case 7:
+ e_1 = _c.sent();
+ rethrowInRender(e_1);
+ return [3 /*break*/, 8];
+ case 8:
+ return [3 /*break*/, 10];
+ case 9:
return [
2 /*return*/,
types.Session.getInstanceOrThrow()
.validateGlobalClaimsAndHandleSuccessRedirection(
- {
- action: "SUCCESS",
- createdNewUser:
- response.createdNewRecipeUser &&
- response.user.loginMethods.length === 1,
- isNewRecipeUser: response.createdNewRecipeUser,
- newSessionCreated:
- payloadAfterCall !== undefined &&
- (payloadBeforeCall === undefined ||
- payloadBeforeCall.sessionHandle !== payloadAfterCall.sessionHandle),
- recipeId: props.recipe.recipeID,
- },
+ genericComponentOverrideContext.__assign(
+ genericComponentOverrideContext.__assign({}, ctx),
+ { action: "SUCCESS" }
+ ),
props.recipe.recipeID,
redirectToPath,
userContext,
@@ -484,7 +547,7 @@ var SignInAndUpCallback$1 = function (props) {
)
.catch(rethrowInRender),
];
- case 5:
+ case 10:
return [2 /*return*/];
}
});
@@ -521,12 +584,14 @@ var SignInAndUpCallback$1 = function (props) {
_b.label = 2;
case 2:
_b.trys.push([2, 4, , 5]);
- evInstance = recipe$1.EmailVerification.getInstanceOrThrow();
+ evInstance = recipe$2.EmailVerification.getInstanceOrThrow();
return [
4 /*yield*/,
evInstance.redirect(
{
action: "VERIFY_EMAIL",
+ tenantIdFromQueryParams:
+ genericComponentOverrideContext.getTenantIdFromQueryParams(),
},
props.navigate,
undefined,
diff --git a/lib/build/totp.js b/lib/build/totp.js
index 12f9d30d9..05a5da4c6 100644
--- a/lib/build/totp.js
+++ b/lib/build/totp.js
@@ -21,6 +21,8 @@ require("supertokens-web-js/utils/sessionClaimValidatorStore");
require("./recipeModule-shared.js");
require("./multifactorauth-shared.js");
require("supertokens-web-js/recipe/session");
+require("./oauth2provider-shared.js");
+require("supertokens-web-js/recipe/oauth2provider");
/* Copyright (c) 2024, VRAI Labs and/or its affiliates. All rights reserved.
*
diff --git a/lib/build/totpprebuiltui.js b/lib/build/totpprebuiltui.js
index e14197492..52dda6640 100644
--- a/lib/build/totpprebuiltui.js
+++ b/lib/build/totpprebuiltui.js
@@ -23,12 +23,14 @@ require("supertokens-web-js/utils");
require("supertokens-web-js/utils/normalisedURLDomain");
require("react-dom");
require("./multitenancy-shared.js");
+require("./oauth2provider-shared.js");
+require("supertokens-web-js/recipe/oauth2provider");
+require("./recipeModule-shared.js");
require("./authRecipe-shared.js");
require("supertokens-web-js/lib/build/normalisedURLPath");
require("supertokens-web-js/recipe/session");
require("./session-shared.js");
require("supertokens-web-js/recipe/totp");
-require("./recipeModule-shared.js");
require("supertokens-web-js/recipe/multifactorauth");
require("supertokens-web-js/utils/sessionClaimValidatorStore");
require("./emailpassword-shared4.js");
@@ -69,7 +71,7 @@ var React__namespace = /*#__PURE__*/ _interopNamespace(React);
var STGeneralError__default = /*#__PURE__*/ _interopDefault(STGeneralError);
var styles =
- '[data-supertokens~="container"] {\n --palette-background: 255, 255, 255;\n --palette-inputBackground: 250, 250, 250;\n --palette-inputBorder: 224, 224, 224;\n --palette-primary: 28, 34, 42;\n --palette-primaryBorder: 45, 54, 68;\n --palette-success: 65, 167, 0;\n --palette-successBackground: 217, 255, 191;\n --palette-error: 255, 23, 23;\n --palette-errorBackground: 255, 241, 235;\n --palette-textTitle: 0, 0, 0;\n --palette-textLabel: 0, 0, 0;\n --palette-textInput: 0, 0, 0;\n --palette-textPrimary: 128, 128, 128;\n --palette-textLink: 0, 122, 255;\n --palette-buttonText: 255, 255, 255;\n --palette-textGray: 54, 54, 54;\n --palette-superTokensBrandingBackground: 242, 245, 246;\n --palette-superTokensBrandingText: 173, 189, 196;\n\n --font-size-0: 12px;\n --font-size-1: 14px;\n --font-size-2: 16px;\n --font-size-3: 19px;\n --font-size-4: 24px;\n --font-size-5: 28px;\n}\n/*\n * Default styles.\n */\n@keyframes slideTop {\n 0% {\n transform: translateY(-5px);\n }\n 100% {\n transform: translateY(0px);\n }\n}\n@keyframes swing-in-top-fwd {\n 0% {\n transform: rotateX(-100deg);\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n transform: rotateX(0deg);\n transform-origin: top;\n opacity: 1;\n }\n}\n[data-supertokens~="container"] {\n font-family: "Arial", sans-serif;\n margin: 12px auto;\n margin-top: 26px;\n margin-bottom: 26px;\n width: 420px;\n text-align: center;\n border-radius: 8px;\n box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.16);\n background-color: rgb(var(--palette-background));\n}\n@media (max-width: 440px) {\n [data-supertokens~="container"] {\n width: 95vw;\n }\n}\n[data-supertokens~="row"] {\n margin: 0 auto;\n width: 76%;\n padding-top: 30px;\n padding-bottom: 10px;\n}\n[data-supertokens~="superTokensBranding"] {\n display: block;\n margin: 10px auto 0;\n background: rgb(var(--palette-superTokensBrandingBackground));\n color: rgb(var(--palette-superTokensBrandingText));\n text-decoration: none;\n width: -webkit-fit-content;\n width: -moz-fit-content;\n width: fit-content;\n border-radius: 6px 6px 0 0;\n padding: 4px 9px;\n font-weight: 400;\n font-size: var(--font-size-0);\n letter-spacing: 0.4px;\n}\n[data-supertokens~="generalError"] {\n background: rgb(var(--palette-errorBackground));\n padding-top: 10px;\n padding-bottom: 10px;\n margin-bottom: 10px;\n margin-top: 24px;\n padding-left: 18px;\n padding-right: 18px;\n letter-spacing: 0.2px;\n font-size: var(--font-size-1);\n border-radius: 8px;\n color: rgb(var(--palette-error));\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n word-wrap: break-word;\n}\n[data-supertokens~="headerTitle"] {\n font-size: var(--font-size-4);\n line-height: 27.6px;\n letter-spacing: 0.58px;\n font-weight: 700;\n margin-bottom: 20px;\n color: rgb(var(--palette-textTitle));\n}\n[data-supertokens~="headerSubtitle"] {\n font-weight: 400;\n color: rgb(var(--palette-textGray));\n margin-bottom: 21px;\n}\n[data-supertokens~="headerSubtitle"][data-supertokens~="secondaryText"] {\n color: rgb(var(--palette-textGray));\n font-weight: 400;\n}\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] {\n max-width: 300px;\n margin-top: 10px;\n}\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] a {\n line-height: 21px;\n}\n/* TODO: split the link style into separate things*/\n/* We add this before primary and secondary text, because if they are applied to the same element the other ones take priority */\n[data-supertokens~="link"] {\n padding-left: 3px;\n padding-right: 3px;\n color: rgb(var(--palette-textLink));\n font-size: var(--font-size-1);\n cursor: pointer;\n letter-spacing: 0.16px;\n line-height: 26px;\n}\n[data-supertokens~="primaryText"] {\n font-size: var(--font-size-2);\n font-weight: 400;\n letter-spacing: 0.4px;\n line-height: 21px;\n color: rgb(var(--palette-textLabel));\n}\n[data-supertokens~="secondaryText"] {\n font-size: var(--font-size-1);\n font-weight: 400;\n letter-spacing: 0.4px;\n color: rgb(var(--palette-textPrimary));\n}\n[data-supertokens~="secondaryText"] strong {\n font-weight: 600;\n}\n[data-supertokens~="divider"] {\n margin-top: 1.5em;\n margin-bottom: 1.5em;\n border-bottom: 0.3px solid #dddddd;\n align-items: center;\n padding-bottom: 5px;\n flex: 3 3;\n}\n[data-supertokens~="headerTinyTitle"] {\n margin-top: 24px;\n font-size: var(--font-size-5);\n letter-spacing: 1.1px;\n font-weight: 700;\n line-height: 28px;\n}\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithArrow"]:hover {\n position: relative;\n left: 2px;\n word-spacing: 4px;\n}\n[data-supertokens~="generalSuccess"] {\n color: rgb(var(--palette-success));\n font-size: var(--font-size-1);\n background: rgb(var(--palette-successBackground));\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n padding: 9px 15px 9px 15px;\n border-radius: 6px;\n display: inline-block;\n}\n[data-supertokens~="spinner"] {\n width: 80px;\n height: auto;\n padding-top: 20px;\n padding-bottom: 40px;\n margin: 0 auto;\n}\n[data-supertokens~="error"] {\n color: rgb(var(--palette-error));\n}\n[data-supertokens~="linkButton"] {\n font-family: "Arial", sans-serif;\n background-color: transparent;\n border: 0;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"] {\n color: rgb(var(--palette-textGray));\n font-weight: 400;\n margin-top: 10px;\n margin-bottom: 40px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n margin-right: 0.3em;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"]:hover svg {\n position: relative;\n left: -4px;\n}\n[data-supertokens~="button"] {\n font-family: "Arial", sans-serif;\n background-color: rgb(var(--palette-primary));\n color: rgb(var(--palette-buttonText));\n width: 100%;\n height: 34px;\n font-weight: 600;\n border-width: 1px;\n border-style: solid;\n border-radius: 6px;\n border-color: rgb(var(--palette-primaryBorder));\n background-position: center;\n transition: all 0.4s;\n background-size: 12000%;\n cursor: pointer;\n}\n[data-supertokens~="button"]:disabled {\n border: none;\n cursor: no-drop;\n}\n[data-supertokens~="button"]:active {\n outline: none;\n transition: all 0s;\n background-size: 100%;\n filter: brightness(0.85);\n}\n[data-supertokens~="button"]:focus {\n outline: none;\n}\n[data-supertokens~="backButtonCommon"] {\n width: 16px;\n height: 13px;\n}\n[data-supertokens~="backButton"] {\n cursor: pointer;\n border: none;\n background-color: transparent;\n padding: 0px;\n}\n[data-supertokens~="backButtonPlaceholder"] {\n display: block;\n}\n[data-supertokens~="delayedRender"] {\n animation-duration: 0.1s;\n animation-name: animate-fade;\n animation-delay: 0.2s;\n animation-fill-mode: backwards;\n}\n@keyframes animate-fade {\n 0% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n}\n[data-supertokens~="footerLinkGroupVert"] {\n display: flex;\n flex-direction: column;\n margin-top: 10px;\n gap: 24px;\n}\n[data-supertokens~="footerLinkGroupVert"] > div {\n cursor: pointer;\n margin: 0;\n}\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryText"] {\n font-weight: 400;\n}\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n font-weight: 400;\n position: relative;\n left: -6px; /* half the width of the left arrow */\n}\n@media (max-width: 360px) {\n [data-supertokens~="footerLinkGroupVert"] {\n flex-direction: column;\n }\n [data-supertokens~="footerLinkGroupVert"] > div {\n margin: 0 auto;\n }\n}\n[data-supertokens~="footerLinkGroupVert"] div:only-child {\n margin-left: auto;\n margin-right: auto;\n margin-top: 14px;\n}\n[data-supertokens~="withBackButton"] {\n position: relative;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n[data-supertokens~="dividerWithOr"] {\n padding-top: 5px;\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n color: rgb(var(--palette-textPrimary));\n}\n[data-supertokens~="dividerText"] {\n flex: 1 1;\n font-weight: 400;\n font-size: var(--font-size-1);\n}\n[data-supertokens~="formLabelWithLinkWrapper"] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n[data-supertokens~="formLabelLinkBtn"] {\n width: auto;\n margin-top: 0;\n line-height: 24px;\n font-size: var(--font-size-0);\n}\n[data-supertokens~="formLabelLinkBtn"]:hover {\n text-decoration: underline;\n}\n[data-supertokens~="formLabelLinkBtn"]:disabled {\n color: rgb(var(--palette-textPrimary));\n cursor: default;\n text-decoration: none;\n}\n[data-supertokens~="authComponentList"] {\n padding-bottom: 20px;\n}\n[data-supertokens~="buttonWithArrow"] {\n border-radius: 6px;\n border: 1px solid #d0d5dd;\n width: 100%;\n color: rgb(var(--palette-textGray));\n display: flex;\n justify-content: center;\n align-items: center;\n gap: 5px;\n margin: 24px 0;\n min-height: 48px;\n cursor: pointer;\n}\n[data-supertokens~="buttonWithArrow"]:hover {\n background-color: rgb(var(--palette-inputBackground));\n}\n[data-supertokens~="buttonWithArrow"] [data-supertokens~="secondaryText"] {\n font-weight: 700;\n font-size: var(--font-size-2);\n color: rgb(var(--palette-textGray));\n margin: 0;\n}\n[data-supertokens~="buttonWithArrow"]:hover [data-supertokens~="secondaryLinkWithRightArrow"] ~ svg {\n position: relative;\n left: 2px;\n}\n[data-supertokens~="buttonWithArrow"]:hover [data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n position: relative;\n left: -2px;\n}\n[data-supertokens~="buttonWithArrow"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n display: flex;\n align-items: center;\n}\n/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved.\n *\n * This software is licensed under the Apache License, Version 2.0 (the\n * "License") as published by the Apache Software Foundation.\n *\n * You may not use this file except in compliance with the License. You may\n * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n[data-supertokens~="inputContainer"] {\n margin-top: 6px;\n}\n[data-supertokens~="inputWrapper"] {\n box-sizing: border-box;\n width: 100%;\n display: flex;\n align-items: center;\n background-color: rgb(var(--palette-inputBackground));\n height: 34px;\n border-radius: 6px;\n border: 1px solid rgb(var(--palette-inputBorder));\n}\n[data-supertokens~="inputWrapper"][focus-within] {\n background-color: rgba(var(--palette-inputBackground), 0.25);\n border: 1px solid rgb(var(--palette-primary));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-primary), 0.25);\n outline: none;\n}\n[data-supertokens~="inputWrapper"]:focus-within {\n background-color: rgba(var(--palette-inputBackground), 0.25);\n border: 1px solid rgb(var(--palette-primary));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-primary), 0.25);\n outline: none;\n}\n[data-supertokens~="inputError"] {\n border: 1px solid rgb(var(--palette-error));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-error), 0.25);\n outline: none;\n}\n[data-supertokens~="inputError"][focus-within] {\n border: 1px solid rgb(var(--palette-error));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-error), 0.25);\n outline: none;\n}\n[data-supertokens~="inputError"]:focus-within {\n border: 1px solid rgb(var(--palette-error));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-error), 0.25);\n outline: none;\n}\n[data-supertokens~="input"] {\n box-sizing: border-box;\n padding-left: 15px;\n filter: none;\n color: rgb(var(--palette-textInput));\n background-color: transparent;\n border-radius: 6px;\n font-size: var(--font-size-1);\n border: none;\n padding-right: 25px;\n letter-spacing: 1.2px;\n flex: 9 1 75%;\n width: 75%;\n height: 32px;\n}\n[data-supertokens~="input"]:focus {\n border: none;\n outline: none;\n}\n[data-supertokens~="input"]:-webkit-autofill,\n[data-supertokens~="input"]:-webkit-autofill:hover,\n[data-supertokens~="input"]:-webkit-autofill:focus,\n[data-supertokens~="input"]:-webkit-autofill:active {\n -webkit-text-fill-color: rgb(var(--palette-textInput));\n box-shadow: 0 0 0 30px rgb(var(--palette-inputBackground)) inset;\n}\n[data-supertokens~="inputAdornment"] {\n justify-content: center;\n margin-right: 5px;\n}\n[data-supertokens~="showPassword"] {\n cursor: pointer;\n}\n[data-supertokens~="enterEmailSuccessMessage"] {\n margin-top: 15px;\n margin-bottom: 15px;\n word-break: break-word;\n}\n[data-supertokens~="submitNewPasswordSuccessMessage"] {\n margin-top: 15px;\n margin-bottom: 15px;\n}\n[data-supertokens~="inputErrorMessage"] {\n padding-top: 5px;\n padding-bottom: 5px;\n color: rgb(var(--palette-error));\n line-height: 24px;\n font-weight: 400;\n font-size: var(--font-size-1);\n text-align: left;\n animation: slideTop 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;\n max-width: 330px;\n}\n@media (max-width: 440px) {\n [data-supertokens~="inputErrorMessage"] {\n max-width: 250px;\n }\n}\n[data-supertokens~="inputErrorSymbol"] {\n margin-right: 5px;\n top: 1px;\n position: relative;\n left: 2px;\n}\n[data-supertokens~="label"] {\n text-align: left;\n font-weight: 700;\n font-size: var(--font-size-0);\n line-height: 24px;\n color: rgb(var(--palette-textLabel));\n}\n[data-supertokens~="formRow"] {\n display: flex;\n flex-direction: column;\n padding-top: 0px;\n padding-bottom: 20px;\n}\n[data-supertokens~="formRow"][data-supertokens~="hasError"] {\n padding-bottom: 0;\n}\n[data-supertokens~="formRow"]:last-child {\n padding-bottom: 0;\n}\n[data-supertokens~="sendVerifyEmailIcon"] {\n margin-top: 11px;\n}\n[data-supertokens~="primaryText"][data-supertokens~="sendVerifyEmailText"] {\n text-align: center;\n letter-spacing: 0.8px;\n color: rgb(var(--palette-textPrimary));\n}\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n font-weight: 700;\n}\n[data-supertokens~="sendVerifyEmailResend"] {\n margin-top: 13px;\n font-weight: 400;\n}\n[data-supertokens~="sendVerifyEmailResend"]:hover {\n text-decoration: underline;\n}\n[data-supertokens~="noFormRow"] {\n padding-bottom: 25px;\n}\n[data-supertokens~="emailVerificationButtonWrapper"] {\n padding-top: 25px;\n max-width: 96px;\n margin: 0 auto;\n}\n[data-supertokens~="resendEmailLink"] {\n display: inline-block;\n}\n[data-supertokens~="resetPasswordEmailForm"] {\n padding-bottom: 20px;\n}\n[data-supertokens~="resetPasswordPasswordForm"] {\n padding-bottom: 20px;\n}\n[data-supertokens~="totp"] [data-supertokens~="container"] {\n padding-top: 24px;\n}\n[data-supertokens~="totp"] [data-supertokens~="divider"] {\n margin-top: 20px;\n margin-bottom: 20px;\n}\n[data-supertokens~="totp"] [data-supertokens~="row"] {\n padding-top: 16px;\n padding-bottom: 8px;\n width: auto;\n margin: 0 50px;\n}\n[data-supertokens~="totpDeviceQR"] {\n border-radius: 12px;\n border: 1px solid rgb(var(--palette-inputBorder));\n padding: 16px;\n max-width: 172px;\n max-height: 172px;\n}\n[data-supertokens~="showTOTPSecret"] {\n display: block;\n color: rgb(var(--palette-textGray));\n font-size: var(--font-size-0);\n margin: 16px 0 12px;\n}\n[data-supertokens~="totpSecret"] {\n display: block;\n border-radius: 6px;\n padding: 7px 15px;\n color: rgb(var(--palette-textLink));\n font-size: var(--font-size-1);\n font-weight: 600;\n letter-spacing: 3.36px;\n background: rgba(var(--palette-textLink), 0.08);\n word-wrap: break-word;\n overflow-y: hidden;\n}\nbutton[data-supertokens~="showTOTPSecretBtn"] {\n font-size: 12px;\n}\n[data-supertokens~="showTOTPSecretBtn"]:hover {\n text-decoration: underline;\n}\n[data-supertokens~="retryCodeBtn"]:disabled {\n border: 0;\n border-radius: 6px;\n color: rgb(var(--palette-error));\n background: rgb(var(--palette-errorBackground));\n}\n';
+ '[data-supertokens~="container"] {\n --palette-background: 255, 255, 255;\n --palette-inputBackground: 250, 250, 250;\n --palette-inputBorder: 224, 224, 224;\n --palette-primary: 28, 34, 42;\n --palette-primaryBorder: 45, 54, 68;\n --palette-success: 65, 167, 0;\n --palette-successBackground: 217, 255, 191;\n --palette-error: 255, 23, 23;\n --palette-errorBackground: 255, 241, 235;\n --palette-textTitle: 0, 0, 0;\n --palette-textLabel: 0, 0, 0;\n --palette-textInput: 0, 0, 0;\n --palette-textPrimary: 128, 128, 128;\n --palette-textLink: 0, 122, 255;\n --palette-buttonText: 255, 255, 255;\n --palette-textGray: 54, 54, 54;\n --palette-superTokensBrandingBackground: 242, 245, 246;\n --palette-superTokensBrandingText: 173, 189, 196;\n\n --font-size-0: 12px;\n --font-size-1: 14px;\n --font-size-2: 16px;\n --font-size-3: 19px;\n --font-size-4: 24px;\n --font-size-5: 28px;\n}\n/*\n * Default styles.\n */\n@keyframes slideTop {\n 0% {\n transform: translateY(-5px);\n }\n 100% {\n transform: translateY(0px);\n }\n}\n@keyframes swing-in-top-fwd {\n 0% {\n transform: rotateX(-100deg);\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n transform: rotateX(0deg);\n transform-origin: top;\n opacity: 1;\n }\n}\n[data-supertokens~="container"] {\n font-family: "Arial", sans-serif;\n margin: 12px auto;\n margin-top: 26px;\n margin-bottom: 26px;\n width: 420px;\n text-align: center;\n border-radius: 8px;\n box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.16);\n background-color: rgb(var(--palette-background));\n}\n@media (max-width: 440px) {\n [data-supertokens~="container"] {\n width: 95vw;\n }\n}\n[data-supertokens~="row"] {\n margin: 0 auto;\n width: 76%;\n padding-top: 30px;\n padding-bottom: 10px;\n}\n[data-supertokens~="superTokensBranding"] {\n display: block;\n margin: 10px auto 0;\n background: rgb(var(--palette-superTokensBrandingBackground));\n color: rgb(var(--palette-superTokensBrandingText));\n text-decoration: none;\n width: -webkit-fit-content;\n width: -moz-fit-content;\n width: fit-content;\n border-radius: 6px 6px 0 0;\n padding: 4px 9px;\n font-weight: 400;\n font-size: var(--font-size-0);\n letter-spacing: 0.4px;\n}\n[data-supertokens~="generalError"] {\n background: rgb(var(--palette-errorBackground));\n padding-top: 10px;\n padding-bottom: 10px;\n margin-bottom: 10px;\n margin-top: 24px;\n padding-left: 18px;\n padding-right: 18px;\n letter-spacing: 0.2px;\n font-size: var(--font-size-1);\n border-radius: 8px;\n color: rgb(var(--palette-error));\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n word-wrap: break-word;\n}\n[data-supertokens~="headerTitle"] {\n font-size: var(--font-size-4);\n line-height: 27.6px;\n letter-spacing: 0.58px;\n font-weight: 700;\n margin-bottom: 20px;\n color: rgb(var(--palette-textTitle));\n}\n[data-supertokens~="headerSubtitle"] {\n font-weight: 400;\n color: rgb(var(--palette-textGray));\n margin-bottom: 21px;\n}\n[data-supertokens~="headerSubtitle"][data-supertokens~="secondaryText"] {\n color: rgb(var(--palette-textGray));\n font-weight: 400;\n}\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] {\n max-width: 300px;\n margin-top: 10px;\n}\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] a {\n line-height: 21px;\n}\n/* TODO: split the link style into separate things*/\n/* We add this before primary and secondary text, because if they are applied to the same element the other ones take priority */\n[data-supertokens~="link"] {\n padding-left: 3px;\n padding-right: 3px;\n color: rgb(var(--palette-textLink));\n font-size: var(--font-size-1);\n cursor: pointer;\n letter-spacing: 0.16px;\n line-height: 26px;\n}\n[data-supertokens~="primaryText"] {\n font-size: var(--font-size-2);\n font-weight: 400;\n letter-spacing: 0.4px;\n line-height: 21px;\n color: rgb(var(--palette-textLabel));\n}\n[data-supertokens~="secondaryText"] {\n font-size: var(--font-size-1);\n font-weight: 400;\n letter-spacing: 0.4px;\n color: rgb(var(--palette-textPrimary));\n}\n[data-supertokens~="secondaryText"] strong {\n font-weight: 600;\n}\n[data-supertokens~="divider"] {\n margin-top: 1.5em;\n margin-bottom: 1.5em;\n border-bottom: 0.3px solid #dddddd;\n align-items: center;\n padding-bottom: 5px;\n flex: 3 3;\n}\n[data-supertokens~="headerTinyTitle"] {\n margin-top: 24px;\n font-size: var(--font-size-5);\n letter-spacing: 1.1px;\n font-weight: 700;\n line-height: 28px;\n}\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithArrow"]:hover {\n position: relative;\n left: 2px;\n word-spacing: 4px;\n}\n[data-supertokens~="generalSuccess"] {\n color: rgb(var(--palette-success));\n font-size: var(--font-size-1);\n background: rgb(var(--palette-successBackground));\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n padding: 9px 15px 9px 15px;\n border-radius: 6px;\n display: inline-block;\n}\n[data-supertokens~="spinner"] {\n width: 80px;\n height: auto;\n padding-top: 20px;\n padding-bottom: 40px;\n margin: 0 auto;\n}\n[data-supertokens~="error"] {\n color: rgb(var(--palette-error));\n}\n[data-supertokens~="linkButton"] {\n font-family: "Arial", sans-serif;\n background-color: transparent;\n border: 0;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"] {\n color: rgb(var(--palette-textGray));\n font-weight: 400;\n margin-top: 10px;\n margin-bottom: 40px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n margin-right: 0.3em;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"]:hover svg {\n position: relative;\n left: -4px;\n}\n[data-supertokens~="button"] {\n font-family: "Arial", sans-serif;\n background-color: rgb(var(--palette-primary));\n color: rgb(var(--palette-buttonText));\n width: 100%;\n height: 34px;\n font-weight: 600;\n border-width: 1px;\n border-style: solid;\n border-radius: 6px;\n border-color: rgb(var(--palette-primaryBorder));\n background-position: center;\n transition: all 0.4s;\n background-size: 12000%;\n cursor: pointer;\n}\n[data-supertokens~="button"]:disabled {\n border: none;\n cursor: no-drop;\n}\n[data-supertokens~="button"]:active {\n outline: none;\n transition: all 0s;\n background-size: 100%;\n filter: brightness(0.85);\n}\n[data-supertokens~="button"]:focus {\n outline: none;\n}\n[data-supertokens~="backButtonCommon"] {\n width: 16px;\n height: 13px;\n}\n[data-supertokens~="backButton"] {\n cursor: pointer;\n border: none;\n background-color: transparent;\n padding: 0px;\n}\n[data-supertokens~="backButtonPlaceholder"] {\n display: block;\n}\n[data-supertokens~="delayedRender"] {\n animation-duration: 0.1s;\n animation-name: animate-fade;\n animation-delay: 0.2s;\n animation-fill-mode: backwards;\n}\n@keyframes animate-fade {\n 0% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n}\n[data-supertokens~="footerLinkGroupVert"] {\n display: flex;\n flex-direction: column;\n margin-top: 10px;\n gap: 24px;\n}\n[data-supertokens~="footerLinkGroupVert"] > div {\n cursor: pointer;\n margin: 0;\n}\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryText"] {\n font-weight: 400;\n}\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n font-weight: 400;\n position: relative;\n left: -6px; /* half the width of the left arrow */\n}\n@media (max-width: 360px) {\n [data-supertokens~="footerLinkGroupVert"] {\n flex-direction: column;\n }\n [data-supertokens~="footerLinkGroupVert"] > div {\n margin: 0 auto;\n }\n}\n[data-supertokens~="footerLinkGroupVert"] div:only-child {\n margin-left: auto;\n margin-right: auto;\n margin-top: 14px;\n}\n[data-supertokens~="withBackButton"] {\n position: relative;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n[data-supertokens~="dividerWithOr"] {\n padding-top: 5px;\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n color: rgb(var(--palette-textPrimary));\n}\n[data-supertokens~="dividerText"] {\n flex: 1 1;\n font-weight: 400;\n font-size: var(--font-size-1);\n}\n[data-supertokens~="formLabelWithLinkWrapper"] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n[data-supertokens~="formLabelLinkBtn"] {\n width: auto;\n margin-top: 0;\n line-height: 24px;\n font-size: var(--font-size-0);\n}\n[data-supertokens~="formLabelLinkBtn"]:hover {\n text-decoration: underline;\n}\n[data-supertokens~="formLabelLinkBtn"]:disabled {\n color: rgb(var(--palette-textPrimary));\n cursor: default;\n text-decoration: none;\n}\n[data-supertokens~="authComponentList"] {\n padding-bottom: 20px;\n}\n[data-supertokens~="authPageTitleOAuthClient"] {\n color: rgb(var(--palette-textGray));\n font-size: var(--font-size-1);\n font-weight: 400;\n margin: 10px 0 25px;\n}\n[data-supertokens~="authPageTitleOAuthClientUrl"] {\n text-decoration: none;\n}\n[data-supertokens~="authPageTitleOAuthClientLogo"] {\n width: 44px;\n height: 44px;\n margin-bottom: 10px;\n}\n[data-supertokens~="authPageTitleOAuthClient"] [data-supertokens~="authPageTitleOAuthClientName"] {\n color: rgb(var(--palette-textTitle));\n}\n[data-supertokens~="buttonWithArrow"] {\n border-radius: 6px;\n border: 1px solid #d0d5dd;\n width: 100%;\n color: rgb(var(--palette-textGray));\n display: flex;\n justify-content: center;\n align-items: center;\n gap: 5px;\n margin: 24px 0;\n min-height: 48px;\n cursor: pointer;\n}\n[data-supertokens~="buttonWithArrow"]:hover {\n background-color: rgb(var(--palette-inputBackground));\n}\n[data-supertokens~="buttonWithArrow"] [data-supertokens~="secondaryText"] {\n font-weight: 700;\n font-size: var(--font-size-2);\n color: rgb(var(--palette-textGray));\n margin: 0;\n}\n[data-supertokens~="buttonWithArrow"]:hover [data-supertokens~="secondaryLinkWithRightArrow"] ~ svg {\n position: relative;\n left: 2px;\n}\n[data-supertokens~="buttonWithArrow"]:hover [data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n position: relative;\n left: -2px;\n}\n[data-supertokens~="buttonWithArrow"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n display: flex;\n align-items: center;\n}\n/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved.\n *\n * This software is licensed under the Apache License, Version 2.0 (the\n * "License") as published by the Apache Software Foundation.\n *\n * You may not use this file except in compliance with the License. You may\n * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n[data-supertokens~="inputContainer"] {\n margin-top: 6px;\n}\n[data-supertokens~="inputWrapper"] {\n box-sizing: border-box;\n width: 100%;\n display: flex;\n align-items: center;\n background-color: rgb(var(--palette-inputBackground));\n height: 34px;\n border-radius: 6px;\n border: 1px solid rgb(var(--palette-inputBorder));\n}\n[data-supertokens~="inputWrapper"][focus-within] {\n background-color: rgba(var(--palette-inputBackground), 0.25);\n border: 1px solid rgb(var(--palette-primary));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-primary), 0.25);\n outline: none;\n}\n[data-supertokens~="inputWrapper"]:focus-within {\n background-color: rgba(var(--palette-inputBackground), 0.25);\n border: 1px solid rgb(var(--palette-primary));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-primary), 0.25);\n outline: none;\n}\n[data-supertokens~="inputError"] {\n border: 1px solid rgb(var(--palette-error));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-error), 0.25);\n outline: none;\n}\n[data-supertokens~="inputError"][focus-within] {\n border: 1px solid rgb(var(--palette-error));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-error), 0.25);\n outline: none;\n}\n[data-supertokens~="inputError"]:focus-within {\n border: 1px solid rgb(var(--palette-error));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-error), 0.25);\n outline: none;\n}\n[data-supertokens~="input"] {\n box-sizing: border-box;\n padding-left: 15px;\n filter: none;\n color: rgb(var(--palette-textInput));\n background-color: transparent;\n border-radius: 6px;\n font-size: var(--font-size-1);\n border: none;\n padding-right: 25px;\n letter-spacing: 1.2px;\n flex: 9 1 75%;\n width: 75%;\n height: 32px;\n}\n[data-supertokens~="input"]:focus {\n border: none;\n outline: none;\n}\n[data-supertokens~="input"]:-webkit-autofill,\n[data-supertokens~="input"]:-webkit-autofill:hover,\n[data-supertokens~="input"]:-webkit-autofill:focus,\n[data-supertokens~="input"]:-webkit-autofill:active {\n -webkit-text-fill-color: rgb(var(--palette-textInput));\n box-shadow: 0 0 0 30px rgb(var(--palette-inputBackground)) inset;\n}\n[data-supertokens~="inputAdornment"] {\n justify-content: center;\n margin-right: 5px;\n}\n[data-supertokens~="showPassword"] {\n cursor: pointer;\n}\n[data-supertokens~="enterEmailSuccessMessage"] {\n margin-top: 15px;\n margin-bottom: 15px;\n word-break: break-word;\n}\n[data-supertokens~="submitNewPasswordSuccessMessage"] {\n margin-top: 15px;\n margin-bottom: 15px;\n}\n[data-supertokens~="inputErrorMessage"] {\n padding-top: 5px;\n padding-bottom: 5px;\n color: rgb(var(--palette-error));\n line-height: 24px;\n font-weight: 400;\n font-size: var(--font-size-1);\n text-align: left;\n animation: slideTop 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;\n max-width: 330px;\n}\n@media (max-width: 440px) {\n [data-supertokens~="inputErrorMessage"] {\n max-width: 250px;\n }\n}\n[data-supertokens~="inputErrorSymbol"] {\n margin-right: 5px;\n top: 1px;\n position: relative;\n left: 2px;\n}\n[data-supertokens~="label"] {\n text-align: left;\n font-weight: 700;\n font-size: var(--font-size-0);\n line-height: 24px;\n color: rgb(var(--palette-textLabel));\n}\n[data-supertokens~="formRow"] {\n display: flex;\n flex-direction: column;\n padding-top: 0px;\n padding-bottom: 20px;\n}\n[data-supertokens~="formRow"][data-supertokens~="hasError"] {\n padding-bottom: 0;\n}\n[data-supertokens~="formRow"]:last-child {\n padding-bottom: 0;\n}\n[data-supertokens~="sendVerifyEmailIcon"] {\n margin-top: 11px;\n}\n[data-supertokens~="primaryText"][data-supertokens~="sendVerifyEmailText"] {\n text-align: center;\n letter-spacing: 0.8px;\n color: rgb(var(--palette-textPrimary));\n}\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n font-weight: 700;\n}\n[data-supertokens~="sendVerifyEmailResend"] {\n margin-top: 13px;\n font-weight: 400;\n}\n[data-supertokens~="sendVerifyEmailResend"]:hover {\n text-decoration: underline;\n}\n[data-supertokens~="noFormRow"] {\n padding-bottom: 25px;\n}\n[data-supertokens~="emailVerificationButtonWrapper"] {\n padding-top: 25px;\n max-width: 96px;\n margin: 0 auto;\n}\n[data-supertokens~="resendEmailLink"] {\n display: inline-block;\n}\n[data-supertokens~="resetPasswordEmailForm"] {\n padding-bottom: 20px;\n}\n[data-supertokens~="resetPasswordPasswordForm"] {\n padding-bottom: 20px;\n}\n[data-supertokens~="totp"] [data-supertokens~="container"] {\n padding-top: 24px;\n}\n[data-supertokens~="totp"] [data-supertokens~="divider"] {\n margin-top: 20px;\n margin-bottom: 20px;\n}\n[data-supertokens~="totp"] [data-supertokens~="row"] {\n padding-top: 16px;\n padding-bottom: 8px;\n width: auto;\n margin: 0 50px;\n}\n[data-supertokens~="totpDeviceQR"] {\n border-radius: 12px;\n border: 1px solid rgb(var(--palette-inputBorder));\n padding: 16px;\n max-width: 172px;\n max-height: 172px;\n}\n[data-supertokens~="showTOTPSecret"] {\n display: block;\n color: rgb(var(--palette-textGray));\n font-size: var(--font-size-0);\n margin: 16px 0 12px;\n}\n[data-supertokens~="totpSecret"] {\n display: block;\n border-radius: 6px;\n padding: 7px 15px;\n color: rgb(var(--palette-textLink));\n font-size: var(--font-size-1);\n font-weight: 600;\n letter-spacing: 3.36px;\n background: rgba(var(--palette-textLink), 0.08);\n word-wrap: break-word;\n overflow-y: hidden;\n}\nbutton[data-supertokens~="showTOTPSecretBtn"] {\n font-size: 12px;\n}\n[data-supertokens~="showTOTPSecretBtn"]:hover {\n text-decoration: underline;\n}\n[data-supertokens~="retryCodeBtn"]:disabled {\n border: 0;\n border-radius: 6px;\n color: rgb(var(--palette-error));\n background: rgb(var(--palette-errorBackground));\n}\n';
var ThemeBase = function (_a) {
var children = _a.children,
diff --git a/lib/build/translation/translations.d.ts b/lib/build/translation/translations.d.ts
index ea5e1261c..24274f854 100644
--- a/lib/build/translation/translations.d.ts
+++ b/lib/build/translation/translations.d.ts
@@ -3,6 +3,7 @@ export declare const defaultTranslationsCommon: {
AUTH_PAGE_HEADER_TITLE_SIGN_IN_AND_UP: string;
AUTH_PAGE_HEADER_TITLE_SIGN_IN: string;
AUTH_PAGE_HEADER_TITLE_SIGN_UP: string;
+ AUTH_PAGE_HEADER_TITLE_SIGN_IN_UP_TO_APP: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_START: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_SIGN_UP_LINK: string;
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_END: string;
diff --git a/lib/build/types.d.ts b/lib/build/types.d.ts
index 07706a714..c7acea0bf 100644
--- a/lib/build/types.d.ts
+++ b/lib/build/types.d.ts
@@ -1,4 +1,5 @@
import type { DateProviderInput } from "./dateProvider/types";
+import type { AuthSuccessContext } from "./recipe/authRecipe/types";
import type { BaseRecipeModule } from "./recipe/recipeModule/baseRecipeModule";
import type { NormalisedConfig as NormalisedRecipeModuleConfig } from "./recipe/recipeModule/types";
import type { TranslationFunc, TranslationStore } from "./translation/translationHelpers";
@@ -9,7 +10,7 @@ import type { CookieHandlerInput } from "supertokens-web-js/utils/cookieHandler/
import type NormalisedURLDomain from "supertokens-web-js/utils/normalisedURLDomain";
import type NormalisedURLPath from "supertokens-web-js/utils/normalisedURLPath";
import type { WindowHandlerInput } from "supertokens-web-js/utils/windowHandler/types";
-export declare type SuccessRedirectContext = {
+declare type SuccessRedirectContextCommon = {
recipeId:
| "emailpassword"
| "thirdparty"
@@ -18,18 +19,26 @@ export declare type SuccessRedirectContext = {
| "thirdpartyemailpassword"
| "emailverification"
| "totp";
- action: "SUCCESS";
isNewRecipeUser: boolean;
createdNewUser: boolean;
newSessionCreated: boolean;
+};
+export declare type SuccessRedirectContextInApp = SuccessRedirectContextCommon & {
+ action: "SUCCESS";
redirectToPath?: string;
};
-export declare type GetRedirectionURLContext =
+export declare type SuccessRedirectContextOAuth2 = SuccessRedirectContextCommon & {
+ action: "SUCCESS_OAUTH2";
+ frontendRedirectTo: string;
+};
+export declare type SuccessRedirectContext = SuccessRedirectContextInApp | SuccessRedirectContextOAuth2;
+export declare type GetRedirectionURLContext = NormalisedGetRedirectionURLContext<
| {
action: "TO_AUTH";
showSignIn?: boolean;
}
- | SuccessRedirectContext;
+ | SuccessRedirectContextInApp
+>;
export declare type ValidationFailureCallback =
| (({
userContext,
@@ -66,7 +75,7 @@ export declare type SuperTokensConfig = {
};
enableDebugLogs?: boolean;
getRedirectionURL?: (
- context: GetRedirectionURLContext,
+ context: NormalisedGetRedirectionURLContext,
userContext: UserContext
) => Promise;
style?: string;
@@ -184,6 +193,7 @@ export declare type UserContext = Record;
export declare type AuthComponentProps = {
setFactorList: (factorIds: string[]) => void;
rebuildAuthPage: () => void;
+ onAuthSuccess: (successContext: AuthSuccessContext) => Promise;
navigate: Navigate | undefined;
userContext: UserContext;
error: string | undefined;
@@ -217,4 +227,7 @@ export declare type PartialAuthComponent = {
component: React.FC;
};
export declare type AuthComponent = PartialAuthComponent | FullPageAuthComponent;
+export declare type NormalisedGetRedirectionURLContext = RecipeContext & {
+ tenantIdFromQueryParams: string | undefined;
+};
export {};
diff --git a/lib/build/ui-entry.js b/lib/build/ui-entry.js
index 52083a79c..c91525c6e 100644
--- a/lib/build/ui-entry.js
+++ b/lib/build/ui-entry.js
@@ -23,6 +23,8 @@ require("supertokens-web-js/utils/sessionClaimValidatorStore");
require("./recipeModule-shared.js");
require("./multifactorauth-shared.js");
require("supertokens-web-js/recipe/session");
+require("./oauth2provider-shared.js");
+require("supertokens-web-js/recipe/oauth2provider");
require("./authRecipe-shared.js");
require("supertokens-web-js/lib/build/normalisedURLPath");
diff --git a/lib/build/ui/index.d.ts b/lib/build/ui/index.d.ts
index 3f69b71fd..9137df7c3 100644
--- a/lib/build/ui/index.d.ts
+++ b/lib/build/ui/index.d.ts
@@ -41,6 +41,13 @@ declare class UI {
onSignInUpSwitcherClick: (() => void) | undefined;
resetFactorList: () => void;
showBackButton: boolean;
+ oauth2ClientInfo?:
+ | {
+ logoUri?: string | undefined;
+ clientUri?: string | undefined;
+ clientName: string;
+ }
+ | undefined;
}>;
static AuthPageComponentList: React.ComponentType;
static AuthRecipeComponentsOverrideContextProvider: React.FC<
diff --git a/lib/build/ui/types.d.ts b/lib/build/ui/types.d.ts
index 794478b9c..4555c45d0 100644
--- a/lib/build/ui/types.d.ts
+++ b/lib/build/ui/types.d.ts
@@ -1,6 +1,7 @@
import type { EmailPasswordPreBuiltUI } from "../recipe/emailpassword/prebuiltui";
import type { EmailVerificationPreBuiltUI } from "../recipe/emailverification/prebuiltui";
import type { MultiFactorAuthPreBuiltUI } from "../recipe/multifactorauth/prebuiltui";
+import type { OAuth2ProviderPreBuiltUI } from "../recipe/oauth2provider/prebuiltui";
import type { PasswordlessPreBuiltUI } from "../recipe/passwordless/prebuiltui";
import type { SessionPreBuiltUI } from "../recipe/session/prebuiltui";
import type { ThirdPartyPreBuiltUI } from "../recipe/thirdparty/prebuiltui";
@@ -19,5 +20,6 @@ export declare type PreBuiltRecipes = (
| typeof EmailVerificationPreBuiltUI
| typeof MultiFactorAuthPreBuiltUI
| typeof TOTPPreBuiltUI
+ | typeof OAuth2ProviderPreBuiltUI
| typeof SessionPreBuiltUI
)[];
diff --git a/lib/build/utils.d.ts b/lib/build/utils.d.ts
index 7e87db5b9..9c63de8a9 100644
--- a/lib/build/utils.d.ts
+++ b/lib/build/utils.d.ts
@@ -8,6 +8,7 @@ import type {
Navigate,
NormalisedAppInfo,
NormalisedFormField,
+ NormalisedGetRedirectionURLContext,
UserContext,
} from "./types";
export declare function getRecipeIdFromSearch(search: string): string | null;
@@ -17,6 +18,15 @@ export declare function clearErrorQueryParam(): void;
export declare function getQueryParams(param: string): string | null;
export declare function getURLHash(): string;
export declare function getRedirectToPathFromURL(): string | undefined;
+export declare function getTenantIdFromQueryParams(): string | undefined;
+export declare function getDefaultRedirectionURLForPath(
+ config: {
+ appInfo: NormalisedAppInfo;
+ },
+ defaultPath: string,
+ context: NormalisedGetRedirectionURLContext,
+ extraQueryParams?: Record
+): string;
export declare function isTest(): boolean;
export declare function normaliseInputAppInfoOrThrowError(appInfo: AppInfoUserInput): NormalisedAppInfo;
export declare function validateForm(
diff --git a/lib/build/version.d.ts b/lib/build/version.d.ts
index 94509572d..f84ac887e 100644
--- a/lib/build/version.d.ts
+++ b/lib/build/version.d.ts
@@ -1 +1 @@
-export declare const package_version = "0.47.1";
+export declare const package_version = "0.49.0";
diff --git a/lib/ts/components/assets/logoutIcon.tsx b/lib/ts/components/assets/logoutIcon.tsx
new file mode 100644
index 000000000..d10c86f17
--- /dev/null
+++ b/lib/ts/components/assets/logoutIcon.tsx
@@ -0,0 +1,27 @@
+/* Copyright (c) 2024, VRAI Labs and/or its affiliates. All rights reserved.
+ *
+ * This software is licensed under the Apache License, Version 2.0 (the
+ * "License") as published by the Apache Software Foundation.
+ *
+ * You may not use this file except in compliance with the License. You may
+ * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+export default function LogoutIcon(): JSX.Element {
+ return (
+
+
+
+ );
+}
diff --git a/lib/ts/constants.ts b/lib/ts/constants.ts
index 3727b23b1..ab313489b 100644
--- a/lib/ts/constants.ts
+++ b/lib/ts/constants.ts
@@ -17,6 +17,7 @@
* Consts.
*/
export const RECIPE_ID_QUERY_PARAM = "rid";
+export const TENANT_ID_QUERY_PARAM = "tenantId";
export const DEFAULT_API_BASE_PATH = "/auth";
diff --git a/lib/ts/recipe/authRecipe/components/feature/authPage/authPage.tsx b/lib/ts/recipe/authRecipe/components/feature/authPage/authPage.tsx
index c15b11c1c..5b4e2fbb4 100644
--- a/lib/ts/recipe/authRecipe/components/feature/authPage/authPage.tsx
+++ b/lib/ts/recipe/authRecipe/components/feature/authPage/authPage.tsx
@@ -25,12 +25,21 @@ import SuperTokens from "../../../../../superTokens";
import { TranslationContextProvider } from "../../../../../translation/translationContext";
import { defaultTranslationsCommon } from "../../../../../translation/translations";
import { UserContextProvider, useUserContext } from "../../../../../usercontext";
-import { getRedirectToPathFromURL, mergeObjects, updateQueryParam, useRethrowInRender } from "../../../../../utils";
+import {
+ clearQueryParams,
+ getRedirectToPathFromURL,
+ getTenantIdFromQueryParams,
+ mergeObjects,
+ updateQueryParam,
+ useOnMountAPICall,
+ useRethrowInRender,
+} from "../../../../../utils";
import MultiFactorAuth from "../../../../multifactorauth/recipe";
import { FactorIds } from "../../../../multifactorauth/types";
import DynamicLoginMethodsSpinner from "../../../../multitenancy/components/features/dynamicLoginMethodsSpinner";
import { DynamicLoginMethodsProvider } from "../../../../multitenancy/dynamicLoginMethodsContext";
import Multitenancy from "../../../../multitenancy/recipe";
+import OAuth2Provider from "../../../../oauth2provider/recipe";
import Session from "../../../../session/recipe";
import SessionAuthWrapper from "../../../../session/sessionAuth";
import useSessionContext from "../../../../session/useSessionContext";
@@ -43,8 +52,9 @@ import type { TranslationStore } from "../../../../../translation/translationHel
import type { AuthComponent, Navigate, PartialAuthComponent, UserContext } from "../../../../../types";
import type { GetLoginMethodsResponseNormalized } from "../../../../multitenancy/types";
import type { RecipeRouter } from "../../../../recipeRouter";
-import type { AuthPageThemeProps } from "../../../types";
+import type { AuthPageThemeProps, AuthSuccessContext } from "../../../types";
import type { PropsWithChildren } from "react";
+import type { LoginInfo } from "supertokens-web-js/recipe/oauth2provider/types";
const errorQSMap: Record = {
signin: "SOMETHING_WENT_WRONG_ERROR",
@@ -102,6 +112,8 @@ const AuthPageInner: React.FC = (props) => {
const showStringFromQSRef = useRef(showStringFromQS);
const errorFromQSRef = useRef(errorFromQS);
+ const loginChallenge = search.get("loginChallenge");
+ const forceFreshAuth = search.get("forceFreshAuth") === "true";
const sessionContext = useSessionContext();
const userContext = useUserContext();
@@ -110,6 +122,7 @@ const AuthPageInner: React.FC = (props) => {
const [loadedDynamicLoginMethods, setLoadedDynamicLoginMethods] = useState<
GetLoginMethodsResponseNormalized | undefined
>(undefined);
+ const [oauth2ClientInfo, setOAuth2ClientInfo] = useState(undefined);
const [error, setError] = useState(errorFromQS);
const [sessionLoadedAndNotRedirecting, setSessionLoadedAndNotRedirecting] = useState(false);
const st = SuperTokens.getInstanceOrThrow();
@@ -163,6 +176,31 @@ const AuthPageInner: React.FC = (props) => {
);
}, [loadedDynamicLoginMethods, setLoadedDynamicLoginMethods]);
+ useOnMountAPICall(
+ async () => {
+ if (oauth2ClientInfo) {
+ return;
+ }
+ const oauth2Recipe = OAuth2Provider.getInstance();
+ if (oauth2Recipe !== undefined && loginChallenge !== null) {
+ return oauth2Recipe.webJSRecipe.getLoginChallengeInfo({ loginChallenge, userContext });
+ }
+ return undefined;
+ },
+ async (info) => {
+ if (info !== undefined) {
+ if (info.status === "OK") {
+ setOAuth2ClientInfo(info.info);
+ } else {
+ setError("SOMETHING_WENT_WRONG_ERROR");
+ }
+ }
+ },
+ () => {
+ return clearQueryParams(["loginChallenge"]);
+ }
+ );
+
useEffect(() => {
if (sessionLoadedAndNotRedirecting) {
return;
@@ -175,19 +213,48 @@ const AuthPageInner: React.FC = (props) => {
if (sessionContext.doesSessionExist) {
if (props.onSessionAlreadyExists !== undefined) {
props.onSessionAlreadyExists();
- } else if (props.redirectOnSessionExists !== false) {
+ } else if (props.redirectOnSessionExists !== false && !forceFreshAuth) {
Session.getInstanceOrThrow().config.onHandleEvent({
action: "SESSION_ALREADY_EXISTS",
});
- void Session.getInstanceOrThrow()
- .validateGlobalClaimsAndHandleSuccessRedirection(
- undefined,
- Session.RECIPE_ID, // TODO
- getRedirectToPathFromURL(),
- userContext,
- props.navigate
- )
- .catch(rethrowInRender);
+ const oauth2Recipe = OAuth2Provider.getInstance();
+ if (loginChallenge !== null && oauth2Recipe !== undefined) {
+ (async function () {
+ const { frontendRedirectTo } =
+ await oauth2Recipe.webJSRecipe.getRedirectURLToContinueOAuthFlow({
+ loginChallenge,
+ userContext,
+ });
+ return Session.getInstanceOrThrow().validateGlobalClaimsAndHandleSuccessRedirection(
+ {
+ // We get here if the user was redirected to the auth screen with an already existing session
+ // and a loginChallenge (we check the forceFreshAuth queryparam above)
+ action: "SUCCESS_OAUTH2",
+ frontendRedirectTo,
+ // We can use these defaults, since this is not the result of a sign in/up call
+ createdNewUser: false,
+ isNewRecipeUser: false,
+ newSessionCreated: false,
+ tenantIdFromQueryParams: getTenantIdFromQueryParams(),
+ recipeId: Session.RECIPE_ID,
+ },
+ Session.RECIPE_ID,
+ getRedirectToPathFromURL(),
+ userContext,
+ props.navigate
+ );
+ })().catch(rethrowInRender);
+ } else {
+ void Session.getInstanceOrThrow()
+ .validateGlobalClaimsAndHandleSuccessRedirection(
+ undefined,
+ Session.RECIPE_ID,
+ getRedirectToPathFromURL(),
+ userContext,
+ props.navigate
+ )
+ .catch(rethrowInRender);
+ }
} else {
setSessionLoadedAndNotRedirecting(true);
}
@@ -247,10 +314,50 @@ const AuthPageInner: React.FC = (props) => {
rethrowInRender,
]);
+ const onAuthSuccess = useCallback(
+ async (ctx: AuthSuccessContext) => {
+ const oauth2Recipe = OAuth2Provider.getInstance();
+ if (loginChallenge === null || oauth2Recipe === undefined) {
+ return Session.getInstanceOrThrow().validateGlobalClaimsAndHandleSuccessRedirection(
+ {
+ ...ctx,
+ action: "SUCCESS",
+ tenantIdFromQueryParams: getTenantIdFromQueryParams(),
+ redirectToPath: getRedirectToPathFromURL(),
+ },
+ ctx.recipeId,
+ getRedirectToPathFromURL(),
+ userContext,
+ props.navigate
+ );
+ }
+ const { frontendRedirectTo } = await oauth2Recipe.webJSRecipe.getRedirectURLToContinueOAuthFlow({
+ loginChallenge,
+ userContext,
+ });
+ return Session.getInstanceOrThrow().validateGlobalClaimsAndHandleSuccessRedirection(
+ {
+ ...ctx,
+ action: "SUCCESS_OAUTH2",
+ tenantIdFromQueryParams: getTenantIdFromQueryParams(),
+ frontendRedirectTo,
+ },
+ ctx.recipeId,
+ getRedirectToPathFromURL(),
+ userContext,
+ props.navigate
+ );
+ },
+ [loginChallenge]
+ );
+
const childProps: AuthPageThemeProps | undefined =
- authComponentListInfo !== undefined
+ authComponentListInfo !== undefined &&
+ (loginChallenge === null || oauth2ClientInfo !== undefined || OAuth2Provider.getInstance() === undefined)
? {
...authComponentListInfo,
+ oauth2ClientInfo,
+ onAuthSuccess,
error,
onError: (err) => {
setError(err);
diff --git a/lib/ts/recipe/authRecipe/components/theme/authPage/authPageHeader.tsx b/lib/ts/recipe/authRecipe/components/theme/authPage/authPageHeader.tsx
index 40c4cb375..29a681466 100644
--- a/lib/ts/recipe/authRecipe/components/theme/authPage/authPageHeader.tsx
+++ b/lib/ts/recipe/authRecipe/components/theme/authPage/authPageHeader.tsx
@@ -26,6 +26,7 @@ export const AuthPageHeader = withOverride(
isSignUp,
showBackButton,
resetFactorList,
+ oauth2ClientInfo,
}: {
factorIds: string[];
isSignUp: boolean;
@@ -33,11 +34,23 @@ export const AuthPageHeader = withOverride(
onSignInUpSwitcherClick: (() => void) | undefined;
resetFactorList: () => void;
showBackButton: boolean;
+ oauth2ClientInfo?: {
+ logoUri?: string;
+ clientUri?: string;
+ clientName: string;
+ };
}): JSX.Element {
const t = useTranslation();
return (
+ {oauth2ClientInfo?.logoUri && (
+
+ )}
{showBackButton ? (
@@ -55,6 +68,24 @@ export const AuthPageHeader = withOverride(
{/* empty span for spacing the back button */}
+ {oauth2ClientInfo &&
+ oauth2ClientInfo.clientName !== undefined &&
+ oauth2ClientInfo.clientName.length > 0 && (
+
+ {t("AUTH_PAGE_HEADER_TITLE_SIGN_IN_UP_TO_APP")}
+ {oauth2ClientInfo.clientUri !== undefined ? (
+
+ {oauth2ClientInfo.clientName}
+
+ ) : (
+
+ {oauth2ClientInfo.clientName}
+
+ )}
+
+ )}
{hasSeparateSignUpView &&
(!isSignUp ? (
diff --git a/lib/ts/recipe/authRecipe/components/theme/authPage/index.tsx b/lib/ts/recipe/authRecipe/components/theme/authPage/index.tsx
index cec9ccd85..88d937b38 100644
--- a/lib/ts/recipe/authRecipe/components/theme/authPage/index.tsx
+++ b/lib/ts/recipe/authRecipe/components/theme/authPage/index.tsx
@@ -50,6 +50,7 @@ export function AuthPageTheme(props: AuthPageThemeProps): JSX.Element {
hasSeparateSignUpView={props.hasSeparateSignUpView}
resetFactorList={props.resetFactorList}
showBackButton={props.showBackButton}
+ oauth2ClientInfo={props.oauth2ClientInfo}
/>
{props.error !== undefined &&
}
diff --git a/lib/ts/recipe/authRecipe/types.ts b/lib/ts/recipe/authRecipe/types.ts
index 92c47fcc5..e41837acd 100644
--- a/lib/ts/recipe/authRecipe/types.ts
+++ b/lib/ts/recipe/authRecipe/types.ts
@@ -17,7 +17,13 @@ import type { AuthPageComponentList } from "./components/theme/authPage/authPage
import type { AuthPageFooter } from "./components/theme/authPage/authPageFooter";
import type { AuthPageHeader } from "./components/theme/authPage/authPageHeader";
import type { ComponentOverride } from "../../components/componentOverride/componentOverride";
-import type { AuthComponentProps, Navigate, PartialAuthComponentProps, UserContext } from "../../types";
+import type {
+ AuthComponentProps,
+ Navigate,
+ PartialAuthComponentProps,
+ SuccessRedirectContext,
+ UserContext,
+} from "../../types";
import type {
Config as RecipeModuleConfig,
NormalisedConfig as NormalisedRecipeModuleConfig,
@@ -47,7 +53,19 @@ type ComponentWithPreloadInfo
= {
preloadInfo: T;
};
+export type AuthSuccessContext = Omit<
+ SuccessRedirectContext,
+ "redirectToPath" | "action" | "loginChallenge" | "recipeId"
+> & { recipeId: string };
+
export type AuthPageThemeProps = {
+ oauth2ClientInfo?: {
+ clientLogo?: string;
+ clientUri?: string;
+ clientName: string;
+ };
+ onAuthSuccess: (successContext: AuthSuccessContext) => Promise;
+
showBackButton: boolean;
setFactorList: (factorIds: string[]) => void;
resetFactorList: () => void;
diff --git a/lib/ts/recipe/emailpassword/components/features/signin/index.tsx b/lib/ts/recipe/emailpassword/components/features/signin/index.tsx
index 3a7a09119..23b768f50 100644
--- a/lib/ts/recipe/emailpassword/components/features/signin/index.tsx
+++ b/lib/ts/recipe/emailpassword/components/features/signin/index.tsx
@@ -23,16 +23,18 @@ import { useCallback } from "react";
import AuthComponentWrapper from "../../../../../components/authCompWrapper";
import { useTranslation } from "../../../../../translation/translationContext";
-import { getRedirectToPathFromURL, useRethrowInRender } from "../../../../../utils";
+import { getTenantIdFromQueryParams, useRethrowInRender } from "../../../../../utils";
import { EmailVerificationClaim } from "../../../../emailverification";
import EmailVerification from "../../../../emailverification/recipe";
import { getInvalidClaimsFromResponse } from "../../../../session";
import Session from "../../../../session/recipe";
import useSessionContext from "../../../../session/useSessionContext";
+import EmailPassword from "../../../recipe";
import { Label } from "../../library";
import SignInTheme from "../../themes/signIn";
import type { Navigate, UserContext, PartialAuthComponentProps } from "../../../../../types";
+import type { AuthSuccessContext } from "../../../../authRecipe/types";
import type Recipe from "../../../recipe";
import type { SignInThemeProps } from "../../../types";
import type { ComponentOverrideMap } from "../../../types";
@@ -40,6 +42,7 @@ import type { RecipeInterface } from "supertokens-web-js/recipe/emailpassword";
export function useChildProps(
recipe: Recipe,
+ onAuthSuccess: (successContext: AuthSuccessContext) => Promise,
error: string | undefined,
onError: (err: string) => void,
clearError: () => void,
@@ -61,30 +64,26 @@ export function useChildProps(
payloadAfterCall = undefined;
}
- return Session.getInstanceOrThrow()
- .validateGlobalClaimsAndHandleSuccessRedirection(
- {
- action: "SUCCESS",
- createdNewUser: false,
- isNewRecipeUser: false,
- newSessionCreated:
- session.loading ||
- !session.doesSessionExist ||
- (payloadAfterCall !== undefined &&
- session.accessTokenPayload.sessionHandle !== payloadAfterCall.sessionHandle),
- recipeId: recipe!.recipeID,
- },
- recipe!.recipeID,
- getRedirectToPathFromURL(),
- userContext,
- navigate
- )
- .catch(rethrowInRender);
+ return onAuthSuccess({
+ createdNewUser: false,
+ isNewRecipeUser: false,
+ newSessionCreated:
+ session.loading ||
+ !session.doesSessionExist ||
+ (payloadAfterCall !== undefined &&
+ session.accessTokenPayload.sessionHandle !== payloadAfterCall.sessionHandle),
+ recipeId: EmailPassword.RECIPE_ID,
+ }).catch(rethrowInRender);
}, [recipe, userContext, navigate]);
return useMemo(() => {
const onForgotPasswordClick = () =>
- recipe.redirect({ action: "RESET_PASSWORD" }, navigate, undefined, userContext);
+ recipe.redirect(
+ { action: "RESET_PASSWORD", tenantIdFromQueryParams: getTenantIdFromQueryParams() },
+ navigate,
+ undefined,
+ userContext
+ );
const signInAndUpFeature = recipe.config.signInAndUpFeature;
const signInFeature = signInAndUpFeature.signInForm;
@@ -124,6 +123,7 @@ export function useChildProps(
await evInstance.redirect(
{
action: "VERIFY_EMAIL",
+ tenantIdFromQueryParams: getTenantIdFromQueryParams(),
},
navigate,
undefined,
@@ -153,6 +153,7 @@ export const SignInFeature: React.FC<
> = (props) => {
const childProps = useChildProps(
props.recipe,
+ props.onAuthSuccess,
props.error,
props.onError,
props.clearError,
@@ -187,5 +188,13 @@ export default SignInFeature;
const getModifiedRecipeImplementation = (origImpl: RecipeInterface): RecipeInterface => {
return {
...origImpl,
+ signIn: async function (input) {
+ const response = await origImpl.signIn({ ...input, shouldTryLinkingWithSessionUser: false });
+ return response;
+ },
+ signUp: async function (input) {
+ const response = await origImpl.signUp({ ...input, shouldTryLinkingWithSessionUser: false });
+ return response;
+ },
};
};
diff --git a/lib/ts/recipe/emailpassword/components/features/signup/index.tsx b/lib/ts/recipe/emailpassword/components/features/signup/index.tsx
index 43f236a5b..aa0c27f19 100644
--- a/lib/ts/recipe/emailpassword/components/features/signup/index.tsx
+++ b/lib/ts/recipe/emailpassword/components/features/signup/index.tsx
@@ -24,7 +24,7 @@ import STGeneralError from "supertokens-web-js/utils/error";
import AuthComponentWrapper from "../../../../../components/authCompWrapper";
import { useUserContext } from "../../../../../usercontext";
-import { getRedirectToPathFromURL, useRethrowInRender } from "../../../../../utils";
+import { getTenantIdFromQueryParams, useRethrowInRender } from "../../../../../utils";
import { EmailVerificationClaim } from "../../../../emailverification";
import EmailVerification from "../../../../emailverification/recipe";
import { getInvalidClaimsFromResponse } from "../../../../session";
@@ -33,6 +33,7 @@ import useSessionContext from "../../../../session/useSessionContext";
import SignUpTheme from "../../themes/signUp";
import type { Navigate, NormalisedFormField, UserContext, PartialAuthComponentProps } from "../../../../../types";
+import type { AuthSuccessContext } from "../../../../authRecipe/types";
import type Recipe from "../../../recipe";
import type { SignUpThemeProps } from "../../../types";
import type { ComponentOverrideMap, FormFieldThemeProps } from "../../../types";
@@ -41,6 +42,7 @@ import type { User } from "supertokens-web-js/types";
export function useChildProps(
recipe: Recipe,
+ onAuthSuccess: (successContext: AuthSuccessContext) => Promise,
error: string | undefined,
onError: (err: string) => void,
clearError: () => void,
@@ -61,25 +63,16 @@ export function useChildProps(
} catch {
payloadAfterCall = undefined;
}
- return Session.getInstanceOrThrow()
- .validateGlobalClaimsAndHandleSuccessRedirection(
- {
- action: "SUCCESS",
- createdNewUser: result.user.loginMethods.length === 1,
- isNewRecipeUser: true,
- newSessionCreated:
- session.loading ||
- !session.doesSessionExist ||
- (payloadAfterCall !== undefined &&
- session.accessTokenPayload.sessionHandle !== payloadAfterCall.sessionHandle),
- recipeId: recipe!.recipeID,
- },
- recipe!.recipeID,
- getRedirectToPathFromURL(),
- userContext,
- navigate
- )
- .catch(rethrowInRender);
+ return onAuthSuccess({
+ createdNewUser: result.user.loginMethods.length === 1,
+ isNewRecipeUser: true,
+ newSessionCreated:
+ session.loading ||
+ !session.doesSessionExist ||
+ (payloadAfterCall !== undefined &&
+ session.accessTokenPayload.sessionHandle !== payloadAfterCall.sessionHandle),
+ recipeId: recipe!.recipeID,
+ }).catch(rethrowInRender);
},
[recipe, userContext, navigate]
);
@@ -103,6 +96,7 @@ export function useChildProps(
await evInstance.redirect(
{
action: "VERIFY_EMAIL",
+ tenantIdFromQueryParams: getTenantIdFromQueryParams(),
},
navigate,
undefined,
@@ -138,6 +132,7 @@ export const SignUpFeature: React.FC<
}
const childProps = useChildProps(
props.recipe,
+ props.onAuthSuccess,
props.error,
props.onError,
props.clearError,
@@ -172,6 +167,14 @@ export default SignUpFeature;
const getModifiedRecipeImplementation = (origImpl: RecipeInterface): RecipeInterface => {
return {
...origImpl,
+ signIn: async function (input) {
+ const response = await origImpl.signIn({ ...input, shouldTryLinkingWithSessionUser: false });
+ return response;
+ },
+ signUp: async function (input) {
+ const response = await origImpl.signUp({ ...input, shouldTryLinkingWithSessionUser: false });
+ return response;
+ },
};
};
diff --git a/lib/ts/recipe/emailpassword/components/themes/signIn/index.tsx b/lib/ts/recipe/emailpassword/components/themes/signIn/index.tsx
index 298a8d394..61d66b8ec 100644
--- a/lib/ts/recipe/emailpassword/components/themes/signIn/index.tsx
+++ b/lib/ts/recipe/emailpassword/components/themes/signIn/index.tsx
@@ -57,6 +57,7 @@ export const SignInForm = withOverride(
const response = await props.recipeImplementation.signIn({
formFields,
+ shouldTryLinkingWithSessionUser: false,
userContext,
});
if (response.status === "WRONG_CREDENTIALS_ERROR") {
diff --git a/lib/ts/recipe/emailpassword/components/themes/signUp/index.tsx b/lib/ts/recipe/emailpassword/components/themes/signUp/index.tsx
index 9e796e0c4..d07c5c8b5 100644
--- a/lib/ts/recipe/emailpassword/components/themes/signUp/index.tsx
+++ b/lib/ts/recipe/emailpassword/components/themes/signUp/index.tsx
@@ -57,6 +57,7 @@ export const SignUpForm = withOverride(
const res = await props.recipeImplementation.signUp({
formFields,
+ shouldTryLinkingWithSessionUser: false,
userContext,
});
diff --git a/lib/ts/recipe/emailpassword/index.ts b/lib/ts/recipe/emailpassword/index.ts
index e601cf2ba..52957243b 100644
--- a/lib/ts/recipe/emailpassword/index.ts
+++ b/lib/ts/recipe/emailpassword/index.ts
@@ -100,6 +100,7 @@ export default class Wrapper {
id: string;
value: string;
}[];
+ shouldTryLinkingWithSessionUser?: boolean;
options?: RecipeFunctionOptions;
userContext?: UserContext;
}): Promise<
@@ -133,6 +134,7 @@ export default class Wrapper {
id: string;
value: string;
}[];
+ shouldTryLinkingWithSessionUser?: boolean;
options?: RecipeFunctionOptions;
userContext?: UserContext;
}): Promise<
diff --git a/lib/ts/recipe/emailpassword/recipe.tsx b/lib/ts/recipe/emailpassword/recipe.tsx
index e0f05a2ad..367b0186b 100644
--- a/lib/ts/recipe/emailpassword/recipe.tsx
+++ b/lib/ts/recipe/emailpassword/recipe.tsx
@@ -18,10 +18,9 @@
*/
import EmailPasswordWebJS from "supertokens-web-js/recipe/emailpassword";
-import NormalisedURLPath from "supertokens-web-js/utils/normalisedURLPath";
import { SSR_ERROR } from "../../constants";
-import { isTest } from "../../utils";
+import { getDefaultRedirectionURLForPath, isTest } from "../../utils";
import AuthRecipe from "../authRecipe";
import { FactorIds } from "../multifactorauth/types";
@@ -50,7 +49,7 @@ export default class EmailPassword extends AuthRecipe<
NormalisedConfig
> {
static instance?: EmailPassword;
- static RECIPE_ID = "emailpassword";
+ static RECIPE_ID = "emailpassword" as const;
recipeID = EmailPassword.RECIPE_ID;
firstFactorIds = [FactorIds.EMAILPASSWORD];
@@ -63,15 +62,11 @@ export default class EmailPassword extends AuthRecipe<
public readonly webJSRecipe: WebJSRecipeInterface = EmailPasswordWebJS
) {
super(config);
- this.recipeID = config.recipeId;
}
getDefaultRedirectionURL = async (context: GetRedirectionURLContext): Promise => {
if (context.action === "RESET_PASSWORD") {
- const resetPasswordPath = new NormalisedURLPath(DEFAULT_RESET_PASSWORD_PATH);
- return `${this.config.appInfo.websiteBasePath.appendPath(resetPasswordPath).getAsStringDangerous()}?rid=${
- this.config.recipeId
- }`;
+ return getDefaultRedirectionURLForPath(this.config, DEFAULT_RESET_PASSWORD_PATH, context);
}
return this.getAuthRecipeDefaultRedirectionURL(context);
diff --git a/lib/ts/recipe/emailpassword/types.ts b/lib/ts/recipe/emailpassword/types.ts
index e67ea3d86..b30f27e3f 100644
--- a/lib/ts/recipe/emailpassword/types.ts
+++ b/lib/ts/recipe/emailpassword/types.ts
@@ -26,6 +26,7 @@ import type {
FormFieldBaseConfig,
NormalisedBaseConfig,
NormalisedFormField,
+ NormalisedGetRedirectionURLContext,
ThemeBaseProps,
UserContext,
} from "../../types";
@@ -265,12 +266,12 @@ export type PreAPIHookContext = {
userContext: UserContext;
};
-export type GetRedirectionURLContext = {
+export type GetRedirectionURLContext = NormalisedGetRedirectionURLContext<{
/*
* Get Redirection URL Context
*/
action: "RESET_PASSWORD";
-};
+}>;
export type OnHandleEventContext =
| AuthRecipeModuleOnHandleEventContext
diff --git a/lib/ts/recipe/emailverification/emailVerificationClaim.ts b/lib/ts/recipe/emailverification/emailVerificationClaim.ts
index dd68daa42..550cf0dff 100644
--- a/lib/ts/recipe/emailverification/emailVerificationClaim.ts
+++ b/lib/ts/recipe/emailverification/emailVerificationClaim.ts
@@ -1,5 +1,7 @@
import { EmailVerificationClaimClass as EmailVerificationClaimClassWebJS } from "supertokens-web-js/recipe/emailverification";
+import { getTenantIdFromQueryParams } from "../../utils";
+
import EmailVerification from "./recipe";
import type { UserContext, ValidationFailureCallback } from "../../types";
@@ -24,7 +26,10 @@ export class EmailVerificationClaimClass extends EmailVerificationClaimClassWebJ
}
const recipe = EmailVerification.getInstanceOrThrow();
if (recipe.config.mode === "REQUIRED") {
- return recipe.getRedirectUrl({ action: "VERIFY_EMAIL" }, args.userContext);
+ return recipe.getRedirectUrl(
+ { action: "VERIFY_EMAIL", tenantIdFromQueryParams: getTenantIdFromQueryParams() },
+ args.userContext
+ );
}
return undefined;
},
diff --git a/lib/ts/recipe/emailverification/recipe.tsx b/lib/ts/recipe/emailverification/recipe.tsx
index bb2cbcb42..07a1f2e89 100644
--- a/lib/ts/recipe/emailverification/recipe.tsx
+++ b/lib/ts/recipe/emailverification/recipe.tsx
@@ -18,12 +18,11 @@
*/
import EmailVerificationWebJS from "supertokens-web-js/recipe/emailverification";
-import NormalisedURLPath from "supertokens-web-js/utils/normalisedURLPath";
import { PostSuperTokensInitCallbacks } from "supertokens-web-js/utils/postSuperTokensInitCallbacks";
import { SessionClaimValidatorStore } from "supertokens-web-js/utils/sessionClaimValidatorStore";
import { SSR_ERROR } from "../../constants";
-import { isTest } from "../../utils";
+import { getDefaultRedirectionURLForPath, isTest } from "../../utils";
import RecipeModule from "../recipeModule";
import { DEFAULT_VERIFY_EMAIL_PATH } from "./constants";
@@ -135,10 +134,7 @@ export default class EmailVerification extends RecipeModule<
getDefaultRedirectionURL = async (context: GetRedirectionURLContext): Promise => {
if (context.action === "VERIFY_EMAIL") {
- const verifyEmailPath = new NormalisedURLPath(DEFAULT_VERIFY_EMAIL_PATH);
- return `${this.config.appInfo.websiteBasePath.appendPath(verifyEmailPath).getAsStringDangerous()}?rid=${
- this.config.recipeId
- }`;
+ return getDefaultRedirectionURLForPath(this.config, DEFAULT_VERIFY_EMAIL_PATH, context);
} else {
return "/";
}
diff --git a/lib/ts/recipe/emailverification/types.ts b/lib/ts/recipe/emailverification/types.ts
index 224449991..01f3fba7b 100644
--- a/lib/ts/recipe/emailverification/types.ts
+++ b/lib/ts/recipe/emailverification/types.ts
@@ -15,7 +15,7 @@
import type { SendVerifyEmail } from "./components/themes/emailVerification/sendVerifyEmail";
import type { VerifyEmailLinkClicked } from "./components/themes/emailVerification/verifyEmailLinkClicked";
import type { ComponentOverride } from "../../components/componentOverride/componentOverride";
-import type { FeatureBaseConfig, ThemeBaseProps, UserContext } from "../../types";
+import type { FeatureBaseConfig, NormalisedGetRedirectionURLContext, ThemeBaseProps, UserContext } from "../../types";
import type {
Config as RecipeModuleConfig,
NormalisedConfig as NormalisedRecipeModuleConfig,
@@ -61,9 +61,9 @@ export type NormalisedConfig = {
};
} & NormalisedRecipeModuleConfig;
-export type GetRedirectionURLContext = {
+export type GetRedirectionURLContext = NormalisedGetRedirectionURLContext<{
action: "VERIFY_EMAIL";
-};
+}>;
export type PreAndPostAPIHookAction = "VERIFY_EMAIL" | "SEND_VERIFY_EMAIL" | "IS_EMAIL_VERIFIED";
diff --git a/lib/ts/recipe/multifactorauth/recipe.tsx b/lib/ts/recipe/multifactorauth/recipe.tsx
index 9d6ef7dcd..d7fd8f0d0 100644
--- a/lib/ts/recipe/multifactorauth/recipe.tsx
+++ b/lib/ts/recipe/multifactorauth/recipe.tsx
@@ -19,7 +19,6 @@
import MultiFactorAuthWebJS from "supertokens-web-js/recipe/multifactorauth";
import { getNormalisedUserContext } from "supertokens-web-js/utils";
-import NormalisedURLPath from "supertokens-web-js/utils/normalisedURLPath";
import { PostSuperTokensInitCallbacks } from "supertokens-web-js/utils/postSuperTokensInitCallbacks";
import { SessionClaimValidatorStore } from "supertokens-web-js/utils/sessionClaimValidatorStore";
import { WindowHandlerReference } from "supertokens-web-js/utils/windowHandler";
@@ -29,7 +28,9 @@ import SuperTokens from "../../superTokens";
import {
appendQueryParamsToURL,
getCurrentNormalisedUrlPathWithQueryParamsAndFragments,
+ getDefaultRedirectionURLForPath,
getRedirectToPathFromURL,
+ getTenantIdFromQueryParams,
isTest,
} from "../../utils";
import RecipeModule from "../recipeModule";
@@ -69,7 +70,10 @@ export default class MultiFactorAuth extends RecipeModule<
static MultiFactorAuthClaim = new MultiFactorAuthClaimClass(
() => MultiFactorAuth.getInstanceOrThrow(),
async (context, userContext) =>
- (await this.getInstanceOrThrow().getRedirectUrl(context, userContext)) || undefined
+ (await this.getInstanceOrThrow().getRedirectUrl(
+ { ...context, tenantIdFromQueryParams: getTenantIdFromQueryParams() },
+ userContext
+ )) || undefined
);
public recipeID = MultiFactorAuth.RECIPE_ID;
@@ -149,36 +153,22 @@ export default class MultiFactorAuth extends RecipeModule<
getDefaultRedirectionURL = async (context: GetRedirectionURLContext, userContext: UserContext): Promise => {
if (context.action === "FACTOR_CHOOSER") {
- const chooserPath = new NormalisedURLPath(DEFAULT_FACTOR_CHOOSER_PATH);
- let url = this.config.appInfo.websiteBasePath.appendPath(chooserPath).getAsStringDangerous();
- const queryParams = new URLSearchParams();
- if (context.nextFactorOptions && context.nextFactorOptions.length > 0) {
- queryParams.set("n", context.nextFactorOptions.join(","));
- }
- if (context.stepUp) {
- queryParams.set("stepUp", "true");
- }
- if (queryParams.toString() !== "") {
- url += "?" + queryParams.toString();
- }
- return url;
+ const nParam =
+ context.nextFactorOptions && context.nextFactorOptions.length > 0
+ ? context.nextFactorOptions.join(",")
+ : undefined;
+
+ return getDefaultRedirectionURLForPath(this.config, DEFAULT_FACTOR_CHOOSER_PATH, context, {
+ n: nParam,
+ stepUp: context.stepUp ? "true" : undefined,
+ });
} else if (context.action === "GO_TO_FACTOR") {
const redirectInfo = this.getSecondaryFactors(userContext).find((f) => f.id === context.factorId);
if (redirectInfo !== undefined) {
- let url = this.config.appInfo.websiteBasePath
- .appendPath(new NormalisedURLPath(redirectInfo.path))
- .getAsStringDangerous();
- const queryParams = new URLSearchParams();
- if (context.forceSetup) {
- queryParams.set("setup", "true");
- }
- if (context.stepUp) {
- queryParams.set("stepUp", "true");
- }
- if (queryParams.toString() !== "") {
- url += "?" + queryParams.toString();
- }
- return url;
+ return getDefaultRedirectionURLForPath(this.config, redirectInfo.path, context, {
+ setup: context.forceSetup ? "true" : undefined,
+ stepUp: context.stepUp ? "true" : undefined,
+ });
}
throw new Error("Requested redirect to unknown factor id: " + context.factorId);
} else {
@@ -219,7 +209,13 @@ export default class MultiFactorAuth extends RecipeModule<
userContext: UserContext | undefined;
}) {
let url = await this.getRedirectUrl(
- { action: "GO_TO_FACTOR", forceSetup, stepUp, factorId },
+ {
+ action: "GO_TO_FACTOR",
+ forceSetup,
+ stepUp,
+ factorId,
+ tenantIdFromQueryParams: getTenantIdFromQueryParams(),
+ },
getNormalisedUserContext(userContext)
);
if (url === null) {
@@ -262,7 +258,12 @@ export default class MultiFactorAuth extends RecipeModule<
userContext: UserContext | undefined;
}) {
let url = await this.getRedirectUrl(
- { action: "FACTOR_CHOOSER", nextFactorOptions, stepUp },
+ {
+ action: "FACTOR_CHOOSER",
+ nextFactorOptions,
+ stepUp,
+ tenantIdFromQueryParams: getTenantIdFromQueryParams(),
+ },
getNormalisedUserContext(userContext)
);
diff --git a/lib/ts/recipe/multifactorauth/types.ts b/lib/ts/recipe/multifactorauth/types.ts
index fbcc75693..6dc4b24eb 100644
--- a/lib/ts/recipe/multifactorauth/types.ts
+++ b/lib/ts/recipe/multifactorauth/types.ts
@@ -18,7 +18,7 @@ import type { FactorChooserHeader } from "./components/themes/factorChooser/fact
import type { FactorList } from "./components/themes/factorChooser/factorList";
import type { FactorOption } from "./components/themes/factorChooser/factorOption";
import type { ComponentOverride } from "../../components/componentOverride/componentOverride";
-import type { FeatureBaseConfig, UserContext } from "../../types";
+import type { FeatureBaseConfig, NormalisedGetRedirectionURLContext, UserContext } from "../../types";
import type {
Config as RecipeModuleConfig,
NormalisedConfig as NormalisedRecipeModuleConfig,
@@ -75,7 +75,7 @@ export type NormalisedConfig = {
};
} & NormalisedRecipeModuleConfig;
-export type GetRedirectionURLContext =
+export type GetRedirectionURLContext = NormalisedGetRedirectionURLContext<
| {
action: "FACTOR_CHOOSER";
nextFactorOptions?: string[];
@@ -86,7 +86,8 @@ export type GetRedirectionURLContext =
factorId: string;
forceSetup?: boolean;
stepUp?: boolean;
- };
+ }
+>;
export type PreAndPostAPIHookAction = "GET_MFA_INFO";
diff --git a/lib/ts/recipe/multifactorauth/utils.ts b/lib/ts/recipe/multifactorauth/utils.ts
index 2e276e42e..fb1934d29 100644
--- a/lib/ts/recipe/multifactorauth/utils.ts
+++ b/lib/ts/recipe/multifactorauth/utils.ts
@@ -13,6 +13,7 @@
* under the License.
*/
+import { logDebugMessage } from "../../logger";
import { normaliseRecipeModuleConfig } from "../recipeModule/utils";
import type MultiFactorAuth from "./recipe";
@@ -48,6 +49,14 @@ export function getAvailableFactors(
recipe: MultiFactorAuth,
userContext: UserContext
) {
+ logDebugMessage(`getAvailableFactors: allowed to setup: ${factors.allowedToSetup}`);
+ logDebugMessage(`getAvailableFactors: already setup: ${factors.alreadySetup}`);
+ logDebugMessage(`getAvailableFactors: next from factorInfo: ${factors.next}`);
+ logDebugMessage(`getAvailableFactors: nextArrayQueryParam: ${nextArrayQueryParam}`);
+ logDebugMessage(
+ `getAvailableFactors: secondary factors: ${recipe.getSecondaryFactors(userContext).map((f) => f.id)}`
+ );
+
// There are 3 cases here:
// 1. The app provided an array of factors to show (nextArrayQueryParam) -> we show whatever is in the array
// 2. no app provided list and validator passed -> we show all factors available to set up or complete
diff --git a/lib/ts/recipe/oauth2provider/componentOverrideContext.tsx b/lib/ts/recipe/oauth2provider/componentOverrideContext.tsx
new file mode 100644
index 000000000..467bd5485
--- /dev/null
+++ b/lib/ts/recipe/oauth2provider/componentOverrideContext.tsx
@@ -0,0 +1,7 @@
+import { createGenericComponentsOverrideContext } from "../../components/componentOverride/genericComponentOverrideContext";
+
+import type { ComponentOverrideMap } from "./types";
+
+const [useContext, Provider] = createGenericComponentsOverrideContext();
+
+export { useContext as useRecipeComponentOverrideContext, Provider as RecipeComponentsOverrideContextProvider };
diff --git a/lib/ts/recipe/oauth2provider/components/features/oauth2LogoutScreen/index.tsx b/lib/ts/recipe/oauth2provider/components/features/oauth2LogoutScreen/index.tsx
new file mode 100644
index 000000000..175a56e8e
--- /dev/null
+++ b/lib/ts/recipe/oauth2provider/components/features/oauth2LogoutScreen/index.tsx
@@ -0,0 +1,136 @@
+/* Copyright (c) 2024, VRAI Labs and/or its affiliates. All rights reserved.
+ *
+ * This software is licensed under the Apache License, Version 2.0 (the
+ * "License") as published by the Apache Software Foundation.
+ *
+ * You may not use this file except in compliance with the License. You may
+ * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*
+ * Imports.
+ */
+import * as React from "react";
+import { Fragment } from "react";
+
+import { ComponentOverrideContext } from "../../../../../components/componentOverride/componentOverrideContext";
+import FeatureWrapper from "../../../../../components/featureWrapper";
+import SuperTokens from "../../../../../superTokens";
+import UI from "../../../../../ui";
+import { useUserContext } from "../../../../../usercontext";
+import { getQueryParams, getTenantIdFromQueryParams, useRethrowInRender } from "../../../../../utils";
+import { SessionContext } from "../../../../session";
+import OAuth2Provider from "../../../recipe";
+import { OAuth2LogoutScreenTheme } from "../../themes/oauth2LogoutScreen";
+import { defaultTranslationsOAuth2Provider } from "../../themes/translations";
+
+import type { FeatureBaseProps, UserContext } from "../../../../../types";
+import type Recipe from "../../../recipe";
+import type { ComponentOverrideMap } from "../../../types";
+
+type Prop = FeatureBaseProps<{
+ recipe: Recipe;
+ userContext?: UserContext;
+ useComponentOverrides: () => ComponentOverrideMap;
+}>;
+
+export const OAuth2LogoutScreen: React.FC = (props) => {
+ const rethrowInRender = useRethrowInRender();
+ const sessionContext = React.useContext(SessionContext);
+ const [isLoggingOut, setIsLoggingOut] = React.useState(false);
+ const recipeComponentOverrides = props.useComponentOverrides();
+ let userContext = useUserContext();
+ if (props.userContext !== undefined) {
+ userContext = props.userContext;
+ }
+
+ const logoutChallenge = getQueryParams("logoutChallenge") ?? undefined;
+ const navigate = props.navigate ?? UI.getReactRouterDomWithCustomHistory()?.useHistoryCustom();
+
+ const onLogout = React.useCallback(async () => {
+ if (logoutChallenge === undefined) {
+ return;
+ }
+ setIsLoggingOut(true);
+ try {
+ const { frontendRedirectTo } = await OAuth2Provider.getInstanceOrThrow().webJSRecipe.logOut({
+ logoutChallenge,
+ userContext,
+ });
+ await props.recipe.redirect(
+ {
+ recipeId: "oauth2provider",
+ action: "POST_OAUTH2_LOGOUT_REDIRECT",
+ tenantIdFromQueryParams: getTenantIdFromQueryParams(),
+ frontendRedirectTo,
+ },
+ navigate,
+ {},
+ userContext
+ );
+ } catch (err: any) {
+ rethrowInRender(err);
+ }
+ }, [logoutChallenge, navigate, props.recipe, userContext, rethrowInRender]);
+
+ React.useEffect(() => {
+ // We wait for session loading to finish
+ if (sessionContext.loading === false) {
+ // Redirect to the auth page if there is no logoutChallenge
+ if (logoutChallenge === undefined) {
+ void SuperTokens.getInstanceOrThrow()
+ .redirectToAuth({
+ userContext,
+ redirectBack: false,
+ })
+ .catch(rethrowInRender);
+ } else {
+ // Call logOut directly if there is no session
+ if (sessionContext.doesSessionExist === false) {
+ void onLogout();
+ }
+ }
+ }
+ }, [userContext, logoutChallenge, sessionContext, onLogout]);
+
+ const childProps = {
+ config: props.recipe.config,
+ showSpinner: sessionContext.loading || sessionContext.doesSessionExist === false,
+ onLogoutClicked: onLogout,
+ isLoggingOut,
+ };
+
+ if (logoutChallenge === undefined) {
+ return null;
+ }
+
+ return (
+
+
+
+ {/* No custom theme, use default. */}
+ {props.children === undefined && }
+ {/* Otherwise, custom theme is provided, propagate props. */}
+ {props.children &&
+ React.Children.map(props.children, (child) => {
+ if (React.isValidElement(child)) {
+ return React.cloneElement(child, childProps);
+ }
+
+ return child;
+ })}
+
+
+
+ );
+};
+
+export default OAuth2LogoutScreen;
diff --git a/lib/ts/recipe/oauth2provider/components/features/tryRefreshPage/index.tsx b/lib/ts/recipe/oauth2provider/components/features/tryRefreshPage/index.tsx
new file mode 100644
index 000000000..ddb045694
--- /dev/null
+++ b/lib/ts/recipe/oauth2provider/components/features/tryRefreshPage/index.tsx
@@ -0,0 +1,104 @@
+/* Copyright (c) 2024, VRAI Labs and/or its affiliates. All rights reserved.
+ *
+ * This software is licensed under the Apache License, Version 2.0 (the
+ * "License") as published by the Apache Software Foundation.
+ *
+ * You may not use this file except in compliance with the License. You may
+ * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*
+ * Imports.
+ */
+import * as React from "react";
+import { useContext, Fragment } from "react";
+
+import FeatureWrapper from "../../../../../components/featureWrapper";
+import SuperTokens from "../../../../../superTokens";
+import { useUserContext } from "../../../../../usercontext";
+import { getQueryParams, getTenantIdFromQueryParams, useRethrowInRender } from "../../../../../utils";
+import DynamicLoginMethodsSpinner from "../../../../multitenancy/components/features/dynamicLoginMethodsSpinner";
+import { SessionContext } from "../../../../session";
+import { defaultTranslationsOAuth2Provider } from "../../themes/translations";
+
+import type { FeatureBaseProps, UserContext } from "../../../../../types";
+import type Recipe from "../../../recipe";
+import type { ComponentOverrideMap } from "../../../types";
+
+type Prop = FeatureBaseProps<{
+ recipe: Recipe;
+ userContext?: UserContext;
+ useComponentOverrides: () => ComponentOverrideMap;
+}>;
+
+export const TryRefreshPage: React.FC = (props) => {
+ const rethrowInRender = useRethrowInRender();
+ const sessionContext = useContext(SessionContext);
+ const loginChallenge = getQueryParams("loginChallenge") ?? undefined;
+ let userContext = useUserContext();
+ if (props.userContext !== undefined) {
+ userContext = props.userContext;
+ }
+
+ React.useEffect(() => {
+ if (sessionContext.loading === false) {
+ if (loginChallenge) {
+ (async function () {
+ const { frontendRedirectTo } = await props.recipe.webJSRecipe.getRedirectURLToContinueOAuthFlow({
+ loginChallenge,
+ userContext,
+ });
+ return props.recipe.redirect(
+ {
+ action: "CONTINUE_OAUTH2_AFTER_REFRESH",
+ frontendRedirectTo,
+ tenantIdFromQueryParams: getTenantIdFromQueryParams(),
+ recipeId: "oauth2provider",
+ },
+ props.navigate,
+ {},
+ userContext
+ );
+ })().catch(rethrowInRender);
+ } else {
+ void SuperTokens.getInstanceOrThrow()
+ .redirectToAuth({
+ userContext,
+ redirectBack: false,
+ })
+ .catch(rethrowInRender);
+ }
+ }
+ }, [loginChallenge, props.recipe, props.navigate, userContext, sessionContext]);
+
+ const childProps = {
+ config: props.recipe.config,
+ };
+ return (
+
+
+ {/* No custom theme, use default. */}
+ {props.children === undefined && }
+ {/* Otherwise, custom theme is provided, propagate props. */}
+ {props.children &&
+ React.Children.map(props.children, (child) => {
+ if (React.isValidElement(child)) {
+ return React.cloneElement(child, childProps);
+ }
+
+ return child;
+ })}
+
+
+ );
+};
+
+export default TryRefreshPage;
diff --git a/lib/ts/recipe/oauth2provider/components/themes/oauth2LogoutScreen/OAuth2LogoutScreenInner.tsx b/lib/ts/recipe/oauth2provider/components/themes/oauth2LogoutScreen/OAuth2LogoutScreenInner.tsx
new file mode 100644
index 000000000..75244caa2
--- /dev/null
+++ b/lib/ts/recipe/oauth2provider/components/themes/oauth2LogoutScreen/OAuth2LogoutScreenInner.tsx
@@ -0,0 +1,41 @@
+/* Copyright (c) 2024, VRAI Labs and/or its affiliates. All rights reserved.
+ *
+ * This software is licensed under the Apache License, Version 2.0 (the
+ * "License") as published by the Apache Software Foundation.
+ *
+ * You may not use this file except in compliance with the License. You may
+ * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+import LogoutIcon from "../../../../../components/assets/logoutIcon";
+import { withOverride } from "../../../../../components/componentOverride/withOverride";
+import { useTranslation } from "../../../../../translation/translationContext";
+import { Button } from "../../../../emailpassword/components/library";
+
+export const OAuth2LogoutScreenInner = withOverride(
+ "OAuth2LogoutScreenInner",
+ function OAuth2LogoutScreenInner(props: { isLoggingOut: boolean; onLogoutClicked: () => void }): JSX.Element {
+ const t = useTranslation();
+ return (
+ <>
+
+ {t("LOGGING_OUT")}
+ {t("LOGOUT_CONFIRMATION")}
+
+
+ >
+ );
+ }
+);
diff --git a/lib/ts/recipe/oauth2provider/components/themes/oauth2LogoutScreen/index.tsx b/lib/ts/recipe/oauth2provider/components/themes/oauth2LogoutScreen/index.tsx
new file mode 100644
index 000000000..76c9d556a
--- /dev/null
+++ b/lib/ts/recipe/oauth2provider/components/themes/oauth2LogoutScreen/index.tsx
@@ -0,0 +1,36 @@
+/* eslint-disable react/jsx-no-literals */
+import React from "react";
+
+import { SuperTokensBranding } from "../../../../../components/SuperTokensBranding";
+import SuperTokens from "../../../../../superTokens";
+import DynamicLoginMethodsSpinner from "../../../../multitenancy/components/features/dynamicLoginMethodsSpinner";
+import { ThemeBase } from "../themeBase";
+
+import { OAuth2LogoutScreenInner } from "./OAuth2LogoutScreenInner";
+
+import type { OAuth2LogoutScreenThemeProps } from "../../../types";
+import type { FC } from "react";
+
+const OAuth2LogoutScreen: FC = (props) => {
+ if (props.showSpinner) {
+ return ;
+ }
+ return (
+
+ );
+};
+
+export const OAuth2LogoutScreenTheme: React.FC = (props) => {
+ const rootStyle = SuperTokens.getInstanceOrThrow().rootStyle;
+
+ return (
+
+
+
+ );
+};
diff --git a/lib/ts/recipe/oauth2provider/components/themes/styles.css b/lib/ts/recipe/oauth2provider/components/themes/styles.css
new file mode 100644
index 000000000..b26535209
--- /dev/null
+++ b/lib/ts/recipe/oauth2provider/components/themes/styles.css
@@ -0,0 +1,31 @@
+/* Copyright (c) 2024, VRAI Labs and/or its affiliates. All rights reserved.
+ *
+ * This software is licensed under the Apache License, Version 2.0 (the
+ * "License") as published by the Apache Software Foundation.
+ *
+ * You may not use this file except in compliance with the License. You may
+ * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+@import "../../../../styles/styles.css";
+
+[data-supertokens~="logoutIcon"] {
+ padding: 18px 20px 18px 24px;
+ background-color: rgba(var(--palette-textGray), 0.1);
+ border-radius: 12px;
+}
+
+[data-supertokens~="oauth2Logout"] [data-supertokens~="headerTitle"] {
+ margin-top: 24px;
+ margin-bottom: 24px;
+}
+
+[data-supertokens~="oauth2Logout"] [data-supertokens~="button"] {
+ margin-bottom: 24px;
+}
diff --git a/lib/ts/recipe/oauth2provider/components/themes/themeBase.tsx b/lib/ts/recipe/oauth2provider/components/themes/themeBase.tsx
new file mode 100644
index 000000000..883671522
--- /dev/null
+++ b/lib/ts/recipe/oauth2provider/components/themes/themeBase.tsx
@@ -0,0 +1,36 @@
+/* Copyright (c) 2024, VRAI Labs and/or its affiliates. All rights reserved.
+ *
+ * This software is licensed under the Apache License, Version 2.0 (the
+ * "License") as published by the Apache Software Foundation.
+ *
+ * You may not use this file except in compliance with the License. You may
+ * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+import React from "react";
+import { Fragment } from "react";
+
+import styles from "./styles.css";
+
+import type { PropsWithChildren } from "react";
+
+export const ThemeBase: React.FC }>> = ({
+ children,
+ userStyles,
+}) => {
+ return (
+
+ {children}
+
+
+ );
+};
diff --git a/lib/ts/recipe/oauth2provider/components/themes/translations.ts b/lib/ts/recipe/oauth2provider/components/themes/translations.ts
new file mode 100644
index 000000000..92edb895e
--- /dev/null
+++ b/lib/ts/recipe/oauth2provider/components/themes/translations.ts
@@ -0,0 +1,10 @@
+import { defaultTranslationsCommon } from "../../../../translation/translations";
+
+export const defaultTranslationsOAuth2Provider = {
+ en: {
+ ...defaultTranslationsCommon.en,
+ LOGGING_OUT: "Logging Out",
+ LOGOUT_CONFIRMATION: "Are you sure you want to log out?",
+ LOGOUT: "LOG OUT",
+ },
+};
diff --git a/lib/ts/recipe/oauth2provider/constants.ts b/lib/ts/recipe/oauth2provider/constants.ts
new file mode 100644
index 000000000..3ac81a72d
--- /dev/null
+++ b/lib/ts/recipe/oauth2provider/constants.ts
@@ -0,0 +1,16 @@
+/* Copyright (c) 2024, VRAI Labs and/or its affiliates. All rights reserved.
+ *
+ * This software is licensed under the Apache License, Version 2.0 (the
+ * "License") as published by the Apache Software Foundation.
+ *
+ * You may not use this file except in compliance with the License. You may
+ * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+export const DEFAULT_TRY_REFRESH_PATH = "/try-refresh";
+export const DEFAULT_OAUTH2_LOGOUT_PATH = "/oauth/logout";
diff --git a/lib/ts/recipe/oauth2provider/functionOverrides.ts b/lib/ts/recipe/oauth2provider/functionOverrides.ts
new file mode 100644
index 000000000..e1df04bd8
--- /dev/null
+++ b/lib/ts/recipe/oauth2provider/functionOverrides.ts
@@ -0,0 +1,28 @@
+import type { OnHandleEventContext } from "./types";
+import type { RecipeOnHandleEventFunction } from "../recipeModule/types";
+import type { RecipeInterface } from "supertokens-web-js/recipe/oauth2provider";
+
+export const getFunctionOverrides =
+ (onHandleEvent: RecipeOnHandleEventFunction) =>
+ (originalImp: RecipeInterface): RecipeInterface => ({
+ ...originalImp,
+ async getLoginChallengeInfo(input) {
+ const response = await originalImp.getLoginChallengeInfo(input);
+ onHandleEvent({
+ action: "LOADED_LOGIN_CHALLENGE",
+ loginChallenge: input.loginChallenge,
+ loginInfo: response.info,
+ userContext: input.userContext,
+ });
+ return response;
+ },
+ async logOut(input) {
+ const response = await originalImp.logOut(input);
+ onHandleEvent({
+ action: "OAUTH2_LOGOUT_SUCCESS",
+ frontendRedirectTo: response.frontendRedirectTo,
+ userContext: input.userContext,
+ });
+ return response;
+ },
+ });
diff --git a/lib/ts/recipe/oauth2provider/index.ts b/lib/ts/recipe/oauth2provider/index.ts
new file mode 100644
index 000000000..b935f352f
--- /dev/null
+++ b/lib/ts/recipe/oauth2provider/index.ts
@@ -0,0 +1,115 @@
+/* Copyright (c) 2024, VRAI Labs and/or its affiliates. All rights reserved.
+ *
+ * This software is licensed under the Apache License, Version 2.0 (the
+ * "License") as published by the Apache Software Foundation.
+ *
+ * You may not use this file except in compliance with the License. You may
+ * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { RecipeComponentsOverrideContextProvider } from "./componentOverrideContext";
+import OAuth2Provider from "./recipe";
+import { UserInput, GetRedirectionURLContext, PreAPIHookContext, OnHandleEventContext } from "./types";
+
+import type { RecipeFunctionOptions, LoginInfo } from "supertokens-web-js/recipe/oauth2provider";
+import type { RecipeInterface } from "supertokens-web-js/recipe/oauth2provider";
+
+export default class Wrapper {
+ static init(config?: UserInput) {
+ return OAuth2Provider.init(config);
+ }
+ /**
+ * Returns information about an OAuth login in progress
+ *
+ * @param loginChallenge The login challenge from the url
+ *
+ * @param userContext (OPTIONAL) Refer to {@link https://supertokens.com/docs/emailpassword/advanced-customizations/user-context the documentation}
+ *
+ * @param options (OPTIONAL) Use this to configure additional properties (for example pre api hooks)
+ *
+ * @returns `{status: "OK", info: LoginInfo}`
+ *
+ * @throws STGeneralError if the API exposed by the backend SDKs returns `status: "GENERAL_ERROR"`
+ */
+ static getLoginChallengeInfo(input: {
+ loginChallenge: string;
+ options?: RecipeFunctionOptions;
+ userContext?: any;
+ }): Promise<{
+ status: "OK";
+ info: LoginInfo;
+ fetchResponse: Response;
+ }> {
+ return OAuth2Provider.getInstanceOrThrow().webJSRecipe.getLoginChallengeInfo(input);
+ }
+
+ /**
+ * Accepts the OAuth2 Login request and returns the redirect URL to continue the OAuth flow.
+ *
+ * @param loginChallenge The login challenge from the url
+ *
+ * @param userContext (OPTIONAL) Refer to {@link https://supertokens.com/docs/emailpassword/advanced-customizations/user-context the documentation}
+ *
+ * @param options (OPTIONAL) Use this to configure additional properties (for example pre api hooks)
+ *
+ * @returns `{status: "OK", frontendRedirectTo: string}`
+ *
+ * @throws STGeneralError if the API exposed by the backend SDKs returns `status: "GENERAL_ERROR"`
+ */
+ static getRedirectURLToContinueOAuthFlow(input: {
+ loginChallenge: string;
+ options?: RecipeFunctionOptions;
+ userContext?: any;
+ }): Promise<{
+ status: "OK";
+ frontendRedirectTo: string;
+ fetchResponse: Response;
+ }> {
+ return OAuth2Provider.getInstanceOrThrow().webJSRecipe.getRedirectURLToContinueOAuthFlow(input);
+ }
+
+ /**
+ * Accepts the OAuth2 Logout request, clears the SuperTokens session and returns post logout redirect URL.
+ *
+ * @param logoutChallenge The logout challenge from the url
+ *
+ * @param userContext (OPTIONAL) Refer to {@link https://supertokens.com/docs/emailpassword/advanced-customizations/user-context the documentation}
+ *
+ * @param options (OPTIONAL) Use this to configure additional properties (for example pre api hooks)
+ *
+ * @returns `{status: "OK", frontendRedirectTo: string}`
+ *
+ * @throws STGeneralError if the API exposed by the backend SDKs returns `status: "GENERAL_ERROR"`
+ */
+ static logOut(input: { logoutChallenge: string; options?: RecipeFunctionOptions; userContext?: any }): Promise<{
+ status: "OK";
+ frontendRedirectTo: string;
+ fetchResponse: Response;
+ }> {
+ return OAuth2Provider.getInstanceOrThrow().webJSRecipe.logOut(input);
+ }
+
+ static ComponentsOverrideProvider = RecipeComponentsOverrideContextProvider;
+}
+
+const init = Wrapper.init;
+const getLoginChallengeInfo = Wrapper.getLoginChallengeInfo;
+const logOut = Wrapper.logOut;
+
+export {
+ init,
+ getLoginChallengeInfo,
+ logOut,
+ GetRedirectionURLContext,
+ PreAPIHookContext,
+ OnHandleEventContext,
+ UserInput,
+ RecipeInterface,
+ RecipeComponentsOverrideContextProvider,
+};
diff --git a/lib/ts/recipe/oauth2provider/prebuiltui.tsx b/lib/ts/recipe/oauth2provider/prebuiltui.tsx
new file mode 100644
index 000000000..3f88e7e71
--- /dev/null
+++ b/lib/ts/recipe/oauth2provider/prebuiltui.tsx
@@ -0,0 +1,140 @@
+import NormalisedURLPath from "supertokens-web-js/utils/normalisedURLPath";
+
+import UserContextWrapper from "../../usercontext/userContextWrapper";
+import { isTest, matchRecipeIdUsingQueryParams } from "../../utils";
+import { RecipeRouter } from "../recipeRouter";
+import { SessionAuth } from "../session";
+
+import { useRecipeComponentOverrideContext } from "./componentOverrideContext";
+import { default as OAuth2LogoutScreen } from "./components/features/oauth2LogoutScreen";
+import { default as TryRefreshPageFeature } from "./components/features/tryRefreshPage";
+import { defaultTranslationsOAuth2Provider } from "./components/themes/translations";
+import { DEFAULT_TRY_REFRESH_PATH, DEFAULT_OAUTH2_LOGOUT_PATH } from "./constants";
+import OAuth2ProviderRecipe from "./recipe";
+
+import type { GenericComponentOverrideMap } from "../../components/componentOverride/componentOverrideContext";
+import type { FeatureBaseProps, RecipeFeatureComponentMap, UserContext } from "../../types";
+import type { AuthComponent } from "../../types";
+
+export class OAuth2ProviderPreBuiltUI extends RecipeRouter {
+ static instance?: OAuth2ProviderPreBuiltUI;
+ languageTranslations = defaultTranslationsOAuth2Provider;
+
+ constructor(public readonly recipeInstance: OAuth2ProviderRecipe) {
+ super();
+ }
+
+ // Static methods
+ static getInstanceOrInitAndGetInstance(): OAuth2ProviderPreBuiltUI {
+ if (OAuth2ProviderPreBuiltUI.instance === undefined) {
+ const recipeInstance = OAuth2ProviderRecipe.getInstanceOrThrow();
+ OAuth2ProviderPreBuiltUI.instance = new OAuth2ProviderPreBuiltUI(recipeInstance);
+ }
+
+ return OAuth2ProviderPreBuiltUI.instance;
+ }
+ static getFeatures(
+ useComponentOverrides: () => GenericComponentOverrideMap = useRecipeComponentOverrideContext
+ ): RecipeFeatureComponentMap {
+ return OAuth2ProviderPreBuiltUI.getInstanceOrInitAndGetInstance().getFeatures(useComponentOverrides);
+ }
+ static getFeatureComponent(
+ componentName: "try-refresh-page" | "oauth2-logout-screen",
+ props: any,
+ useComponentOverrides: () => GenericComponentOverrideMap = useRecipeComponentOverrideContext
+ ): JSX.Element {
+ return OAuth2ProviderPreBuiltUI.getInstanceOrInitAndGetInstance().getFeatureComponent(
+ componentName,
+ props,
+ useComponentOverrides
+ );
+ }
+
+ // Instance methods
+ getFeatures = (
+ useComponentOverrides: () => GenericComponentOverrideMap = useRecipeComponentOverrideContext
+ ): RecipeFeatureComponentMap => {
+ if (this.recipeInstance.config.disableDefaultUI) {
+ return {};
+ }
+ const features: RecipeFeatureComponentMap = {};
+ if (this.recipeInstance.config.tryRefreshPage.disableDefaultUI !== true) {
+ const normalisedFullPath = this.recipeInstance.config.appInfo.websiteBasePath.appendPath(
+ new NormalisedURLPath(DEFAULT_TRY_REFRESH_PATH)
+ );
+ features[normalisedFullPath.getAsStringDangerous()] = {
+ matches: matchRecipeIdUsingQueryParams(this.recipeInstance.config.recipeId),
+ component: (props: any) => this.getFeatureComponent("try-refresh-page", props, useComponentOverrides),
+ recipeID: OAuth2ProviderRecipe.RECIPE_ID,
+ };
+ }
+ if (this.recipeInstance.config.oauth2LogoutScreen.disableDefaultUI !== true) {
+ const normalisedFullPath = this.recipeInstance.config.appInfo.websiteBasePath.appendPath(
+ new NormalisedURLPath(DEFAULT_OAUTH2_LOGOUT_PATH)
+ );
+ features[normalisedFullPath.getAsStringDangerous()] = {
+ matches: matchRecipeIdUsingQueryParams(this.recipeInstance.config.recipeId),
+ component: (props) =>
+ this.getFeatureComponent("oauth2-logout-screen", props as any, useComponentOverrides),
+ recipeID: OAuth2ProviderRecipe.RECIPE_ID,
+ };
+ }
+ return features;
+ };
+ getFeatureComponent = (
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ componentName: "try-refresh-page" | "oauth2-logout-screen",
+ props: FeatureBaseProps<{ userContext?: UserContext }>,
+ useComponentOverrides: () => GenericComponentOverrideMap = useRecipeComponentOverrideContext
+ ): JSX.Element => {
+ if (componentName === "try-refresh-page") {
+ return (
+
+ []}>
+
+
+
+ );
+ } else if (componentName === "oauth2-logout-screen") {
+ return (
+
+ []}>
+
+
+
+ );
+ }
+ throw new Error("Should never come here.");
+ };
+
+ getAuthComponents(): AuthComponent[] {
+ return [];
+ }
+
+ // For tests
+ static reset(): void {
+ if (!isTest()) {
+ return;
+ }
+
+ OAuth2ProviderPreBuiltUI.instance = undefined;
+ return;
+ }
+
+ static TryRefreshPage = (props: FeatureBaseProps<{ userContext?: UserContext }>) =>
+ OAuth2ProviderPreBuiltUI.getInstanceOrInitAndGetInstance().getFeatureComponent("try-refresh-page", props);
+ static OAuth2LogoutScreen = (props: FeatureBaseProps<{ userContext?: UserContext }>) =>
+ OAuth2ProviderPreBuiltUI.getInstanceOrInitAndGetInstance().getFeatureComponent("oauth2-logout-screen", props);
+}
+
+const TryRefreshPage = OAuth2ProviderPreBuiltUI.TryRefreshPage;
+
+export { TryRefreshPage };
diff --git a/lib/ts/recipe/oauth2provider/recipe.ts b/lib/ts/recipe/oauth2provider/recipe.ts
new file mode 100644
index 000000000..1509a632d
--- /dev/null
+++ b/lib/ts/recipe/oauth2provider/recipe.ts
@@ -0,0 +1,137 @@
+/* Copyright (c) 2024, VRAI Labs and/or its affiliates. All rights reserved.
+ *
+ * This software is licensed under the Apache License, Version 2.0 (the
+ * "License") as published by the Apache Software Foundation.
+ *
+ * You may not use this file except in compliance with the License. You may
+ * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*
+ * Imports.
+ */
+
+import OAuth2WebJS from "supertokens-web-js/recipe/oauth2provider";
+
+import { SSR_ERROR } from "../../constants";
+import { isTest } from "../../utils";
+import RecipeModule from "../recipeModule";
+
+import { getFunctionOverrides } from "./functionOverrides";
+import { normaliseOAuth2Config } from "./utils";
+
+import type {
+ GetRedirectionURLContext,
+ NormalisedConfig,
+ OnHandleEventContext,
+ PreAndPostAPIHookAction,
+ UserInput,
+} from "./types";
+import type { RecipeInitResult, NormalisedConfigWithAppInfoAndRecipeID, WebJSRecipeInterface } from "../../types";
+import type { NormalisedAppInfo } from "../../types";
+
+/*
+ * Class.
+ */
+export default class OAuth2Provider extends RecipeModule<
+ GetRedirectionURLContext,
+ PreAndPostAPIHookAction,
+ OnHandleEventContext,
+ NormalisedConfig
+> {
+ static instance?: OAuth2Provider;
+ static readonly RECIPE_ID = "oauth2provider";
+
+ public readonly recipeID = OAuth2Provider.RECIPE_ID;
+
+ constructor(
+ config: NormalisedConfigWithAppInfoAndRecipeID,
+ public readonly webJSRecipe: WebJSRecipeInterface = OAuth2WebJS
+ ) {
+ super(config);
+ }
+
+ static init(config?: UserInput): RecipeInitResult {
+ const normalisedConfig = normaliseOAuth2Config(config);
+ return {
+ recipeID: OAuth2Provider.RECIPE_ID,
+ authReact: (
+ appInfo: NormalisedAppInfo
+ ): RecipeModule<
+ GetRedirectionURLContext,
+ PreAndPostAPIHookAction,
+ OnHandleEventContext,
+ NormalisedConfig
+ > => {
+ OAuth2Provider.instance = new OAuth2Provider({
+ ...normalisedConfig,
+ appInfo,
+ recipeId: OAuth2Provider.RECIPE_ID,
+ });
+ return OAuth2Provider.instance;
+ },
+ webJS: OAuth2WebJS.init({
+ ...normalisedConfig,
+ override: {
+ functions: (originalImpl, builder) => {
+ const functions = getFunctionOverrides(normalisedConfig.onHandleEvent);
+ builder.override(functions);
+ builder.override(normalisedConfig.override.functions);
+ return originalImpl;
+ },
+ },
+ }),
+ };
+ }
+
+ static getInstanceOrThrow(): OAuth2Provider {
+ if (OAuth2Provider.instance === undefined) {
+ let error =
+ "No instance of OAuth2Provider found. Make sure to call the OAuth2Provider.init method." +
+ "See https://supertokens.io/docs/oauth2/quick-setup/frontend";
+
+ // eslint-disable-next-line supertokens-auth-react/no-direct-window-object
+ if (typeof window === "undefined") {
+ error = error + SSR_ERROR;
+ }
+ throw Error(error);
+ }
+
+ return OAuth2Provider.instance;
+ }
+
+ static getInstance(): OAuth2Provider | undefined {
+ return OAuth2Provider.instance;
+ }
+
+ async getDefaultRedirectionURL(ctx: GetRedirectionURLContext): Promise {
+ // We do not use the util here, because we are likely redirecting across domains here.
+ if (
+ ctx.action === "SUCCESS_OAUTH2" ||
+ ctx.action === "CONTINUE_OAUTH2_AFTER_REFRESH" ||
+ ctx.action === "POST_OAUTH2_LOGOUT_REDIRECT"
+ ) {
+ return ctx.frontendRedirectTo;
+ } else {
+ throw new Error("Should never come here: unknown action in OAuth2Provider.getDefaultRedirectionURL");
+ }
+ }
+
+ /*
+ * Tests methods.
+ */
+ static reset(): void {
+ if (!isTest()) {
+ return;
+ }
+
+ OAuth2Provider.instance = undefined;
+ return;
+ }
+}
diff --git a/lib/ts/recipe/oauth2provider/types.ts b/lib/ts/recipe/oauth2provider/types.ts
new file mode 100644
index 000000000..6d8f8e7ec
--- /dev/null
+++ b/lib/ts/recipe/oauth2provider/types.ts
@@ -0,0 +1,106 @@
+import type { OAuth2LogoutScreenInner } from "./components/themes/oauth2LogoutScreen/OAuth2LogoutScreenInner";
+import type { ComponentOverride } from "../../components/componentOverride/componentOverride";
+import type {
+ NormalisedBaseConfig,
+ NormalisedGetRedirectionURLContext,
+ SuccessRedirectContextOAuth2,
+ UserContext,
+} from "../../types";
+import type {
+ UserInput as RecipeModuleUserInput,
+ NormalisedConfig as NormalisedRecipeModuleConfig,
+} from "../recipeModule/types";
+import type OverrideableBuilder from "supertokens-js-override";
+import type { LoginInfo, RecipeInterface } from "supertokens-web-js/recipe/oauth2provider/types";
+
+export type PreAndPostAPIHookAction =
+ | "GET_LOGIN_CHALLENGE_INFO"
+ | "GET_REDIRECT_URL_TO_CONTINUE_OAUTH_FLOW"
+ | "LOG_OUT";
+
+export type PreAPIHookContext = {
+ action: PreAndPostAPIHookAction;
+ requestInit: RequestInit;
+ url: string;
+ userContext: UserContext;
+};
+
+export type UserInput = {
+ disableDefaultUI?: boolean;
+ oauth2LogoutScreen?: Partial;
+ tryRefreshPage?: Partial;
+ override?: {
+ functions?: (
+ originalImplementation: RecipeInterface,
+ builder: OverrideableBuilder
+ ) => RecipeInterface;
+ };
+} & RecipeModuleUserInput;
+
+export type NormalisedConfig = NormalisedRecipeModuleConfig<
+ GetRedirectionURLContext,
+ PreAndPostAPIHookAction,
+ OnHandleEventContext
+> & {
+ disableDefaultUI: boolean;
+ oauth2LogoutScreen: OAuth2LogoutScreenConfig;
+ tryRefreshPage: OAuth2TryRefreshPageConfig;
+ override: {
+ functions: (
+ originalImplementation: RecipeInterface,
+ builder: OverrideableBuilder
+ ) => RecipeInterface;
+ };
+};
+
+export type OAuth2LogoutScreenConfig = NormalisedBaseConfig & {
+ disableDefaultUI: boolean;
+};
+
+// This doesn't have the NormalisedBaseConfig because it only shows the generic spinner
+export type OAuth2TryRefreshPageConfig = {
+ disableDefaultUI: boolean;
+};
+
+export type ContinueOAuth2AfterRefreshRedirectContext = {
+ recipeId: "oauth2provider";
+ action: "CONTINUE_OAUTH2_AFTER_REFRESH";
+ frontendRedirectTo: string;
+};
+
+export type PostOAuth2LogoutRedirectContext = {
+ recipeId: "oauth2provider";
+ action: "POST_OAUTH2_LOGOUT_REDIRECT";
+ frontendRedirectTo: string;
+};
+
+export type GetRedirectionURLContext = NormalisedGetRedirectionURLContext<
+ SuccessRedirectContextOAuth2 | ContinueOAuth2AfterRefreshRedirectContext | PostOAuth2LogoutRedirectContext
+>;
+
+export type OnHandleEventContext =
+ | {
+ /*
+ * On Handle Event actions
+ */
+ action: "LOADED_LOGIN_CHALLENGE";
+ loginChallenge: string;
+ loginInfo: LoginInfo;
+ userContext: UserContext;
+ }
+ | {
+ action: "OAUTH2_LOGOUT_SUCCESS";
+ frontendRedirectTo: string;
+ userContext: UserContext;
+ };
+
+export type ComponentOverrideMap = {
+ OAuth2LogoutScreenInner_Override?: ComponentOverride;
+};
+
+export type OAuth2LogoutScreenThemeProps = {
+ config: NormalisedConfig;
+ isLoggingOut: boolean;
+ onLogoutClicked: () => void;
+ showSpinner: boolean;
+};
diff --git a/lib/ts/recipe/oauth2provider/utils.ts b/lib/ts/recipe/oauth2provider/utils.ts
new file mode 100644
index 000000000..762dde7cf
--- /dev/null
+++ b/lib/ts/recipe/oauth2provider/utils.ts
@@ -0,0 +1,23 @@
+import { normaliseRecipeModuleConfig } from "../recipeModule/utils";
+
+import type { UserInput, NormalisedConfig } from "./types";
+
+export function normaliseOAuth2Config(config?: UserInput): NormalisedConfig {
+ return {
+ ...normaliseRecipeModuleConfig(config),
+ disableDefaultUI: config?.disableDefaultUI ?? false,
+ tryRefreshPage: {
+ disableDefaultUI: false,
+ ...config?.tryRefreshPage,
+ },
+ oauth2LogoutScreen: {
+ disableDefaultUI: false,
+ style: "",
+ ...config?.oauth2LogoutScreen,
+ },
+ override: {
+ functions: (originalImplementation) => originalImplementation,
+ ...config?.override,
+ },
+ };
+}
diff --git a/lib/ts/recipe/passwordless/components/features/linkClickedScreen/index.tsx b/lib/ts/recipe/passwordless/components/features/linkClickedScreen/index.tsx
index 50ece20a0..89deed42d 100644
--- a/lib/ts/recipe/passwordless/components/features/linkClickedScreen/index.tsx
+++ b/lib/ts/recipe/passwordless/components/features/linkClickedScreen/index.tsx
@@ -23,7 +23,13 @@ import { ComponentOverrideContext } from "../../../../../components/componentOve
import FeatureWrapper from "../../../../../components/featureWrapper";
import SuperTokens from "../../../../../superTokens";
import { useUserContext } from "../../../../../usercontext";
-import { getQueryParams, getURLHash, useOnMountAPICall, useRethrowInRender } from "../../../../../utils";
+import {
+ getQueryParams,
+ getTenantIdFromQueryParams,
+ getURLHash,
+ useOnMountAPICall,
+ useRethrowInRender,
+} from "../../../../../utils";
import Session from "../../../../session/recipe";
import { LinkClickedScreen as LinkClickedScreenTheme } from "../../themes/linkClickedScreen";
import { defaultTranslationsPasswordless } from "../../themes/translations";
@@ -148,6 +154,7 @@ const LinkClickedScreen: React.FC = (props) => {
(payloadBeforeCall === undefined ||
payloadBeforeCall.sessionHandle !== payloadAfterCall.sessionHandle),
recipeId: props.recipe.recipeID,
+ tenantIdFromQueryParams: getTenantIdFromQueryParams(),
},
props.recipe.recipeID,
loginAttemptInfo?.redirectToPath,
diff --git a/lib/ts/recipe/passwordless/components/features/linkSent/index.tsx b/lib/ts/recipe/passwordless/components/features/linkSent/index.tsx
index a6ec99e49..d8b457233 100644
--- a/lib/ts/recipe/passwordless/components/features/linkSent/index.tsx
+++ b/lib/ts/recipe/passwordless/components/features/linkSent/index.tsx
@@ -20,7 +20,12 @@ import { Fragment } from "react";
import { useMemo } from "react";
import AuthComponentWrapper from "../../../../../components/authCompWrapper";
-import { clearErrorQueryParam, getRedirectToPathFromURL, useRethrowInRender } from "../../../../../utils";
+import {
+ clearErrorQueryParam,
+ getRedirectToPathFromURL,
+ getTenantIdFromQueryParams,
+ useRethrowInRender,
+} from "../../../../../utils";
import { EmailVerificationClaim } from "../../../../emailverification";
import EmailVerification from "../../../../emailverification/recipe";
import { getInvalidClaimsFromResponse } from "../../../../session";
@@ -81,6 +86,7 @@ export function useChildProps(
(payloadAfterCall !== undefined &&
session.accessTokenPayload.sessionHandle !== payloadAfterCall.sessionHandle),
recipeId: recipe.recipeID,
+ tenantIdFromQueryParams: getTenantIdFromQueryParams(),
},
recipe.recipeID,
getRedirectToPathFromURL(),
@@ -98,6 +104,7 @@ export function useChildProps(
const evInstance = EmailVerification.getInstanceOrThrow();
await evInstance.redirect(
{
+ tenantIdFromQueryParams: getTenantIdFromQueryParams(),
action: "VERIFY_EMAIL",
},
navigate,
@@ -204,6 +211,7 @@ function getModifiedRecipeImplementation(
userContext: input.userContext,
attemptInfo: {
...loginAttemptInfo,
+ shouldTryLinkingWithSessionUser: loginAttemptInfo.shouldTryLinkingWithSessionUser ?? false,
lastResend: timestamp,
},
});
diff --git a/lib/ts/recipe/passwordless/components/features/mfa/index.tsx b/lib/ts/recipe/passwordless/components/features/mfa/index.tsx
index c742fc27e..a8d83bef1 100644
--- a/lib/ts/recipe/passwordless/components/features/mfa/index.tsx
+++ b/lib/ts/recipe/passwordless/components/features/mfa/index.tsx
@@ -29,6 +29,7 @@ import {
clearErrorQueryParam,
getQueryParams,
getRedirectToPathFromURL,
+ getTenantIdFromQueryParams,
useOnMountAPICall,
useRethrowInRender,
} from "../../../../../utils";
@@ -182,6 +183,7 @@ export function useChildProps(
await evInstance.redirect(
{
action: "VERIFY_EMAIL",
+ tenantIdFromQueryParams: getTenantIdFromQueryParams(),
},
navigate,
undefined,
@@ -384,6 +386,7 @@ function useOnLoad(
// createCode also dispatches the event that marks this page fully loaded
createResp = await recipeImplementation!.createCode({
...createCodeInfo,
+ shouldTryLinkingWithSessionUser: true,
userContext,
});
} catch (err: any) {
@@ -398,6 +401,7 @@ function useOnLoad(
const evInstance = EmailVerificationRecipe.getInstanceOrThrow();
await evInstance.redirect(
{
+ tenantIdFromQueryParams: getTenantIdFromQueryParams(),
action: "VERIFY_EMAIL",
},
props.navigate,
@@ -490,6 +494,7 @@ function getModifiedRecipeImplementation(
const res = await originalImpl.createCode({
...input,
+ shouldTryLinkingWithSessionUser: true,
userContext: { ...input.userContext, additionalAttemptInfo },
});
@@ -520,6 +525,7 @@ function getModifiedRecipeImplementation(
userContext: input.userContext,
attemptInfo: {
...loginAttemptInfo,
+ shouldTryLinkingWithSessionUser: loginAttemptInfo.shouldTryLinkingWithSessionUser ?? true,
lastResend: timestamp,
},
});
@@ -536,7 +542,10 @@ function getModifiedRecipeImplementation(
},
consumeCode: async (input) => {
- const res = await originalImpl.consumeCode(input);
+ const res = await originalImpl.consumeCode({
+ ...input,
+ shouldTryLinkingWithSessionUser: true,
+ });
if (res.status === "RESTART_FLOW_ERROR") {
await originalImpl.clearLoginAttemptInfo({
diff --git a/lib/ts/recipe/passwordless/components/features/signInAndUp/index.tsx b/lib/ts/recipe/passwordless/components/features/signInAndUp/index.tsx
index 20ade54f8..4e29f5fc8 100644
--- a/lib/ts/recipe/passwordless/components/features/signInAndUp/index.tsx
+++ b/lib/ts/recipe/passwordless/components/features/signInAndUp/index.tsx
@@ -21,11 +21,10 @@ import { useMemo } from "react";
import AuthComponentWrapper from "../../../../../components/authCompWrapper";
import { useUserContext } from "../../../../../usercontext";
-import { getRedirectToPathFromURL, useRethrowInRender } from "../../../../../utils";
+import { getRedirectToPathFromURL, getTenantIdFromQueryParams, useRethrowInRender } from "../../../../../utils";
import { EmailVerificationClaim } from "../../../../emailverification";
import EmailVerification from "../../../../emailverification/recipe";
import { getInvalidClaimsFromResponse } from "../../../../session";
-import SessionRecipe from "../../../../session/recipe";
import Session from "../../../../session/recipe";
import useSessionContext from "../../../../session/useSessionContext";
import { defaultPhoneNumberValidator } from "../../../defaultPhoneNumberValidator";
@@ -33,6 +32,7 @@ import { getPhoneNumberUtils } from "../../../phoneNumberUtils";
import SignInUpThemeWrapper from "../../themes/signInUp";
import type { Navigate, UserContext, PartialAuthComponentProps } from "../../../../../types";
+import type { AuthSuccessContext } from "../../../../authRecipe/types";
import type Recipe from "../../../recipe";
import type { ComponentOverrideMap } from "../../../types";
import type { SignInUpChildProps, NormalisedConfig } from "../../../types";
@@ -42,6 +42,7 @@ import type { User } from "supertokens-web-js/types";
export function useChildProps(
recipe: Recipe,
factorIds: string[],
+ onAuthSuccess: (successContext: AuthSuccessContext) => Promise,
error: string | undefined,
onError: (err: string) => void,
clearError: () => void,
@@ -68,25 +69,16 @@ export function useChildProps(
} catch {
payloadAfterCall = undefined;
}
- return SessionRecipe.getInstanceOrThrow()
- .validateGlobalClaimsAndHandleSuccessRedirection(
- {
- action: "SUCCESS",
- createdNewUser: result.createdNewRecipeUser && result.user.loginMethods.length === 1,
- isNewRecipeUser: result.createdNewRecipeUser,
- newSessionCreated:
- session.loading ||
- !session.doesSessionExist ||
- (payloadAfterCall !== undefined &&
- session.accessTokenPayload.sessionHandle !== payloadAfterCall.sessionHandle),
- recipeId: recipe.recipeID,
- },
- recipe.recipeID,
- getRedirectToPathFromURL(),
- userContext,
- navigate
- )
- .catch(rethrowInRender);
+ return onAuthSuccess({
+ createdNewUser: result.createdNewRecipeUser && result.user.loginMethods.length === 1,
+ isNewRecipeUser: result.createdNewRecipeUser,
+ newSessionCreated:
+ session.loading ||
+ !session.doesSessionExist ||
+ (payloadAfterCall !== undefined &&
+ session.accessTokenPayload.sessionHandle !== payloadAfterCall.sessionHandle),
+ recipeId: "passwordless",
+ }).catch(rethrowInRender);
},
error,
onError,
@@ -101,6 +93,7 @@ export function useChildProps(
await evInstance.redirect(
{
action: "VERIFY_EMAIL",
+ tenantIdFromQueryParams: getTenantIdFromQueryParams(),
},
navigate,
undefined,
@@ -137,6 +130,7 @@ const SignInUpFeatureInner: React.FC<
const childProps = useChildProps(
props.recipe,
props.factorIds,
+ props.onAuthSuccess,
props.error,
props.onError,
props.clearError,
@@ -215,6 +209,7 @@ function getModifiedRecipeImplementation(
const res = await originalImpl.createCode({
...input,
+ shouldTryLinkingWithSessionUser: false,
userContext: { ...input.userContext, additionalAttemptInfo },
});
if (res.status === "OK") {
diff --git a/lib/ts/recipe/passwordless/components/features/signInAndUpEPCombo/index.tsx b/lib/ts/recipe/passwordless/components/features/signInAndUpEPCombo/index.tsx
index d2f3d5775..2e808e4a8 100644
--- a/lib/ts/recipe/passwordless/components/features/signInAndUpEPCombo/index.tsx
+++ b/lib/ts/recipe/passwordless/components/features/signInAndUpEPCombo/index.tsx
@@ -22,13 +22,17 @@ import STGeneralError from "supertokens-web-js/lib/build/error";
import AuthComponentWrapper from "../../../../../components/authCompWrapper";
import { useUserContext } from "../../../../../usercontext";
-import { getRedirectToPathFromURL, useRethrowInRender, validateForm } from "../../../../../utils";
+import {
+ getRedirectToPathFromURL,
+ getTenantIdFromQueryParams,
+ useRethrowInRender,
+ validateForm,
+} from "../../../../../utils";
import EmailPassword from "../../../../emailpassword/recipe";
import { EmailVerificationClaim } from "../../../../emailverification";
import EmailVerification from "../../../../emailverification/recipe";
import { FactorIds } from "../../../../multifactorauth";
import { getInvalidClaimsFromResponse } from "../../../../session";
-import SessionRecipe from "../../../../session/recipe";
import Session from "../../../../session/recipe";
import useSessionContext from "../../../../session/useSessionContext";
import { defaultPhoneNumberValidator } from "../../../defaultPhoneNumberValidator";
@@ -36,6 +40,7 @@ import { getPhoneNumberUtils } from "../../../phoneNumberUtils";
import SignInUpEPComboThemeWrapper from "../../themes/signInUpEPCombo";
import type { Navigate, UserContext, PartialAuthComponentProps } from "../../../../../types";
+import type { AuthSuccessContext } from "../../../../authRecipe/types";
import type Recipe from "../../../recipe";
import type { ComponentOverrideMap } from "../../../types";
import type { SignInUpEPComboChildProps, NormalisedConfig } from "../../../types";
@@ -44,6 +49,7 @@ import type { RecipeInterface } from "supertokens-web-js/recipe/passwordless";
export function useChildProps(
recipe: Recipe,
factorIds: string[],
+ onAuthSuccess: (successContext: AuthSuccessContext) => Promise,
error: string | undefined,
onError: (err: string) => void,
clearError: () => void,
@@ -80,7 +86,11 @@ export function useChildProps(
showContinueWithPasswordlessLink,
onContactInfoSubmit: async (contactInfo: string) => {
if (isPhoneNumber) {
- const createRes = await recipeImplementation.createCode({ phoneNumber: contactInfo, userContext });
+ const createRes = await recipeImplementation.createCode({
+ phoneNumber: contactInfo,
+ shouldTryLinkingWithSessionUser: false,
+ userContext,
+ });
if (createRes.status === "SIGN_IN_UP_NOT_ALLOWED") {
throw new STGeneralError(createRes.reason);
@@ -109,7 +119,11 @@ export function useChildProps(
return { status: "OK" };
} else if (pwlessExists.doesExist) {
// only pwless exists
- const createRes = await recipeImplementation.createCode({ email, userContext });
+ const createRes = await recipeImplementation.createCode({
+ email,
+ shouldTryLinkingWithSessionUser: false,
+ userContext,
+ });
if (createRes.status === "SIGN_IN_UP_NOT_ALLOWED") {
throw new STGeneralError(createRes.reason);
@@ -140,6 +154,7 @@ export function useChildProps(
const response = await EmailPassword.getInstanceOrThrow().webJSRecipe.signIn({
formFields,
+ shouldTryLinkingWithSessionUser: false,
userContext,
});
if (response.status === "WRONG_CREDENTIALS_ERROR") {
@@ -153,7 +168,11 @@ export function useChildProps(
onContinueWithPasswordlessClick: async (contactInfo) => {
// When this function is called, the contactInfo has already been validated
const createInfo = isPhoneNumber ? { phoneNumber: contactInfo } : { email: contactInfo };
- const createRes = await recipeImplementation.createCode({ ...createInfo, userContext });
+ const createRes = await recipeImplementation.createCode({
+ ...createInfo,
+ shouldTryLinkingWithSessionUser: false,
+ userContext,
+ });
if (createRes.status !== "OK") {
onError(createRes.reason);
} else {
@@ -172,25 +191,16 @@ export function useChildProps(
} catch {
payloadAfterCall = undefined;
}
- return SessionRecipe.getInstanceOrThrow()
- .validateGlobalClaimsAndHandleSuccessRedirection(
- {
- action: "SUCCESS",
- createdNewUser: result.createdNewRecipeUser && result.user.loginMethods.length === 1,
- isNewRecipeUser: result.createdNewRecipeUser,
- newSessionCreated:
- session.loading ||
- !session.doesSessionExist ||
- (payloadAfterCall !== undefined &&
- session.accessTokenPayload.sessionHandle !== payloadAfterCall.sessionHandle),
- recipeId: result.isEmailPassword ? EmailPassword.RECIPE_ID : recipe.recipeID,
- },
- result.isEmailPassword ? EmailPassword.RECIPE_ID : recipe.recipeID,
- getRedirectToPathFromURL(),
- userContext,
- navigate
- )
- .catch(rethrowInRender);
+ return onAuthSuccess({
+ createdNewUser: result.createdNewRecipeUser && result.user.loginMethods.length === 1,
+ isNewRecipeUser: result.createdNewRecipeUser,
+ newSessionCreated:
+ session.loading ||
+ !session.doesSessionExist ||
+ (payloadAfterCall !== undefined &&
+ session.accessTokenPayload.sessionHandle !== payloadAfterCall.sessionHandle),
+ recipeId: result.isEmailPassword ? EmailPassword.RECIPE_ID : recipe.recipeID,
+ }).catch(rethrowInRender);
},
error,
onError,
@@ -205,6 +215,7 @@ export function useChildProps(
await evInstance.redirect(
{
action: "VERIFY_EMAIL",
+ tenantIdFromQueryParams: getTenantIdFromQueryParams(),
},
navigate,
undefined,
@@ -249,6 +260,7 @@ const SignInUpEPComboFeatureInner: React.FC<
const childProps = useChildProps(
props.recipe,
props.factorIds,
+ props.onAuthSuccess,
props.error,
props.onError,
props.clearError,
@@ -327,6 +339,7 @@ function getModifiedRecipeImplementation(
const res = await originalImpl.createCode({
...input,
+ shouldTryLinkingWithSessionUser: false,
userContext: { ...input.userContext, additionalAttemptInfo },
});
if (res.status === "OK") {
diff --git a/lib/ts/recipe/passwordless/components/features/userInputCode/index.tsx b/lib/ts/recipe/passwordless/components/features/userInputCode/index.tsx
index 6baa25972..b49d83827 100644
--- a/lib/ts/recipe/passwordless/components/features/userInputCode/index.tsx
+++ b/lib/ts/recipe/passwordless/components/features/userInputCode/index.tsx
@@ -20,16 +20,16 @@ import { Fragment } from "react";
import { useMemo } from "react";
import AuthComponentWrapper from "../../../../../components/authCompWrapper";
-import { clearErrorQueryParam, getRedirectToPathFromURL, useRethrowInRender } from "../../../../../utils";
+import { clearErrorQueryParam, getTenantIdFromQueryParams, useRethrowInRender } from "../../../../../utils";
import { EmailVerificationClaim } from "../../../../emailverification";
import EmailVerification from "../../../../emailverification/recipe";
import { getInvalidClaimsFromResponse } from "../../../../session";
-import SessionRecipe from "../../../../session/recipe";
import Session from "../../../../session/recipe";
import useSessionContext from "../../../../session/useSessionContext";
import UserInputCodeFormScreenWrapper from "../../themes/userInputCodeForm/userInputCodeFormScreen";
import type { Navigate, UserContext, AuthComponentProps } from "../../../../../types";
+import type { AuthSuccessContext } from "../../../../authRecipe/types";
import type Recipe from "../../../recipe";
import type {
AdditionalLoginAttemptInfoProperties,
@@ -43,6 +43,7 @@ import type { User } from "supertokens-web-js/types";
export function useChildProps(
recipe: Recipe,
loginAttemptInfo: LoginAttemptInfo,
+ onAuthSuccess: (successContext: AuthSuccessContext) => Promise,
error: string | undefined,
onError: (err: string) => void,
clearError: () => void,
@@ -69,25 +70,16 @@ export function useChildProps(
} catch {
payloadAfterCall = undefined;
}
- return SessionRecipe.getInstanceOrThrow()
- .validateGlobalClaimsAndHandleSuccessRedirection(
- {
- action: "SUCCESS",
- createdNewUser: result.createdNewRecipeUser && result.user.loginMethods.length === 1,
- isNewRecipeUser: result.createdNewRecipeUser,
- newSessionCreated:
- session.loading ||
- !session.doesSessionExist ||
- (payloadAfterCall !== undefined &&
- session.accessTokenPayload.sessionHandle !== payloadAfterCall.sessionHandle),
- recipeId: recipe.recipeID,
- },
- recipe.recipeID,
- getRedirectToPathFromURL(),
- userContext,
- navigate
- )
- .catch(rethrowInRender);
+ return onAuthSuccess({
+ createdNewUser: result.createdNewRecipeUser && result.user.loginMethods.length === 1,
+ isNewRecipeUser: result.createdNewRecipeUser,
+ newSessionCreated:
+ session.loading ||
+ !session.doesSessionExist ||
+ (payloadAfterCall !== undefined &&
+ session.accessTokenPayload.sessionHandle !== payloadAfterCall.sessionHandle),
+ recipeId: "passwordless",
+ }).catch(rethrowInRender);
},
onFetchError: async (err: Response) => {
if (err.status === Session.getInstanceOrThrow().config.invalidClaimStatusCode) {
@@ -99,6 +91,7 @@ export function useChildProps(
await evInstance.redirect(
{
action: "VERIFY_EMAIL",
+ tenantIdFromQueryParams: getTenantIdFromQueryParams(),
},
navigate,
undefined,
@@ -132,6 +125,7 @@ const UserInputCodeFeatureInner: React.FC<
const childProps = useChildProps(
props.recipe,
props.loginAttemptInfo,
+ props.onAuthSuccess,
props.error,
props.onError,
props.clearError,
@@ -206,6 +200,7 @@ function getModifiedRecipeImplementation(
userContext: input.userContext,
attemptInfo: {
...loginAttemptInfo,
+ shouldTryLinkingWithSessionUser: loginAttemptInfo.shouldTryLinkingWithSessionUser ?? false,
lastResend: timestamp,
},
});
diff --git a/lib/ts/recipe/passwordless/components/themes/signInUp/emailForm.tsx b/lib/ts/recipe/passwordless/components/themes/signInUp/emailForm.tsx
index 902924b0c..aadd55613 100644
--- a/lib/ts/recipe/passwordless/components/themes/signInUp/emailForm.tsx
+++ b/lib/ts/recipe/passwordless/components/themes/signInUp/emailForm.tsx
@@ -62,6 +62,7 @@ export const EmailForm = withOverride(
const response = await props.recipeImplementation.createCode({
email,
+ // shouldTryLinkingWithSessionUser is set by the fn override
userContext,
});
diff --git a/lib/ts/recipe/passwordless/components/themes/signInUp/emailOrPhoneForm.tsx b/lib/ts/recipe/passwordless/components/themes/signInUp/emailOrPhoneForm.tsx
index 795bf7faa..afbe7000e 100644
--- a/lib/ts/recipe/passwordless/components/themes/signInUp/emailOrPhoneForm.tsx
+++ b/lib/ts/recipe/passwordless/components/themes/signInUp/emailOrPhoneForm.tsx
@@ -137,6 +137,7 @@ export const EmailOrPhoneForm = withOverride(
const response = await props.recipeImplementation.createCode({
...contactInfo,
+ // shouldTryLinkingWithSessionUser is set by the fn override
userContext,
});
diff --git a/lib/ts/recipe/passwordless/components/themes/signInUp/phoneForm.tsx b/lib/ts/recipe/passwordless/components/themes/signInUp/phoneForm.tsx
index 0fe9efe43..cf733537c 100644
--- a/lib/ts/recipe/passwordless/components/themes/signInUp/phoneForm.tsx
+++ b/lib/ts/recipe/passwordless/components/themes/signInUp/phoneForm.tsx
@@ -79,6 +79,7 @@ export const PhoneForm = withOverride(
const response = await props.recipeImplementation.createCode({
phoneNumber,
+ // shouldTryLinkingWithSessionUser is set by the fn override
userContext,
});
diff --git a/lib/ts/recipe/passwordless/components/themes/signInUpEPCombo/emailForm.tsx b/lib/ts/recipe/passwordless/components/themes/signInUpEPCombo/emailForm.tsx
index 0fa0c7dc4..06560aa56 100644
--- a/lib/ts/recipe/passwordless/components/themes/signInUpEPCombo/emailForm.tsx
+++ b/lib/ts/recipe/passwordless/components/themes/signInUpEPCombo/emailForm.tsx
@@ -17,6 +17,7 @@ import STGeneralError from "supertokens-web-js/utils/error";
import { withOverride } from "../../../../../components/componentOverride/withOverride";
import { useTranslation } from "../../../../../translation/translationContext";
+import { getTenantIdFromQueryParams } from "../../../../../utils";
import { Label } from "../../../../emailpassword/components/library";
import FormBase from "../../../../emailpassword/components/library/formBase";
import EmailPassword from "../../../../emailpassword/recipe";
@@ -57,7 +58,12 @@ export const EPComboEmailForm = withOverride(
EmailPassword.getInstanceOrThrow().redirect({ action: "RESET_PASSWORD" })}
+ onClick={() =>
+ EmailPassword.getInstanceOrThrow().redirect({
+ action: "RESET_PASSWORD",
+ tenantIdFromQueryParams: getTenantIdFromQueryParams(),
+ })
+ }
data-supertokens="link linkButton formLabelLinkBtn forgotPasswordLink">
{t("PWLESS_COMBO_FORGOT_PW_LINK")}
diff --git a/lib/ts/recipe/passwordless/components/themes/signInUpEPCombo/emailOrPhoneForm.tsx b/lib/ts/recipe/passwordless/components/themes/signInUpEPCombo/emailOrPhoneForm.tsx
index 1dfe55059..30d5b9e85 100644
--- a/lib/ts/recipe/passwordless/components/themes/signInUpEPCombo/emailOrPhoneForm.tsx
+++ b/lib/ts/recipe/passwordless/components/themes/signInUpEPCombo/emailOrPhoneForm.tsx
@@ -19,6 +19,7 @@ import STGeneralError from "supertokens-web-js/utils/error";
import { withOverride } from "../../../../../components/componentOverride/withOverride";
import { useTranslation } from "../../../../../translation/translationContext";
+import { getTenantIdFromQueryParams } from "../../../../../utils";
import { Label } from "../../../../emailpassword/components/library";
import FormBase from "../../../../emailpassword/components/library/formBase";
import EmailPassword from "../../../../emailpassword/recipe";
@@ -107,7 +108,12 @@ export const EPComboEmailOrPhoneForm = withOverride(
EmailPassword.getInstanceOrThrow().redirect({ action: "RESET_PASSWORD" })}
+ onClick={() =>
+ EmailPassword.getInstanceOrThrow().redirect({
+ action: "RESET_PASSWORD",
+ tenantIdFromQueryParams: getTenantIdFromQueryParams(),
+ })
+ }
data-supertokens="link linkButton formLabelLinkBtn forgotPasswordLink">
{t("PWLESS_COMBO_FORGOT_PW_LINK")}
diff --git a/lib/ts/recipe/passwordless/index.ts b/lib/ts/recipe/passwordless/index.ts
index b3276b8e0..89ed3066f 100644
--- a/lib/ts/recipe/passwordless/index.ts
+++ b/lib/ts/recipe/passwordless/index.ts
@@ -40,8 +40,18 @@ export default class Wrapper {
static async createCode(
input:
- | { email: string; userContext?: UserContext; options?: RecipeFunctionOptions }
- | { phoneNumber: string; userContext?: UserContext; options?: RecipeFunctionOptions }
+ | {
+ email: string;
+ shouldTryLinkingWithSessionUser?: boolean;
+ userContext?: UserContext;
+ options?: RecipeFunctionOptions;
+ }
+ | {
+ phoneNumber: string;
+ shouldTryLinkingWithSessionUser?: boolean;
+ userContext?: UserContext;
+ options?: RecipeFunctionOptions;
+ }
): Promise<
| {
status: "OK";
diff --git a/lib/ts/recipe/recipeModule/index.ts b/lib/ts/recipe/recipeModule/index.ts
index c8e0cf3fd..d5db9ce4b 100644
--- a/lib/ts/recipe/recipeModule/index.ts
+++ b/lib/ts/recipe/recipeModule/index.ts
@@ -20,7 +20,7 @@ import { appendQueryParamsToURL, getNormalisedUserContext } from "../../utils";
import { BaseRecipeModule } from "./baseRecipeModule";
import type { NormalisedConfig } from "./types";
-import type { Navigate, UserContext } from "../../types";
+import type { Navigate, NormalisedGetRedirectionURLContext, UserContext } from "../../types";
export default abstract class RecipeModule<
GetRedirectionURLContextType,
@@ -29,7 +29,7 @@ export default abstract class RecipeModule<
N extends NormalisedConfig
> extends BaseRecipeModule {
redirect = async (
- context: GetRedirectionURLContextType,
+ context: NormalisedGetRedirectionURLContext,
navigate?: Navigate,
queryParams?: Record,
userContext?: UserContext
@@ -54,7 +54,7 @@ export default abstract class RecipeModule<
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
getRedirectUrl = async (
- context: GetRedirectionURLContextType,
+ context: NormalisedGetRedirectionURLContext,
userContext: UserContext
): Promise => {
// If getRedirectionURL provided by user.
@@ -68,7 +68,10 @@ export default abstract class RecipeModule<
};
// eslint-disable-next-line @typescript-eslint/no-unused-vars
- async getDefaultRedirectionURL(_: GetRedirectionURLContextType, _userContext: UserContext): Promise {
+ async getDefaultRedirectionURL(
+ _: NormalisedGetRedirectionURLContext,
+ _userContext: UserContext
+ ): Promise {
throw new Error("getDefaultRedirectionURL is not implemented.");
}
}
diff --git a/lib/ts/recipe/recipeModule/types.ts b/lib/ts/recipe/recipeModule/types.ts
index e302fed6e..830451db3 100644
--- a/lib/ts/recipe/recipeModule/types.ts
+++ b/lib/ts/recipe/recipeModule/types.ts
@@ -1,4 +1,4 @@
-import type { UserContext } from "../../types";
+import type { NormalisedGetRedirectionURLContext, UserContext } from "../../types";
export type RecipePreAPIHookContext = {
requestInit: RequestInit;
@@ -25,7 +25,7 @@ export type RecipeOnHandleEventFunction = (context: EventType) => voi
export type UserInput = {
getRedirectionURL?: (
- context: GetRedirectionURLContextType,
+ context: NormalisedGetRedirectionURLContext,
userContext: UserContext
) => Promise;
preAPIHook?: RecipePreAPIHookFunction;
@@ -42,7 +42,7 @@ export type Config = {
getRedirectionURL: (
- context: GetRedirectionURLContextType,
+ context: NormalisedGetRedirectionURLContext,
userContext: UserContext
) => Promise;
onHandleEvent: RecipeOnHandleEventFunction;
diff --git a/lib/ts/recipe/session/recipe.tsx b/lib/ts/recipe/session/recipe.tsx
index 5c628333b..dd2741cc3 100644
--- a/lib/ts/recipe/session/recipe.tsx
+++ b/lib/ts/recipe/session/recipe.tsx
@@ -23,10 +23,12 @@ import SuperTokens from "../../superTokens";
import {
getLocalStorage,
getNormalisedUserContext,
+ getTenantIdFromQueryParams,
isTest,
removeFromLocalStorage,
setLocalStorage,
} from "../../utils";
+import OAuth2Provider from "../oauth2provider/recipe";
import RecipeModule from "../recipeModule";
import {
@@ -41,8 +43,10 @@ import type {
Navigate,
NormalisedAppInfo,
NormalisedConfigWithAppInfoAndRecipeID,
+ NormalisedGetRedirectionURLContext,
RecipeInitResult,
- SuccessRedirectContext,
+ SuccessRedirectContextInApp,
+ SuccessRedirectContextOAuth2,
UserContext,
} from "../../types";
import type { ClaimValidationError, SessionClaimValidator } from "supertokens-web-js/recipe/session";
@@ -126,11 +130,16 @@ export default class Session extends RecipeModule & { recipeId: string }) | undefined,
+ successRedirectContext:
+ | ((Omit | Omit) & {
+ recipeId: string;
+ tenantIdFromQueryParams: string | undefined;
+ })
+ | undefined,
fallbackRecipeId: string,
- redirectToPath?: string,
- userContext?: UserContext,
- navigate?: Navigate
+ redirectToPath: string | undefined,
+ userContext: UserContext | undefined,
+ navigate: Navigate | undefined
): Promise => {
userContext = getNormalisedUserContext(userContext);
// First we check if there is an active session
@@ -202,6 +211,7 @@ export default class Session extends RecipeModule,
+ navigate,
+ {},
+ userContext
+ );
+ }
+
+ if (successRedirectContext.action === "SUCCESS" && redirectToPath !== undefined) {
successRedirectContext.redirectToPath = redirectToPath;
}
return SuperTokens.getInstanceOrThrow().redirect(
- successRedirectContext as SuccessRedirectContext,
+ successRedirectContext as NormalisedGetRedirectionURLContext,
navigate,
{},
userContext
@@ -227,6 +246,7 @@ export default class Session extends RecipeModule => {
+ // We do not use the util here, since we are redirecting outside of the SDK routes
return "/";
};
diff --git a/lib/ts/recipe/thirdparty/components/features/signInAndUp/index.tsx b/lib/ts/recipe/thirdparty/components/features/signInAndUp/index.tsx
index c19ac7f4f..215738113 100644
--- a/lib/ts/recipe/thirdparty/components/features/signInAndUp/index.tsx
+++ b/lib/ts/recipe/thirdparty/components/features/signInAndUp/index.tsx
@@ -27,12 +27,14 @@ import { mergeProviders } from "../../../utils";
import SignInAndUpTheme from "../../themes/signInAndUp";
import type { Navigate, PartialAuthComponentProps, UserContext, WebJSRecipeInterface } from "../../../../../types";
+import type { AuthSuccessContext } from "../../../../authRecipe/types";
import type Recipe from "../../../recipe";
import type { ComponentOverrideMap, SignInAndUpThemeProps } from "../../../types";
import type ThirdPartyWebJS from "supertokens-web-js/recipe/thirdparty";
export function useChildProps(
recipe: Recipe,
+ onAuthSuccess: (successContext: AuthSuccessContext) => Promise,
error: string | undefined,
onError: (err: string) => void,
clearError: () => void,
@@ -57,6 +59,7 @@ export function useChildProps(
}
return {
+ onAuthSuccess,
error,
onError,
clearError,
@@ -84,6 +87,7 @@ type PropType = PartialAuthComponentProps & {
export const SignInAndUpFeature: React.FC = (props) => {
const childProps = useChildProps(
props.recipe,
+ props.onAuthSuccess,
props.error,
props.onError,
props.clearError,
diff --git a/lib/ts/recipe/thirdparty/components/features/signInAndUpCallback/index.tsx b/lib/ts/recipe/thirdparty/components/features/signInAndUpCallback/index.tsx
index 4d9fe7a5f..28dd8feb7 100644
--- a/lib/ts/recipe/thirdparty/components/features/signInAndUpCallback/index.tsx
+++ b/lib/ts/recipe/thirdparty/components/features/signInAndUpCallback/index.tsx
@@ -22,9 +22,10 @@ import { ComponentOverrideContext } from "../../../../../components/componentOve
import FeatureWrapper from "../../../../../components/featureWrapper";
import SuperTokens from "../../../../../superTokens";
import { useUserContext } from "../../../../../usercontext";
-import { useOnMountAPICall, useRethrowInRender } from "../../../../../utils";
+import { getTenantIdFromQueryParams, useOnMountAPICall, useRethrowInRender } from "../../../../../utils";
import { EmailVerificationClaim } from "../../../../emailverification";
import EmailVerification from "../../../../emailverification/recipe";
+import OAuth2Provider from "../../../../oauth2provider/recipe";
import { getInvalidClaimsFromResponse } from "../../../../session";
import Session from "../../../../session/recipe";
import { SignInAndUpCallbackTheme } from "../../themes/signInAndUpCallback";
@@ -104,25 +105,55 @@ const SignInAndUpCallback: React.FC = (props) => {
userContext,
});
const redirectToPath = stateResponse === undefined ? undefined : stateResponse.redirectToPath;
-
- return Session.getInstanceOrThrow()
- .validateGlobalClaimsAndHandleSuccessRedirection(
- {
- action: "SUCCESS",
- createdNewUser: response.createdNewRecipeUser && response.user.loginMethods.length === 1,
- isNewRecipeUser: response.createdNewRecipeUser,
- newSessionCreated:
- payloadAfterCall !== undefined &&
- (payloadBeforeCall === undefined ||
- payloadBeforeCall.sessionHandle !== payloadAfterCall.sessionHandle),
- recipeId: props.recipe.recipeID,
- },
- props.recipe.recipeID,
- redirectToPath,
- userContext,
- props.navigate
- )
- .catch(rethrowInRender);
+ const loginChallenge = stateResponse?.oauth2LoginChallenge;
+
+ const ctx = {
+ createdNewUser: response.createdNewRecipeUser && response.user.loginMethods.length === 1,
+ isNewRecipeUser: response.createdNewRecipeUser,
+ newSessionCreated:
+ payloadAfterCall !== undefined &&
+ (payloadBeforeCall === undefined ||
+ payloadBeforeCall.sessionHandle !== payloadAfterCall.sessionHandle),
+ recipeId: props.recipe.recipeID,
+ tenantIdFromQueryParams: getTenantIdFromQueryParams(),
+ };
+ const oauth2Recipe = OAuth2Provider.getInstance();
+ if (loginChallenge !== undefined && oauth2Recipe !== undefined) {
+ try {
+ const { frontendRedirectTo } = await oauth2Recipe.webJSRecipe.getRedirectURLToContinueOAuthFlow(
+ {
+ loginChallenge,
+ userContext,
+ }
+ );
+ return Session.getInstanceOrThrow().validateGlobalClaimsAndHandleSuccessRedirection(
+ {
+ ...ctx,
+ action: "SUCCESS_OAUTH2",
+ frontendRedirectTo,
+ },
+ props.recipe.recipeID,
+ redirectToPath,
+ userContext,
+ props.navigate
+ );
+ } catch (e: any) {
+ rethrowInRender(e);
+ }
+ } else {
+ return Session.getInstanceOrThrow()
+ .validateGlobalClaimsAndHandleSuccessRedirection(
+ {
+ ...ctx,
+ action: "SUCCESS",
+ },
+ props.recipe.recipeID,
+ redirectToPath,
+ userContext,
+ props.navigate
+ )
+ .catch(rethrowInRender);
+ }
}
},
[props.recipe, props.navigate, userContext]
@@ -139,6 +170,7 @@ const SignInAndUpCallback: React.FC = (props) => {
await evInstance.redirect(
{
action: "VERIFY_EMAIL",
+ tenantIdFromQueryParams: getTenantIdFromQueryParams(),
},
props.navigate,
undefined,
diff --git a/lib/ts/recipe/thirdparty/components/themes/signInAndUp/providersForm.tsx b/lib/ts/recipe/thirdparty/components/themes/signInAndUp/providersForm.tsx
index 2240c395c..824056dee 100644
--- a/lib/ts/recipe/thirdparty/components/themes/signInAndUp/providersForm.tsx
+++ b/lib/ts/recipe/thirdparty/components/themes/signInAndUp/providersForm.tsx
@@ -35,6 +35,7 @@ export const ThirdPartySignInAndUpProvidersForm: React.FC
recipeImplementation: props.recipeImplementation,
thirdPartyId: providerId,
config: props.config,
+ shouldTryLinkingWithSessionUser: false,
userContext,
});
} catch (e) {
diff --git a/lib/ts/recipe/thirdparty/functionOverrides.ts b/lib/ts/recipe/thirdparty/functionOverrides.ts
index 299ce2236..c95f8f51f 100644
--- a/lib/ts/recipe/thirdparty/functionOverrides.ts
+++ b/lib/ts/recipe/thirdparty/functionOverrides.ts
@@ -1,4 +1,4 @@
-import { getRedirectToPathFromURL } from "../../utils";
+import { getQueryParams, getRedirectToPathFromURL } from "../../utils";
import Session from "../session/recipe";
import type { OnHandleEventContext } from "./types";
@@ -49,6 +49,7 @@ export const getFunctionOverrides =
},
setStateAndOtherInfoToStorage: function (input) {
+ const loginChallenge = getQueryParams("loginChallenge") ?? undefined;
return originalImp.setStateAndOtherInfoToStorage<{
rid?: string;
redirectToPath?: string;
@@ -56,6 +57,7 @@ export const getFunctionOverrides =
state: {
...input.state,
rid: recipeId,
+ oauth2LoginChallenge: loginChallenge,
redirectToPath: getRedirectToPathFromURL(),
},
userContext: input.userContext,
diff --git a/lib/ts/recipe/thirdparty/index.ts b/lib/ts/recipe/thirdparty/index.ts
index 126364905..7ef82cf3a 100644
--- a/lib/ts/recipe/thirdparty/index.ts
+++ b/lib/ts/recipe/thirdparty/index.ts
@@ -61,6 +61,7 @@ export default class Wrapper {
static async redirectToThirdPartyLogin(input: {
thirdPartyId: string;
+ shouldTryLinkingWithSessionUser?: boolean;
userContext?: UserContext;
}): Promise<{ status: "OK" | "ERROR" }> {
const recipeInstance: ThirdParty = ThirdParty.getInstanceOrThrow();
@@ -69,6 +70,7 @@ export default class Wrapper {
thirdPartyId: input.thirdPartyId,
config: recipeInstance.config,
userContext: getNormalisedUserContext(input.userContext),
+ shouldTryLinkingWithSessionUser: input.shouldTryLinkingWithSessionUser,
recipeImplementation: recipeInstance.webJSRecipe,
});
}
@@ -86,6 +88,7 @@ export default class Wrapper {
thirdPartyId: string;
frontendRedirectURI: string;
redirectURIOnProviderDashboard?: string;
+ shouldTryLinkingWithSessionUser?: boolean;
userContext?: UserContext;
options?: RecipeFunctionOptions;
}): Promise {
diff --git a/lib/ts/recipe/thirdparty/types.ts b/lib/ts/recipe/thirdparty/types.ts
index dd6658ace..89d177d90 100644
--- a/lib/ts/recipe/thirdparty/types.ts
+++ b/lib/ts/recipe/thirdparty/types.ts
@@ -116,4 +116,5 @@ export type StateObject = WebJsStateObject & {
export type CustomStateProperties = {
rid: string;
redirectToPath: string;
+ oauth2LoginChallenge?: string;
};
diff --git a/lib/ts/recipe/thirdparty/utils.ts b/lib/ts/recipe/thirdparty/utils.ts
index eceb9dd45..d641324b1 100644
--- a/lib/ts/recipe/thirdparty/utils.ts
+++ b/lib/ts/recipe/thirdparty/utils.ts
@@ -130,6 +130,7 @@ export async function redirectToThirdPartyLogin(input: {
thirdPartyId: string;
config: NormalisedConfig;
userContext: UserContext;
+ shouldTryLinkingWithSessionUser: boolean | undefined;
recipeImplementation: WebJSRecipeInterface;
}): Promise<{ status: "OK" | "ERROR" }> {
const loginMethods = await Multitenancy.getInstanceOrThrow().getCurrentDynamicLoginMethods({
@@ -152,6 +153,7 @@ export async function redirectToThirdPartyLogin(input: {
thirdPartyId: input.thirdPartyId,
frontendRedirectURI: provider.getRedirectURL(),
redirectURIOnProviderDashboard: provider.getRedirectURIOnProviderDashboard(),
+ shouldTryLinkingWithSessionUser: input.shouldTryLinkingWithSessionUser,
userContext: input.userContext,
});
diff --git a/lib/ts/styles/styles.css b/lib/ts/styles/styles.css
index da7329534..711e979e6 100644
--- a/lib/ts/styles/styles.css
+++ b/lib/ts/styles/styles.css
@@ -387,6 +387,28 @@
[data-supertokens~="authComponentList"] {
padding-bottom: 20px;
}
+
+[data-supertokens~="authPageTitleOAuthClient"] {
+ color: rgb(var(--palette-textGray));
+ font-size: var(--font-size-1);
+ font-weight: 400;
+ margin: 10px 0 25px;
+}
+
+[data-supertokens~="authPageTitleOAuthClientUrl"] {
+ text-decoration: none;
+}
+
+[data-supertokens~="authPageTitleOAuthClientLogo"] {
+ width: 44px;
+ height: 44px;
+ margin-bottom: 10px;
+}
+
+[data-supertokens~="authPageTitleOAuthClient"] [data-supertokens~="authPageTitleOAuthClientName"] {
+ color: rgb(var(--palette-textTitle));
+}
+
[data-supertokens~="buttonWithArrow"] {
border-radius: 6px;
border: 1px solid #d0d5dd;
diff --git a/lib/ts/superTokens.tsx b/lib/ts/superTokens.tsx
index c0a2416b0..5225bf133 100644
--- a/lib/ts/superTokens.tsx
+++ b/lib/ts/superTokens.tsx
@@ -21,7 +21,7 @@ import { CookieHandlerReference } from "supertokens-web-js/utils/cookieHandler";
import { PostSuperTokensInitCallbacks } from "supertokens-web-js/utils/postSuperTokensInitCallbacks";
import { WindowHandlerReference } from "supertokens-web-js/utils/windowHandler";
-import { SSR_ERROR } from "./constants";
+import { SSR_ERROR, TENANT_ID_QUERY_PARAM } from "./constants";
import { enableLogging, logDebugMessage } from "./logger";
import Multitenancy from "./recipe/multitenancy/recipe";
import { saveCurrentLanguage, TranslationController } from "./translation/translationHelpers";
@@ -32,6 +32,7 @@ import {
getDefaultCookieScope,
getNormalisedUserContext,
getOriginOfPage,
+ getTenantIdFromQueryParams,
isTest,
normaliseCookieScopeOrThrowError,
normaliseInputAppInfoOrThrowError,
@@ -43,7 +44,14 @@ import type RecipeModule from "./recipe/recipeModule";
import type { BaseRecipeModule } from "./recipe/recipeModule/baseRecipeModule";
import type { NormalisedConfig as NormalisedRecipeModuleConfig } from "./recipe/recipeModule/types";
import type { TranslationFunc, TranslationStore } from "./translation/translationHelpers";
-import type { Navigate, GetRedirectionURLContext, NormalisedAppInfo, SuperTokensConfig, UserContext } from "./types";
+import type {
+ Navigate,
+ GetRedirectionURLContext,
+ NormalisedAppInfo,
+ SuperTokensConfig,
+ UserContext,
+ NormalisedGetRedirectionURLContext,
+} from "./types";
/*
* Class.
@@ -183,7 +191,10 @@ export default class SuperTokens {
this.languageTranslations.translationEventSource.emit("TranslationLoaded", store);
}
- async getRedirectUrl(context: GetRedirectionURLContext, userContext: UserContext): Promise {
+ async getRedirectUrl(
+ context: NormalisedGetRedirectionURLContext,
+ userContext: UserContext
+ ): Promise {
if (this.userGetRedirectionURL) {
const userRes = await this.userGetRedirectionURL(context, userContext);
if (userRes !== undefined) {
@@ -192,7 +203,11 @@ export default class SuperTokens {
}
if (context.action === "TO_AUTH") {
const redirectUrl = this.appInfo.websiteBasePath.getAsStringDangerous();
- return appendTrailingSlashToURL(redirectUrl);
+ const basePath = appendTrailingSlashToURL(redirectUrl);
+ if (context.tenantIdFromQueryParams) {
+ return appendQueryParamsToURL(basePath, { [TENANT_ID_QUERY_PARAM]: context.tenantIdFromQueryParams });
+ }
+ return basePath;
} else if (context.action === "SUCCESS") {
return context.redirectToPath ?? "/";
}
@@ -218,6 +233,7 @@ export default class SuperTokens {
{
action: "TO_AUTH",
showSignIn: options.show === "signin",
+ tenantIdFromQueryParams: getTenantIdFromQueryParams(),
},
options.userContext
);
@@ -235,7 +251,7 @@ export default class SuperTokens {
};
redirect = async (
- context: GetRedirectionURLContext,
+ context: NormalisedGetRedirectionURLContext,
navigate?: Navigate,
queryParams?: Record,
userContext?: UserContext
diff --git a/lib/ts/translation/translations.ts b/lib/ts/translation/translations.ts
index b78c4098b..424897019 100644
--- a/lib/ts/translation/translations.ts
+++ b/lib/ts/translation/translations.ts
@@ -3,6 +3,7 @@ export const defaultTranslationsCommon = {
AUTH_PAGE_HEADER_TITLE_SIGN_IN_AND_UP: "Sign Up / Sign In",
AUTH_PAGE_HEADER_TITLE_SIGN_IN: "Sign In",
AUTH_PAGE_HEADER_TITLE_SIGN_UP: "Sign Up",
+ AUTH_PAGE_HEADER_TITLE_SIGN_IN_UP_TO_APP: " to continue to ",
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_START: "Not registered yet?",
AUTH_PAGE_HEADER_SUBTITLE_SIGN_IN_SIGN_UP_LINK: "Sign Up",
diff --git a/lib/ts/types.ts b/lib/ts/types.ts
index ad4b2fff0..118021079 100644
--- a/lib/ts/types.ts
+++ b/lib/ts/types.ts
@@ -14,6 +14,7 @@
*/
import type { DateProviderInput } from "./dateProvider/types";
+import type { AuthSuccessContext } from "./recipe/authRecipe/types";
import type { BaseRecipeModule } from "./recipe/recipeModule/baseRecipeModule";
import type { NormalisedConfig as NormalisedRecipeModuleConfig } from "./recipe/recipeModule/types";
import type { TranslationFunc, TranslationStore } from "./translation/translationHelpers";
@@ -25,7 +26,7 @@ import type NormalisedURLDomain from "supertokens-web-js/utils/normalisedURLDoma
import type NormalisedURLPath from "supertokens-web-js/utils/normalisedURLPath";
import type { WindowHandlerInput } from "supertokens-web-js/utils/windowHandler/types";
-export type SuccessRedirectContext = {
+type SuccessRedirectContextCommon = {
recipeId:
| "emailpassword"
| "thirdparty"
@@ -34,19 +35,26 @@ export type SuccessRedirectContext = {
| "thirdpartyemailpassword"
| "emailverification"
| "totp";
- action: "SUCCESS";
isNewRecipeUser: boolean;
createdNewUser: boolean;
newSessionCreated: boolean;
- redirectToPath?: string;
};
-export type GetRedirectionURLContext =
+export type SuccessRedirectContextInApp = SuccessRedirectContextCommon & { action: "SUCCESS"; redirectToPath?: string };
+export type SuccessRedirectContextOAuth2 = SuccessRedirectContextCommon & {
+ action: "SUCCESS_OAUTH2";
+ frontendRedirectTo: string;
+};
+
+export type SuccessRedirectContext = SuccessRedirectContextInApp | SuccessRedirectContextOAuth2;
+
+export type GetRedirectionURLContext = NormalisedGetRedirectionURLContext<
| {
action: "TO_AUTH";
showSignIn?: boolean;
}
- | SuccessRedirectContext;
+ | SuccessRedirectContextInApp
+>;
export type ValidationFailureCallback =
| (({
@@ -126,7 +134,7 @@ export type SuperTokensConfig = {
};
enableDebugLogs?: boolean;
getRedirectionURL?: (
- context: GetRedirectionURLContext,
+ context: NormalisedGetRedirectionURLContext,
userContext: UserContext
) => Promise;
@@ -415,6 +423,7 @@ export type UserContext = Record;
export type AuthComponentProps = {
setFactorList: (factorIds: string[]) => void;
rebuildAuthPage: () => void;
+ onAuthSuccess: (successContext: AuthSuccessContext) => Promise;
navigate: Navigate | undefined;
userContext: UserContext;
error: string | undefined;
@@ -441,3 +450,6 @@ export type PartialAuthComponent = {
};
export type AuthComponent = PartialAuthComponent | FullPageAuthComponent;
+export type NormalisedGetRedirectionURLContext = RecipeContext & {
+ tenantIdFromQueryParams: string | undefined;
+};
diff --git a/lib/ts/ui/types.ts b/lib/ts/ui/types.ts
index c5d366605..fd7d43094 100644
--- a/lib/ts/ui/types.ts
+++ b/lib/ts/ui/types.ts
@@ -1,6 +1,7 @@
import type { EmailPasswordPreBuiltUI } from "../recipe/emailpassword/prebuiltui";
import type { EmailVerificationPreBuiltUI } from "../recipe/emailverification/prebuiltui";
import type { MultiFactorAuthPreBuiltUI } from "../recipe/multifactorauth/prebuiltui";
+import type { OAuth2ProviderPreBuiltUI } from "../recipe/oauth2provider/prebuiltui";
import type { PasswordlessPreBuiltUI } from "../recipe/passwordless/prebuiltui";
import type { SessionPreBuiltUI } from "../recipe/session/prebuiltui";
import type { ThirdPartyPreBuiltUI } from "../recipe/thirdparty/prebuiltui";
@@ -19,5 +20,6 @@ export type PreBuiltRecipes = (
| typeof EmailVerificationPreBuiltUI
| typeof MultiFactorAuthPreBuiltUI
| typeof TOTPPreBuiltUI
+ | typeof OAuth2ProviderPreBuiltUI
| typeof SessionPreBuiltUI
)[];
diff --git a/lib/ts/utils.ts b/lib/ts/utils.ts
index 3c1a7e58d..30776ce13 100644
--- a/lib/ts/utils.ts
+++ b/lib/ts/utils.ts
@@ -19,7 +19,12 @@ import NormalisedURLDomain from "supertokens-web-js/utils/normalisedURLDomain";
import NormalisedURLPath from "supertokens-web-js/utils/normalisedURLPath";
import { WindowHandlerReference } from "supertokens-web-js/utils/windowHandler";
-import { DEFAULT_API_BASE_PATH, DEFAULT_WEBSITE_BASE_PATH, RECIPE_ID_QUERY_PARAM } from "./constants";
+import {
+ DEFAULT_API_BASE_PATH,
+ DEFAULT_WEBSITE_BASE_PATH,
+ RECIPE_ID_QUERY_PARAM,
+ TENANT_ID_QUERY_PARAM,
+} from "./constants";
import type { FormFieldError } from "./recipe/emailpassword/types";
import type {
@@ -28,6 +33,7 @@ import type {
Navigate,
NormalisedAppInfo,
NormalisedFormField,
+ NormalisedGetRedirectionURLContext,
UserContext,
} from "./types";
@@ -119,6 +125,40 @@ export function getRedirectToPathFromURL(): string | undefined {
}
}
+export function getTenantIdFromQueryParams(): string | undefined {
+ return getQueryParams(TENANT_ID_QUERY_PARAM) ?? undefined;
+}
+
+export function getDefaultRedirectionURLForPath(
+ config: { appInfo: NormalisedAppInfo },
+ defaultPath: string,
+ context: NormalisedGetRedirectionURLContext,
+ extraQueryParams?: Record
+): string {
+ const redirectPath = config.appInfo.websiteBasePath
+ .appendPath(new NormalisedURLPath(defaultPath))
+ .getAsStringDangerous();
+
+ const queryParams = new URLSearchParams();
+ if (context.tenantIdFromQueryParams !== undefined) {
+ queryParams.set(TENANT_ID_QUERY_PARAM, context.tenantIdFromQueryParams);
+ }
+
+ if (extraQueryParams !== undefined) {
+ Object.entries(extraQueryParams).forEach(([key, value]) => {
+ if (value !== undefined) {
+ queryParams.set(key, value);
+ }
+ });
+ }
+
+ if (queryParams.toString() !== "") {
+ return `${redirectPath}?${queryParams.toString()}`;
+ }
+
+ return redirectPath;
+}
+
/*
* isTest
*/
diff --git a/lib/ts/version.ts b/lib/ts/version.ts
index e7e73cd84..1de93fae4 100644
--- a/lib/ts/version.ts
+++ b/lib/ts/version.ts
@@ -12,4 +12,4 @@
* License for the specific language governing permissions and limitations
* under the License.
*/
-export const package_version = "0.47.1";
+export const package_version = "0.49.0";
diff --git a/package-lock.json b/package-lock.json
index 3fe8e0c0f..994cf25d9 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "supertokens-auth-react",
- "version": "0.47.1",
+ "version": "0.49.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "supertokens-auth-react",
- "version": "0.47.1",
+ "version": "0.49.0",
"license": "Apache-2.0",
"dependencies": {
"intl-tel-input": "^17.0.19",
@@ -103,7 +103,7 @@
"peerDependencies": {
"react": ">=16.8.0",
"react-dom": ">=16.8.0",
- "supertokens-web-js": "^0.13.0"
+ "supertokens-web-js": "github:supertokens/supertokens-web-js#0.15"
}
},
"eslint": {
@@ -23889,19 +23889,19 @@
"integrity": "sha512-r0JFBjkMIdep3Lbk3JA+MpnpuOtw4RSyrlRAbrzMcxwiYco3GFWl/daimQZ5b1forOiUODpOlXbSOljP/oyurg=="
},
"node_modules/supertokens-web-js": {
- "version": "0.13.0",
- "resolved": "https://registry.npmjs.org/supertokens-web-js/-/supertokens-web-js-0.13.0.tgz",
- "integrity": "sha512-I0o8Pblu4G1Bopm6c0YI2bZQ/22k5qrjdPFV7etNJ+ydOmNoQPBCo1iY9QbmLANcokyLOaWS5k8jEuwoVh/FYQ==",
+ "version": "0.15.0",
+ "resolved": "git+ssh://git@github.com/supertokens/supertokens-web-js.git#7910f10944829b14dc2c512039f466a566bb8c44",
+ "license": "Apache-2.0",
"peer": true,
"dependencies": {
"supertokens-js-override": "0.0.4",
- "supertokens-website": "^20.0.1"
+ "supertokens-website": "github:supertokens/supertokens-website#20.1"
}
},
"node_modules/supertokens-website": {
- "version": "20.1.1",
- "resolved": "https://registry.npmjs.org/supertokens-website/-/supertokens-website-20.1.1.tgz",
- "integrity": "sha512-AuYp+uOGuUihdrLVVpeB8r8+AJljfqzn8KfiErRgHMPAgxHGbbm2F/+kfi7sudPrh04D6IAfBKxzvKTmJ07w4A==",
+ "version": "20.1.5",
+ "resolved": "git+ssh://git@github.com/supertokens/supertokens-website.git#20c203d8341c5511a1e807991cd00c272e1797bf",
+ "license": "Apache-2.0",
"peer": true,
"dependencies": {
"browser-tabs-lock": "^1.3.0",
@@ -43370,19 +43370,17 @@
"integrity": "sha512-r0JFBjkMIdep3Lbk3JA+MpnpuOtw4RSyrlRAbrzMcxwiYco3GFWl/daimQZ5b1forOiUODpOlXbSOljP/oyurg=="
},
"supertokens-web-js": {
- "version": "0.13.0",
- "resolved": "https://registry.npmjs.org/supertokens-web-js/-/supertokens-web-js-0.13.0.tgz",
- "integrity": "sha512-I0o8Pblu4G1Bopm6c0YI2bZQ/22k5qrjdPFV7etNJ+ydOmNoQPBCo1iY9QbmLANcokyLOaWS5k8jEuwoVh/FYQ==",
+ "version": "git+ssh://git@github.com/supertokens/supertokens-web-js.git#7910f10944829b14dc2c512039f466a566bb8c44",
+ "from": "supertokens-web-js@github:supertokens/supertokens-web-js#0.15",
"peer": true,
"requires": {
"supertokens-js-override": "0.0.4",
- "supertokens-website": "^20.0.1"
+ "supertokens-website": "github:supertokens/supertokens-website#20.1"
}
},
"supertokens-website": {
- "version": "20.1.1",
- "resolved": "https://registry.npmjs.org/supertokens-website/-/supertokens-website-20.1.1.tgz",
- "integrity": "sha512-AuYp+uOGuUihdrLVVpeB8r8+AJljfqzn8KfiErRgHMPAgxHGbbm2F/+kfi7sudPrh04D6IAfBKxzvKTmJ07w4A==",
+ "version": "git+ssh://git@github.com/supertokens/supertokens-website.git#20c203d8341c5511a1e807991cd00c272e1797bf",
+ "from": "supertokens-website@github:supertokens/supertokens-website#20.1",
"peer": true,
"requires": {
"browser-tabs-lock": "^1.3.0",
diff --git a/package.json b/package.json
index add96ed49..e847a78b2 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "supertokens-auth-react",
- "version": "0.47.1",
+ "version": "0.49.0",
"description": "ReactJS SDK that provides login functionality with SuperTokens.",
"main": "./index.js",
"engines": {
@@ -98,7 +98,7 @@
"peerDependencies": {
"react": ">=16.8.0",
"react-dom": ">=16.8.0",
- "supertokens-web-js": "^0.13.0"
+ "supertokens-web-js": "github:supertokens/supertokens-web-js#0.15"
},
"scripts": {
"init": "bash ./init.sh",
@@ -137,19 +137,19 @@
"size-limit": [
{
"path": "lib/build/index.js",
- "limit": "23.5kb"
+ "limit": "25kb"
},
{
"path": "recipe/session/index.js",
- "limit": "24.5kb"
+ "limit": "26kb"
},
{
"path": "recipe/session/prebuiltui.js",
- "limit": "29kb"
+ "limit": "31kb"
},
{
"path": "recipe/thirdparty/index.js",
- "limit": "33kb"
+ "limit": "34kb"
},
{
"path": "recipe/emailpassword/index.js",
@@ -165,19 +165,19 @@
},
{
"path": "recipe/emailverification/prebuiltui.js",
- "limit": "34kb"
+ "limit": "36kb"
},
{
"path": "recipe/thirdparty/prebuiltui.js",
- "limit": "54kb"
+ "limit": "56kb"
},
{
"path": "recipe/emailpassword/prebuiltui.js",
- "limit": "40kb"
+ "limit": "42kb"
},
{
"path": "recipe/passwordless/prebuiltui.js",
- "limit": "130kb"
+ "limit": "132kb"
},
{
"path": "recipe/multitenancy/index.js",
@@ -189,6 +189,14 @@
},
{
"path": "recipe/multifactorauth/prebuiltui.js",
+ "limit": "35kb"
+ },
+ {
+ "path": "recipe/oauth2provider/index.js",
+ "limit": "12kb"
+ },
+ {
+ "path": "recipe/oauth2provider/prebuiltui.js",
"limit": "33kb"
}
],
diff --git a/recipe/oauth2provider/index.d.ts b/recipe/oauth2provider/index.d.ts
new file mode 100644
index 000000000..e7ece88b8
--- /dev/null
+++ b/recipe/oauth2provider/index.d.ts
@@ -0,0 +1,17 @@
+/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved.
+ *
+ * This software is licensed under the Apache License, Version 2.0 (the
+ * "License") as published by the Apache Software Foundation.
+ *
+ * You may not use this file except in compliance with the License. You may
+ * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+export * from "../../lib/build/recipe/oauth2provider";
+import * as _default from "../../lib/build/recipe/oauth2provider";
+export default _default;
diff --git a/recipe/oauth2provider/index.js b/recipe/oauth2provider/index.js
new file mode 100644
index 000000000..5802d3c8e
--- /dev/null
+++ b/recipe/oauth2provider/index.js
@@ -0,0 +1,20 @@
+/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved.
+ *
+ * This software is licensed under the Apache License, Version 2.0 (the
+ * "License") as published by the Apache Software Foundation.
+ *
+ * You may not use this file except in compliance with the License. You may
+ * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+"use strict";
+function __export(m) {
+ for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
+}
+exports.__esModule = true;
+__export(require("../../lib/build/oauth2provider"));
diff --git a/recipe/oauth2provider/prebuiltui.d.ts b/recipe/oauth2provider/prebuiltui.d.ts
new file mode 100644
index 000000000..c983a1551
--- /dev/null
+++ b/recipe/oauth2provider/prebuiltui.d.ts
@@ -0,0 +1,17 @@
+/* Copyright (c) 2024, VRAI Labs and/or its affiliates. All rights reserved.
+ *
+ * This software is licensed under the Apache License, Version 2.0 (the
+ * "License") as published by the Apache Software Foundation.
+ *
+ * You may not use this file except in compliance with the License. You may
+ * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+export * from "../../lib/build/recipe/oauth2provider/prebuiltui";
+import * as _default from "../../lib/build/recipe/oauth2provider/prebuiltui";
+export default _default;
diff --git a/recipe/oauth2provider/prebuiltui.js b/recipe/oauth2provider/prebuiltui.js
new file mode 100644
index 000000000..c5380476f
--- /dev/null
+++ b/recipe/oauth2provider/prebuiltui.js
@@ -0,0 +1,20 @@
+/* Copyright (c) 2024, VRAI Labs and/or its affiliates. All rights reserved.
+ *
+ * This software is licensed under the Apache License, Version 2.0 (the
+ * "License") as published by the Apache Software Foundation.
+ *
+ * You may not use this file except in compliance with the License. You may
+ * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+"use strict";
+function __export(m) {
+ for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
+}
+exports.__esModule = true;
+__export(require("../../lib/build/oauth2providerprebuiltui"));
diff --git a/rollup.config.mjs b/rollup.config.mjs
index e59a7aa1d..8314eab99 100644
--- a/rollup.config.mjs
+++ b/rollup.config.mjs
@@ -25,6 +25,8 @@ export default [
emailpasswordprebuiltui: "lib/ts/recipe/emailpassword/prebuiltui.tsx",
passwordless: "lib/ts/recipe/passwordless/index.ts",
passwordlessprebuiltui: "lib/ts/recipe/passwordless/prebuiltui.tsx",
+ oauth2provider: "lib/ts/recipe/oauth2provider/index.ts",
+ oauth2providerprebuiltui: "lib/ts/recipe/oauth2provider/prebuiltui.tsx",
thirdparty: "lib/ts/recipe/thirdparty/index.ts",
thirdpartyprebuiltui: "lib/ts/recipe/thirdparty/prebuiltui.tsx",
multitenancy: "lib/ts/recipe/multitenancy/index.ts",
diff --git a/stories/allrecipes.stories.tsx b/stories/allrecipes.stories.tsx
index 6b13ea26f..d096ab495 100644
--- a/stories/allrecipes.stories.tsx
+++ b/stories/allrecipes.stories.tsx
@@ -141,6 +141,17 @@ export const ResetPasswordLinkClicked: Story = {
},
};
+export const OAuth2Login: Story = {
+ args: {
+ path: "/auth",
+ query: "loginChallenge=asdf",
+ "oauth2.initialized": true,
+ "oauth2.clientName": "Google",
+ "oauth2.logoUri": "https://upload.wikimedia.org/wikipedia/commons/c/c1/Google_%22G%22_logo.svg",
+ "oauth2.clientUri": "https://google.com",
+ },
+};
+
export const ContactFormCombined: Story = {
args: {
"multifactorauth.firstFactors": ["thirdparty", "emailpassword", "otp-email", "otp-phone"],
diff --git a/stories/authPage.stories.tsx b/stories/authPage.stories.tsx
index 63618e908..0cbb59f7b 100644
--- a/stories/authPage.stories.tsx
+++ b/stories/authPage.stories.tsx
@@ -20,6 +20,10 @@ export type Args = {
"passwordless.initialized": boolean;
"passwordless.contactMethod": "PHONE" | "EMAIL" | "EMAIL_OR_PHONE";
"passwordless.defaultToEmail": boolean;
+ "oauth2.initialized": boolean;
+ "oauth2.clientName": string;
+ "oauth2.logoUri": string;
+ "oauth2.clientUri": string;
path?: string;
query?: string;
hash?: string;
@@ -104,6 +108,10 @@ const meta: Meta = {
"passwordless.contactMethod": "EMAIL_OR_PHONE",
"passwordless.defaultToEmail": true,
rootStyle: "",
+ "oauth2.initialized": true,
+ "oauth2.clientName": "My App",
+ "oauth2.logoUri": "https://example.com/logo.png",
+ "oauth2.clientUri": "https://example.com",
},
argTypes: {
"multifactorauth.initialized": {
@@ -211,6 +219,38 @@ const meta: Meta = {
truthy: true,
},
},
+ "oauth2.initialized": {
+ table: {
+ category: "oauth2",
+ },
+ },
+ "oauth2.clientName": {
+ table: {
+ category: "oauth2",
+ },
+ if: {
+ arg: "oauth2.initialized",
+ truthy: true,
+ },
+ },
+ "oauth2.logoUri": {
+ table: {
+ category: "oauth2",
+ },
+ if: {
+ arg: "oauth2.initialized",
+ truthy: true,
+ },
+ },
+ "oauth2.clientUri": {
+ table: {
+ category: "oauth2",
+ },
+ if: {
+ arg: "oauth2.initialized",
+ truthy: true,
+ },
+ },
},
};
diff --git a/stories/oauth2provider.stories.tsx b/stories/oauth2provider.stories.tsx
new file mode 100644
index 000000000..68c839ad3
--- /dev/null
+++ b/stories/oauth2provider.stories.tsx
@@ -0,0 +1,81 @@
+import type { Meta, StoryObj } from "@storybook/react";
+
+import { OAuth2LogoutScreenTheme as Page } from "../lib/ts/recipe/oauth2provider/components/themes/oauth2LogoutScreen";
+import React from "react";
+import { defaultTranslationsOAuth2Provider } from "../lib/ts/recipe/oauth2provider/components/themes/translations";
+import { WindowHandlerReference } from "supertokens-web-js/utils/windowHandler";
+import { TranslationContextProvider } from "../lib/ts/translation/translationContext";
+import { ComponentOverrideContext } from "../lib/ts/components/componentOverride/componentOverrideContext";
+import { resetAndInitST } from "./utils";
+import { SessionContext } from "../lib/ts/recipe/session";
+
+function noop() {}
+WindowHandlerReference.init((oI) => ({ ...oI }));
+
+const defaultSessionContext = {
+ loading: false,
+ doesSessionExist: true,
+ invalidClaims: [],
+ accessTokenPayload: {},
+ userId: "test-user",
+};
+
+const meta: Meta = {
+ title: "OAuth2Provider",
+ decorators: [
+ (Story, context) => {
+ return (
+
+
+
+
+
+
+
+ );
+ },
+ ],
+ component: Page,
+ render: (args, ctx) => {
+ resetAndInitST();
+ return ;
+ },
+ argTypes: {
+ config: { table: { disable: true } },
+ },
+ args: {
+ showSpinner: false,
+ isLoggingOut: false,
+ config: {
+ oauth2LogoutScreen: { style: "" },
+ } as any, // We don't use any config values
+ },
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const OAuth2LogoutScreen: Story = {
+ parameters: {
+ design: {
+ type: "figma",
+ url: "https://www.figma.com/design/FlU5eMznAw68y5XU3pRVyZ/Homepage-and-pricing-page?node-id=5018-33&t=u8hfT9V6cJ7b7qEL-0",
+ },
+ },
+ args: {},
+};
+
+export const OAuth2LogoutScreenSpinner: Story = {
+ parameters: {
+ design: {
+ type: "figma",
+ url: "https://www.figma.com/design/FlU5eMznAw68y5XU3pRVyZ/Homepage-and-pricing-page?node-id=5018-33&t=u8hfT9V6cJ7b7qEL-0",
+ },
+ },
+ args: {
+ showSpinner: true,
+ },
+};
diff --git a/stories/utils.ts b/stories/utils.ts
index 16dcdee89..a1ebed743 100644
--- a/stories/utils.ts
+++ b/stories/utils.ts
@@ -29,6 +29,7 @@ import SuperTokensWebJS from "supertokens-web-js/lib/build/supertokens";
import { AdditionalLoginAttemptInfoProperties, LoginAttemptInfo } from "../lib/ts/recipe/passwordless/types";
import { WindowHandlerReference } from "supertokens-web-js/utils/windowHandler";
import { PostSuperTokensInitCallbacks } from "supertokens-web-js/utils/postSuperTokensInitCallbacks";
+import OAuth2Provider from "../lib/ts/recipe/oauth2provider/recipe";
export function withFetchResponse(resp: T): T & { fetchResponse: Response } {
return resp as any;
@@ -125,6 +126,12 @@ export type AuthPageConf = {
firstFactors: FirstFactor[];
providers: ProviderId[];
};
+ oauth2: {
+ initialized: boolean;
+ clientName: string;
+ logoUri: string;
+ clientUri: string;
+ };
};
export function buildInit(args: AuthPageConf, funcOverrides: any) {
@@ -213,6 +220,29 @@ export function buildInit(args: AuthPageConf, funcOverrides: any) {
);
}
+ if (args.oauth2.initialized) {
+ recipeList.push(
+ OAuth2Provider.init({
+ override: {
+ functions: (oI) => ({
+ ...oI,
+ getLoginChallengeInfo: async () => {
+ return {
+ status: "OK",
+ info: {
+ clientName: args.oauth2.clientName,
+ logoUri: args.oauth2.logoUri || undefined,
+ clientUri: args.oauth2.clientUri || undefined,
+ },
+ fetchResponse: undefined as any,
+ };
+ },
+ }),
+ },
+ }) as any
+ );
+ }
+
return {
useShadowDom: false,
defaultToSignUp: args.defaultToSignUp,
diff --git a/test/end-to-end/accountlinking.test.js b/test/end-to-end/accountlinking.test.js
index 0b23079d4..92bedc11e 100644
--- a/test/end-to-end/accountlinking.test.js
+++ b/test/end-to-end/accountlinking.test.js
@@ -45,6 +45,7 @@ import {
sendEmailResetPasswordSuccessMessage,
changeEmail,
backendBeforeEach,
+ setupBrowser,
} from "../helpers";
import { TEST_CLIENT_BASE_URL, TEST_SERVER_BASE_URL, SIGN_IN_UP_API, RESET_PASSWORD_API } from "../constants";
@@ -71,10 +72,7 @@ describe("SuperTokens Account linking", function () {
method: "POST",
}).catch(console.error);
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
- headless: true,
- });
+ browser = await setupBrowser();
page = await browser.newPage();
page.on("console", (consoleObj) => {
const log = consoleObj.text();
diff --git a/test/end-to-end/emailverification.test.js b/test/end-to-end/emailverification.test.js
index 468a80ea5..3c4b89035 100644
--- a/test/end-to-end/emailverification.test.js
+++ b/test/end-to-end/emailverification.test.js
@@ -55,6 +55,7 @@ import {
getDefaultSignUpFieldValues,
getTestEmail,
waitForUrl,
+ setupBrowser,
} from "../helpers";
describe("SuperTokens Email Verification", function () {
@@ -68,10 +69,7 @@ describe("SuperTokens Email Verification", function () {
await fetch(`${TEST_SERVER_BASE_URL}/startst`, {
method: "POST",
}).catch(console.error);
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
- headless: true,
- });
+ browser = await setupBrowser();
accountLinkingSupported = await isAccountLinkingSupported();
page = await browser.newPage();
@@ -104,6 +102,7 @@ describe("SuperTokens Email Verification", function () {
consoleLogs = [];
page.on("console", (consoleObj) => {
const log = consoleObj.text();
+ // console.log(log);
if (log.startsWith("ST_LOGS")) {
consoleLogs.push(log);
}
@@ -618,10 +617,7 @@ describe("SuperTokens Email Verification server errors", function () {
let consoleLogs;
before(async function () {
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
- headless: true,
- });
+ browser = await setupBrowser();
page = await browser.newPage();
await page.goto(`${TEST_CLIENT_BASE_URL}/auth?mode=REQUIRED`);
});
@@ -675,10 +671,7 @@ describe("SuperTokens Email Verification general errors", function () {
await fetch(`${TEST_SERVER_BASE_URL}/startst`, {
method: "POST",
}).catch(console.error);
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
- headless: true,
- });
+ browser = await setupBrowser();
page = await browser.newPage();
await Promise.all([
page.goto(`${TEST_CLIENT_BASE_URL}/auth?mode=REQUIRED`),
@@ -786,10 +779,7 @@ describe("SuperTokens Email Verification isEmailVerified server error", function
await fetch(`${TEST_SERVER_BASE_URL}/startst`, {
method: "POST",
}).catch(console.error);
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
- headless: true,
- });
+ browser = await setupBrowser();
});
after(async function () {
@@ -866,10 +856,7 @@ describe("Email verification signOut errors", function () {
method: "POST",
}).catch(console.error);
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
- headless: true,
- });
+ browser = await setupBrowser();
});
after(async function () {
@@ -952,10 +939,7 @@ describe("Email verification claim refresh with clock skew", function () {
}),
}).catch(console.error);
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
- headless: true,
- });
+ browser = await setupBrowser();
});
after(async function () {
diff --git a/test/end-to-end/embed.test.js b/test/end-to-end/embed.test.js
index e5a335334..1ca49a76a 100644
--- a/test/end-to-end/embed.test.js
+++ b/test/end-to-end/embed.test.js
@@ -5,17 +5,19 @@ import { TEST_SERVER_BASE_URL } from "../constants";
import { AuthPage } from "./pages/AuthPage";
import { EmailVerificationPage } from "./pages/EmailVerificationPage";
import { ResetPasswordPage } from "./pages/ResetPasswordPage";
-import { backendBeforeEach, clearBrowserCookiesWithoutAffectingConsole, screenshotOnFailure } from "../helpers";
+import {
+ backendBeforeEach,
+ clearBrowserCookiesWithoutAffectingConsole,
+ screenshotOnFailure,
+ setupBrowser,
+} from "../helpers";
describe("Embed components", async () => {
let browser;
let page;
before(async function () {
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
- headless: true,
- });
+ browser = await setupBrowser();
await backendBeforeEach();
await fetch(`${TEST_SERVER_BASE_URL}/startst`, {
diff --git a/test/end-to-end/generalerror.test.js b/test/end-to-end/generalerror.test.js
index 10160aebd..1100c0150 100644
--- a/test/end-to-end/generalerror.test.js
+++ b/test/end-to-end/generalerror.test.js
@@ -42,6 +42,7 @@ import {
setGeneralErrorToLocalStorage,
backendBeforeEach,
waitForUrl,
+ setupBrowser,
} from "../helpers";
import {
@@ -78,10 +79,7 @@ describe("General error rendering", function () {
method: "POST",
}).catch(console.error);
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
- headless: true,
- });
+ browser = await setupBrowser();
});
after(async function () {
@@ -175,7 +173,7 @@ describe("General error rendering", function () {
{ name: "name", value: "John Doe" },
{ name: "age", value: "20" },
],
- '{"formFields":[{"id":"email","value":"john.doe2@supertokens.io"},{"id":"password","value":"Str0ngP@ssw0rd"},{"id":"name","value":"John Doe"},{"id":"age","value":"20"},{"id":"country","value":""}]}',
+ '{"formFields":[{"id":"email","value":"john.doe2@supertokens.io"},{"id":"password","value":"Str0ngP@ssw0rd"},{"id":"name","value":"John Doe"},{"id":"age","value":"20"},{"id":"country","value":""}],"shouldTryLinkingWithSessionUser":false}',
rid
);
@@ -240,10 +238,7 @@ function getEmailPasswordTests(rid, ridForStorage) {
method: "POST",
}).catch(console.error);
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
- headless: true,
- });
+ browser = await setupBrowser();
});
after(async function () {
@@ -378,10 +373,7 @@ function getThirdPartyTests(rid, ridForStorage) {
method: "POST",
}).catch(console.error);
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
- headless: true,
- });
+ browser = await setupBrowser();
});
after(async function () {
diff --git a/test/end-to-end/getRedirectionURL.test.js b/test/end-to-end/getRedirectionURL.test.js
index fa0304c82..f491f7ad9 100644
--- a/test/end-to-end/getRedirectionURL.test.js
+++ b/test/end-to-end/getRedirectionURL.test.js
@@ -17,6 +17,7 @@ import {
isPasswordlessSupported,
isThirdPartyPasswordlessSupported,
backendBeforeEach,
+ setupBrowser,
} from "../helpers";
import {
@@ -38,10 +39,7 @@ describe("getRedirectionURL Tests", function () {
method: "POST",
}).catch(console.error);
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
- headless: true,
- });
+ browser = await setupBrowser();
});
after(async function () {
@@ -86,10 +84,7 @@ describe("getRedirectionURL Tests", function () {
method: "POST",
}).catch(console.error);
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
- headless: true,
- });
+ browser = await setupBrowser();
page = await browser.newPage();
await page.goto(`${TEST_CLIENT_BASE_URL}/auth?authRecipe=thirdparty`);
});
@@ -139,10 +134,7 @@ describe("getRedirectionURL Tests", function () {
method: "POST",
}).catch(console.error);
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
- headless: true,
- });
+ browser = await setupBrowser();
page = await browser.newPage();
});
@@ -216,10 +208,7 @@ describe("getRedirectionURL Tests", function () {
}),
}).catch(console.error);
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
- headless: true,
- });
+ browser = await setupBrowser();
page = await browser.newPage();
await Promise.all([
page.goto(
@@ -303,10 +292,7 @@ describe("getRedirectionURL Tests", function () {
}),
}).catch(console.error);
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
- headless: true,
- });
+ browser = await setupBrowser();
page = await browser.newPage();
await Promise.all([
page.goto(
@@ -390,10 +376,7 @@ describe("getRedirectionURL Tests", function () {
method: "POST",
}).catch(console.error);
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
- headless: true,
- });
+ browser = await setupBrowser();
page = await browser.newPage();
// We need to set the localStorage value before the page loads to ensure ST initialises with the correct value
@@ -464,10 +447,7 @@ describe("getRedirectionURL Tests", function () {
}),
}).catch(console.error);
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
- headless: true,
- });
+ browser = await setupBrowser();
page = await browser.newPage();
// We need to set the localStorage value before the page loads to ensure ST initialises with the correct value
await page.evaluateOnNewDocument(() => {
@@ -557,10 +537,7 @@ describe("getRedirectionURL Tests", function () {
}),
}).catch(console.error);
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
- headless: true,
- });
+ browser = await setupBrowser();
page = await browser.newPage();
// We need to set the localStorage value before the page loads to ensure ST initialises with the correct value
await page.evaluateOnNewDocument(() => {
@@ -632,10 +609,7 @@ describe("getRedirectionURL Tests", function () {
method: "POST",
}).catch(console.error);
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
- headless: true,
- });
+ browser = await setupBrowser();
page = await browser.newPage();
// We need to set the localStorage value before the page loads to ensure ST initialises with the correct value
diff --git a/test/end-to-end/mfa.chooserscreen.test.js b/test/end-to-end/mfa.chooserscreen.test.js
index 3fab733b6..cb14c1d70 100644
--- a/test/end-to-end/mfa.chooserscreen.test.js
+++ b/test/end-to-end/mfa.chooserscreen.test.js
@@ -33,6 +33,7 @@ import {
setAccountLinkingConfig,
isMFASupported,
expectErrorThrown,
+ setupBrowser,
} from "../helpers";
import fetch from "isomorphic-fetch";
import { CREATE_CODE_API, CREATE_TOTP_DEVICE_API, MFA_INFO_API } from "../constants";
@@ -80,10 +81,7 @@ describe("SuperTokens SignIn w/ MFA", function () {
}).catch(console.error);
await setAccountLinkingConfig(true, true, false);
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
- headless: true,
- });
+ browser = await setupBrowser();
});
after(async function () {
diff --git a/test/end-to-end/mfa.default_reqs.test.js b/test/end-to-end/mfa.default_reqs.test.js
index ab1fda1d3..04e150bf8 100644
--- a/test/end-to-end/mfa.default_reqs.test.js
+++ b/test/end-to-end/mfa.default_reqs.test.js
@@ -32,6 +32,7 @@ import {
getFactorChooserOptions,
setAccountLinkingConfig,
isMFASupported,
+ setupBrowser,
} from "../helpers";
import fetch from "isomorphic-fetch";
import { CREATE_CODE_API, CREATE_TOTP_DEVICE_API, MFA_INFO_API, TEST_APPLICATION_SERVER_BASE_URL } from "../constants";
@@ -80,10 +81,7 @@ describe("SuperTokens SignIn w/ MFA", function () {
}).catch(console.error);
await setAccountLinkingConfig(true, true, false);
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
- headless: true,
- });
+ browser = await setupBrowser();
});
after(async function () {
diff --git a/test/end-to-end/mfa.factorscreen.otp.test.js b/test/end-to-end/mfa.factorscreen.otp.test.js
index 53d9dba6c..6632126ab 100644
--- a/test/end-to-end/mfa.factorscreen.otp.test.js
+++ b/test/end-to-end/mfa.factorscreen.otp.test.js
@@ -34,6 +34,7 @@ import {
isMFASupported,
setAccountLinkingConfig,
waitForUrl,
+ setupBrowser,
} from "../helpers";
import fetch from "isomorphic-fetch";
import {
@@ -87,10 +88,7 @@ describe("SuperTokens SignIn w/ MFA", function () {
}).catch(console.error);
await setAccountLinkingConfig(true, true, false);
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
- headless: true,
- });
+ browser = await setupBrowser();
});
after(async function () {
diff --git a/test/end-to-end/mfa.factorscreen.totp.test.js b/test/end-to-end/mfa.factorscreen.totp.test.js
index 87ea80bab..aafdc6398 100644
--- a/test/end-to-end/mfa.factorscreen.totp.test.js
+++ b/test/end-to-end/mfa.factorscreen.totp.test.js
@@ -33,6 +33,7 @@ import {
isMFASupported,
setAccountLinkingConfig,
waitForUrl,
+ setupBrowser,
} from "../helpers";
import fetch from "isomorphic-fetch";
import { CREATE_CODE_API, CREATE_TOTP_DEVICE_API, MFA_INFO_API } from "../constants";
@@ -81,10 +82,7 @@ describe("SuperTokens SignIn w/ MFA", function () {
}).catch(console.error);
await setAccountLinkingConfig(true, true, false);
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
- headless: true,
- });
+ browser = await setupBrowser();
});
after(async function () {
diff --git a/test/end-to-end/mfa.firstFactors.test.js b/test/end-to-end/mfa.firstFactors.test.js
index a9e597c9a..c3cdd2fcf 100644
--- a/test/end-to-end/mfa.firstFactors.test.js
+++ b/test/end-to-end/mfa.firstFactors.test.js
@@ -28,6 +28,7 @@ import {
submitForm,
isMFASupported,
setAccountLinkingConfig,
+ setupBrowser,
} from "../helpers";
import fetch from "isomorphic-fetch";
@@ -56,10 +57,7 @@ describe("SuperTokens MFA firstFactors support", function () {
}).catch(console.error);
await setAccountLinkingConfig(true, true, false);
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
- headless: true,
- });
+ browser = await setupBrowser();
});
after(async function () {
diff --git a/test/end-to-end/mfa.requirement_handling.test.js b/test/end-to-end/mfa.requirement_handling.test.js
index 347ed2db8..e170f1e45 100644
--- a/test/end-to-end/mfa.requirement_handling.test.js
+++ b/test/end-to-end/mfa.requirement_handling.test.js
@@ -32,6 +32,7 @@ import {
getFactorChooserOptions,
setAccountLinkingConfig,
isMFASupported,
+ setupBrowser,
} from "../helpers";
import fetch from "isomorphic-fetch";
import { CREATE_CODE_API, CREATE_TOTP_DEVICE_API, MFA_INFO_API } from "../constants";
@@ -78,10 +79,7 @@ describe("SuperTokens SignIn w/ MFA", function () {
method: "POST",
}).catch(console.error);
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
- headless: true,
- });
+ browser = await setupBrowser();
});
after(async function () {
diff --git a/test/end-to-end/mfa.signin.test.js b/test/end-to-end/mfa.signin.test.js
index 9e9d0da92..364f234a5 100644
--- a/test/end-to-end/mfa.signin.test.js
+++ b/test/end-to-end/mfa.signin.test.js
@@ -33,6 +33,7 @@ import {
setAccountLinkingConfig,
expectErrorThrown,
waitForUrl,
+ setupBrowser,
} from "../helpers";
import fetch from "isomorphic-fetch";
import { CREATE_CODE_API, CREATE_TOTP_DEVICE_API, MFA_INFO_API } from "../constants";
@@ -81,10 +82,7 @@ describe("SuperTokens SignIn w/ MFA", function () {
await setAccountLinkingConfig(true, true, false);
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
- headless: true,
- });
+ browser = await setupBrowser();
});
after(async function () {
diff --git a/test/end-to-end/multitenancy.dynamic_login_methods.test.js b/test/end-to-end/multitenancy.dynamic_login_methods.test.js
index 210a6864c..6364161fd 100644
--- a/test/end-to-end/multitenancy.dynamic_login_methods.test.js
+++ b/test/end-to-end/multitenancy.dynamic_login_methods.test.js
@@ -40,6 +40,7 @@ import {
setupTenant,
backendBeforeEach,
getTextByDataSupertokens,
+ setupBrowser,
} from "../helpers";
import {
TEST_CLIENT_BASE_URL,
@@ -106,10 +107,7 @@ describe("SuperTokens Multitenancy dynamic login methods", function () {
});
before(async () => {
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox", "--disable-web-security"],
- headless: true,
- });
+ browser = await setupBrowser();
});
after(async function () {
diff --git a/test/end-to-end/multitenancy.mock.test.js b/test/end-to-end/multitenancy.mock.test.js
index 2e479ddb9..34b56121f 100644
--- a/test/end-to-end/multitenancy.mock.test.js
+++ b/test/end-to-end/multitenancy.mock.test.js
@@ -28,6 +28,7 @@ import {
assertNoSTComponents,
assertProviders,
getProviderLogoCount,
+ setupBrowser,
} from "../helpers";
import { TEST_CLIENT_BASE_URL, DEFAULT_WEBSITE_BASE_PATH, ST_ROOT_SELECTOR } from "../constants";
import { before } from "mocha";
@@ -64,10 +65,7 @@ describe.skip("SuperTokens Multitenancy w/ mocked login methods", function () {
});
before(async () => {
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox", "--disable-web-security"],
- headless: true,
- });
+ browser = await setupBrowser();
});
after(async function () {
diff --git a/test/end-to-end/multitenancy.tenant_interactions.test.js b/test/end-to-end/multitenancy.tenant_interactions.test.js
index 57a1bb33f..bceeaedc7 100644
--- a/test/end-to-end/multitenancy.tenant_interactions.test.js
+++ b/test/end-to-end/multitenancy.tenant_interactions.test.js
@@ -47,6 +47,7 @@ import {
removeTenant,
backendBeforeEach,
waitForUrl,
+ setupBrowser,
} from "../helpers";
import {
TEST_CLIENT_BASE_URL,
@@ -117,10 +118,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
});
before(async () => {
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox", "--disable-web-security"],
- headless: true,
- });
+ browser = await setupBrowser();
});
after(async function () {
diff --git a/test/end-to-end/oauth2provider.test.js b/test/end-to-end/oauth2provider.test.js
new file mode 100644
index 000000000..4e2a052f8
--- /dev/null
+++ b/test/end-to-end/oauth2provider.test.js
@@ -0,0 +1,667 @@
+/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved.
+ *
+ * This software is licensed under the Apache License, Version 2.0 (the
+ * "License") as published by the Apache Software Foundation.
+ *
+ * You may not use this file except in compliance with the License. You may
+ * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*
+ * Imports
+ */
+
+import assert from "assert";
+import puppeteer from "puppeteer";
+import {
+ clearBrowserCookiesWithoutAffectingConsole,
+ toggleSignInSignUp,
+ screenshotOnFailure,
+ backendBeforeEach,
+ waitForUrl,
+ createOAuth2Client,
+ setOAuth2ClientInfo,
+ removeOAuth2ClientInfo,
+ getOAuth2LoginButton,
+ getOAuth2LogoutButton,
+ getOAuth2TokenData,
+ isReact16,
+ waitFor,
+ signUp,
+ getDefaultSignUpFieldValues,
+ getTestEmail,
+ getOAuth2Error,
+ waitForSTElement,
+ isOauth2Supported,
+ setupBrowser,
+} from "../helpers";
+import fetch from "isomorphic-fetch";
+
+import {
+ TEST_CLIENT_BASE_URL,
+ TEST_SERVER_BASE_URL,
+ SIGN_OUT_API,
+ TEST_APPLICATION_SERVER_BASE_URL,
+} from "../constants";
+
+// We do no thave to use a separate domain for the oauth2 client, since the way we are testing
+// the lib doesn't interact with the supertokens session handling.
+// Using a redirection uri that has the same domain as the auth portal shouldn't affect the test.
+
+/*
+ * Tests.
+ */
+describe("SuperTokens OAuth2Provider", function () {
+ let browser;
+ let page;
+ let consoleLogs = [];
+ let skipped = false;
+
+ before(async function () {
+ // Skip these tests if running in React 16
+ if (isReact16() || !(await isOauth2Supported())) {
+ skipped = true;
+ this.skip();
+ }
+
+ await backendBeforeEach();
+
+ await fetch(`${TEST_SERVER_BASE_URL}/startst`, {
+ method: "POST",
+ headers: { "content-type": "application/json" },
+ body: JSON.stringify({
+ coreConfig: {
+ access_token_validity: 5, // 5 seconds
+ },
+ }),
+ }).catch(console.error);
+
+ browser = await setupBrowser();
+ });
+
+ after(async function () {
+ if (skipped) {
+ return;
+ }
+ await browser.close();
+
+ await fetch(`${TEST_SERVER_BASE_URL}/after`, {
+ method: "POST",
+ }).catch(console.error);
+
+ await fetch(`${TEST_SERVER_BASE_URL}/stopst`, {
+ method: "POST",
+ }).catch(console.error);
+ });
+
+ afterEach(function () {
+ return screenshotOnFailure(this, browser);
+ });
+
+ beforeEach(async function () {
+ page = await browser.newPage();
+ page.on("console", (consoleObj) => {
+ const log = consoleObj.text();
+ if (log.startsWith("ST_LOGS")) {
+ consoleLogs.push(log);
+ }
+ });
+ consoleLogs = await clearBrowserCookiesWithoutAffectingConsole(page, []);
+ });
+
+ describe("Generic OAuth2 Client Library", function () {
+ afterEach(async function () {
+ await removeOAuth2ClientInfo(page);
+ });
+
+ it("should successfully complete the OAuth2 flow", async function () {
+ const { client } = await createOAuth2Client({
+ scope: "offline_access profile openid email",
+ redirectUris: [`${TEST_CLIENT_BASE_URL}/oauth/callback`],
+ tokenEndpointAuthMethod: "none",
+ grantTypes: ["authorization_code", "refresh_token"],
+ responseTypes: ["code", "id_token"],
+ });
+
+ await setOAuth2ClientInfo(page, client.clientId);
+
+ await Promise.all([
+ page.waitForNavigation({ waitUntil: "networkidle0" }),
+ page.goto(`${TEST_CLIENT_BASE_URL}/oauth/login`),
+ ]);
+
+ let loginButton = await getOAuth2LoginButton(page);
+ await loginButton.click();
+
+ await waitForUrl(page, "/auth");
+
+ await toggleSignInSignUp(page);
+ const { fieldValues, postValues } = getDefaultSignUpFieldValues({ email: getTestEmail() });
+ await signUp(page, fieldValues, postValues, "emailpassword");
+
+ await waitForUrl(page, "/oauth/callback");
+
+ // Validate token data
+ const tokenData = await getOAuth2TokenData(page);
+ assert.deepStrictEqual(tokenData.aud, client.clientId);
+
+ // Logout
+ const logoutButton = await getOAuth2LogoutButton(page);
+ await logoutButton.click();
+
+ await waitFor(1000);
+
+ await page.waitForSelector("#oauth2-token-data", { hidden: true });
+
+ // Ensure the Login Button is visible after logout is clicked
+ loginButton = await getOAuth2LoginButton(page);
+ await loginButton.click();
+ await waitForUrl(page, "/oauth/callback");
+ });
+
+ it("should successfully complete the OAuth2 Logout flow", async function () {
+ const postLogoutRedirectUri = `${TEST_CLIENT_BASE_URL}/oauth/login?logout=true`;
+
+ const { client } = await createOAuth2Client({
+ scope: "offline_access profile openid email",
+ redirectUris: [`${TEST_CLIENT_BASE_URL}/oauth/callback`],
+ postLogoutRedirectUris: [postLogoutRedirectUri],
+ accessTokenStrategy: "jwt",
+ tokenEndpointAuthMethod: "none",
+ grantTypes: ["authorization_code", "refresh_token"],
+ responseTypes: ["code", "id_token"],
+ skipConsent: true,
+ });
+
+ await setOAuth2ClientInfo(
+ page,
+ client.clientId,
+ undefined,
+ undefined,
+ undefined,
+ JSON.stringify({
+ post_logout_redirect_uri: postLogoutRedirectUri,
+ })
+ );
+
+ await Promise.all([
+ page.waitForNavigation({ waitUntil: "networkidle0" }),
+ page.goto(`${TEST_CLIENT_BASE_URL}/oauth/login`),
+ ]);
+
+ let loginButton = await getOAuth2LoginButton(page);
+ await loginButton.click();
+
+ await waitForUrl(page, "/auth");
+
+ await toggleSignInSignUp(page);
+ const { fieldValues, postValues } = getDefaultSignUpFieldValues({ email: getTestEmail() });
+ await signUp(page, fieldValues, postValues, "emailpassword");
+
+ await waitForUrl(page, "/oauth/callback");
+
+ // Logout
+ const logoutButton = await getOAuth2LogoutButton(page, "redirect");
+ await logoutButton.click();
+
+ await waitForUrl(page, "/auth/oauth/logout");
+
+ // Click the Logout button on the provider website
+ const stLogoutButton = await waitForSTElement(page, "[data-supertokens~=button]");
+ await stLogoutButton.click();
+
+ // Ensure the final url matches the post_logout_redirect uri
+ await waitForUrl(page, "/oauth/login?logout=true", false);
+
+ await page.waitForSelector("#oauth2-token-data", { hidden: true });
+
+ // Ensure that the SuperTokens session was cleared by checking for a redirect to the provider's auth page during the login flow.
+ loginButton = await getOAuth2LoginButton(page);
+ await loginButton.click();
+ await waitForUrl(page, "/auth");
+ });
+
+ it("should login without interaction if the user already has a session", async function () {
+ const { client } = await createOAuth2Client({
+ scope: "offline_access profile openid email",
+ redirectUris: [`${TEST_CLIENT_BASE_URL}/oauth/callback`],
+ accessTokenStrategy: "jwt",
+ tokenEndpointAuthMethod: "none",
+ grantTypes: ["authorization_code", "refresh_token"],
+ responseTypes: ["code", "id_token"],
+ skipConsent: true,
+ });
+
+ await setOAuth2ClientInfo(page, client.clientId);
+ await Promise.all([
+ page.waitForNavigation({ waitUntil: "networkidle0" }),
+ page.goto(`${TEST_CLIENT_BASE_URL}/auth`),
+ ]);
+ await toggleSignInSignUp(page);
+ const { fieldValues, postValues } = getDefaultSignUpFieldValues({ email: getTestEmail() });
+ await signUp(page, fieldValues, postValues, "emailpassword");
+
+ await Promise.all([
+ page.waitForNavigation({ waitUntil: "networkidle0" }),
+ page.goto(`${TEST_CLIENT_BASE_URL}/oauth/login`),
+ ]);
+
+ let loginButton = await getOAuth2LoginButton(page);
+ await loginButton.click();
+
+ await waitForUrl(page, "/oauth/callback");
+
+ // Validate token data
+ const tokenData = await getOAuth2TokenData(page);
+ assert.deepStrictEqual(tokenData.aud, client.clientId);
+ });
+
+ it("should require logging in again with prompt=login", async function () {
+ const { client } = await createOAuth2Client({
+ scope: "offline_access profile openid email",
+ redirectUris: [`${TEST_CLIENT_BASE_URL}/oauth/callback`],
+ accessTokenStrategy: "jwt",
+ tokenEndpointAuthMethod: "none",
+ grantTypes: ["authorization_code", "refresh_token"],
+ responseTypes: ["code", "id_token"],
+ skipConsent: true,
+ });
+
+ await setOAuth2ClientInfo(page, client.clientId);
+
+ await Promise.all([
+ page.waitForNavigation({ waitUntil: "networkidle0" }),
+ page.goto(`${TEST_CLIENT_BASE_URL}/oauth/login`),
+ ]);
+
+ let loginButton = await getOAuth2LoginButton(page, "prompt-login");
+ await loginButton.click();
+
+ await waitForUrl(page, "/auth");
+
+ await toggleSignInSignUp(page);
+ const { fieldValues, postValues } = getDefaultSignUpFieldValues({ email: getTestEmail() });
+ await signUp(page, fieldValues, postValues, "emailpassword");
+
+ await waitForUrl(page, "/oauth/callback");
+
+ // Validate token data
+ const tokenData = await getOAuth2TokenData(page);
+ assert.deepStrictEqual(tokenData.aud, client.clientId);
+
+ await Promise.all([
+ page.waitForNavigation({ waitUntil: "networkidle0" }),
+ page.goto(`${TEST_CLIENT_BASE_URL}/oauth/login`),
+ ]);
+
+ loginButton = await getOAuth2LoginButton(page, "prompt-login");
+ await loginButton.click();
+ await waitForUrl(page, "/auth");
+ });
+
+ it("should require logging in again with max_age=3 after 3 seconds", async function () {
+ const { client } = await createOAuth2Client({
+ scope: "offline_access profile openid email",
+ redirectUris: [`${TEST_CLIENT_BASE_URL}/oauth/callback`],
+ accessTokenStrategy: "jwt",
+ tokenEndpointAuthMethod: "none",
+ grantTypes: ["authorization_code", "refresh_token"],
+ responseTypes: ["code", "id_token"],
+ skipConsent: true,
+ });
+
+ await setOAuth2ClientInfo(page, client.clientId);
+
+ await Promise.all([
+ page.waitForNavigation({ waitUntil: "networkidle0" }),
+ page.goto(`${TEST_CLIENT_BASE_URL}/oauth/login`),
+ ]);
+
+ let loginButton = await getOAuth2LoginButton(page, "max-age-3");
+ await loginButton.click();
+
+ await waitForUrl(page, "/auth");
+
+ await toggleSignInSignUp(page);
+ const { fieldValues, postValues } = getDefaultSignUpFieldValues({ email: getTestEmail() });
+ await signUp(page, fieldValues, postValues, "emailpassword");
+
+ await waitForUrl(page, "/oauth/callback");
+
+ // Validate token data
+ const tokenData = await getOAuth2TokenData(page);
+ assert.deepStrictEqual(tokenData.aud, client.clientId);
+
+ await Promise.all([
+ page.waitForNavigation({ waitUntil: "networkidle0" }),
+ page.goto(`${TEST_CLIENT_BASE_URL}/oauth/login`),
+ ]);
+
+ loginButton = await getOAuth2LoginButton(page, "max-age-3");
+ await loginButton.click();
+ await waitForUrl(page, "/oauth/callback");
+
+ await Promise.all([
+ page.waitForNavigation({ waitUntil: "networkidle0" }),
+ page.goto(`${TEST_CLIENT_BASE_URL}/oauth/login`),
+ ]);
+
+ await waitFor(3000);
+ loginButton = await getOAuth2LoginButton(page, "max-age-3");
+ await loginButton.click();
+ await waitForUrl(page, "/auth");
+ });
+
+ it("should successfully refresh the tokens after expiry", async function () {
+ const { client } = await createOAuth2Client({
+ scope: "offline_access profile openid email",
+ redirectUris: [`${TEST_CLIENT_BASE_URL}/oauth/callback`],
+ accessTokenStrategy: "jwt",
+ tokenEndpointAuthMethod: "none",
+ grantTypes: ["authorization_code", "refresh_token"],
+ responseTypes: ["code", "id_token"],
+ skipConsent: true,
+ // The library refreshes the token 60 seconds before it expires.
+ // We set the token lifespan to 63 seconds to force a refresh in 3 seconds.
+ authorizationCodeGrantAccessTokenLifespan: "63s",
+ });
+
+ await setOAuth2ClientInfo(page, client.clientId);
+
+ await Promise.all([
+ page.waitForNavigation({ waitUntil: "networkidle0" }),
+ page.goto(`${TEST_CLIENT_BASE_URL}/oauth/login`),
+ ]);
+
+ let loginButton = await getOAuth2LoginButton(page);
+ await loginButton.click();
+
+ await waitForUrl(page, "/auth");
+
+ await toggleSignInSignUp(page);
+ const { fieldValues, postValues } = getDefaultSignUpFieldValues({ email: getTestEmail() });
+ await signUp(page, fieldValues, postValues, "emailpassword");
+
+ await waitForUrl(page, "/oauth/callback");
+
+ // Validate token data
+ const tokenDataAfterLogin = await getOAuth2TokenData(page);
+ assert.deepStrictEqual(tokenDataAfterLogin.aud, client.clientId);
+
+ // Although the react-oidc-context library automatically refreshes the
+ // token, we wait for 4 seconds and reload the page to ensure a refresh.
+ await waitFor(4000);
+ await Promise.all([page.reload(), page.waitForNavigation({ waitUntil: "networkidle0" })]);
+
+ const tokenDataAfterRefresh = await getOAuth2TokenData(page);
+ assert.deepStrictEqual(tokenDataAfterRefresh.aud, client.clientId);
+
+ // Validate the token was refreshed
+ assert(tokenDataAfterLogin.iat !== tokenDataAfterRefresh.iat);
+ assert(tokenDataAfterLogin.exp < tokenDataAfterRefresh.exp);
+ });
+
+ it("should have roles in the id_token if the scopes is requested", async function () {
+ const { client } = await createOAuth2Client({
+ scope: "offline_access profile openid email roles permissions",
+ redirectUris: [`${TEST_CLIENT_BASE_URL}/oauth/callback`],
+ accessTokenStrategy: "jwt",
+ tokenEndpointAuthMethod: "none",
+ grantTypes: ["authorization_code", "refresh_token"],
+ responseTypes: ["code", "id_token"],
+ skipConsent: true,
+ });
+
+ await setOAuth2ClientInfo(page, client.clientId, "offline_access profile openid email roles permissions");
+
+ await Promise.all([
+ page.waitForNavigation({ waitUntil: "networkidle0" }),
+ page.goto(`${TEST_CLIENT_BASE_URL}/oauth/login`),
+ ]);
+
+ let loginButton = await getOAuth2LoginButton(page);
+ await loginButton.click();
+
+ await waitForUrl(page, "/auth");
+
+ await toggleSignInSignUp(page);
+ const { fieldValues, postValues } = getDefaultSignUpFieldValues({ email: getTestEmail() });
+ await signUp(page, fieldValues, postValues, "emailpassword");
+
+ await waitForUrl(page, "/oauth/callback");
+
+ // Validate token data
+ const tokenDataAfterLogin = await getOAuth2TokenData(page);
+ assert.deepStrictEqual(tokenDataAfterLogin.aud, client.clientId);
+
+ await page.evaluate(
+ (url) =>
+ window.fetch(url, {
+ method: "POST",
+ headers: [["content-type", "application/json"]],
+ body: JSON.stringify({
+ role: "testRole",
+ permissions: ["testPerm"],
+ }),
+ }),
+ `${TEST_APPLICATION_SERVER_BASE_URL}/setRole`
+ );
+
+ await waitFor(2000);
+ loginButton = await getOAuth2LoginButton(page, "silent");
+ await loginButton.click();
+
+ await waitFor(1000);
+
+ const tokenDataAfterRefresh = await getOAuth2TokenData(page);
+ assert.deepStrictEqual(tokenDataAfterRefresh.aud, client.clientId);
+
+ // Validate the token was refreshed
+ assert(tokenDataAfterLogin.iat !== tokenDataAfterRefresh.iat);
+ assert(tokenDataAfterLogin.exp < tokenDataAfterRefresh.exp);
+
+ assert.deepStrictEqual(tokenDataAfterLogin.roles, []);
+ assert.deepStrictEqual(tokenDataAfterLogin.permissions, []);
+
+ assert.deepStrictEqual(tokenDataAfterRefresh.roles, ["testRole"]);
+ assert.deepStrictEqual(tokenDataAfterRefresh.permissions, ["testPerm"]);
+ });
+
+ it("should not include email info if the scope is not requested", async function () {
+ const { client } = await createOAuth2Client({
+ scope: "offline_access profile openid roles permissions",
+ redirectUris: [`${TEST_CLIENT_BASE_URL}/oauth/callback`],
+ accessTokenStrategy: "jwt",
+ tokenEndpointAuthMethod: "none",
+ grantTypes: ["authorization_code", "refresh_token"],
+ responseTypes: ["code", "id_token"],
+ skipConsent: true,
+ // The library refreshes the token 60 seconds before it expires.
+ // We set the token lifespan to 63 seconds to force a refresh in 3 seconds.
+ authorizationCodeGrantAccessTokenLifespan: "63s",
+ });
+
+ await setOAuth2ClientInfo(page, client.clientId, "offline_access profile openid roles permissions");
+
+ await Promise.all([
+ page.waitForNavigation({ waitUntil: "networkidle0" }),
+ page.goto(`${TEST_CLIENT_BASE_URL}/oauth/login`),
+ ]);
+
+ let loginButton = await getOAuth2LoginButton(page);
+ await loginButton.click();
+
+ await waitForUrl(page, "/auth");
+
+ await toggleSignInSignUp(page);
+ const { fieldValues, postValues } = getDefaultSignUpFieldValues({ email: getTestEmail() });
+ await signUp(page, fieldValues, postValues, "emailpassword");
+
+ await waitForUrl(page, "/oauth/callback");
+
+ // Validate token data
+ const tokenDataAfterLogin = await getOAuth2TokenData(page);
+ assert.deepStrictEqual(tokenDataAfterLogin.aud, client.clientId);
+
+ // Although the react-oidc-context library automatically refreshes the
+ // token, we wait for 4 seconds and reload the page to ensure a refresh.
+ await waitFor(4000);
+ await Promise.all([page.reload(), page.waitForNavigation({ waitUntil: "networkidle0" })]);
+
+ const tokenDataAfterRefresh = await getOAuth2TokenData(page);
+ assert.deepStrictEqual(tokenDataAfterRefresh.aud, client.clientId);
+
+ // Validate the token was refreshed
+ assert(tokenDataAfterLogin.iat !== tokenDataAfterRefresh.iat);
+ assert(tokenDataAfterLogin.exp < tokenDataAfterRefresh.exp);
+
+ assert.strictEqual(tokenDataAfterLogin.email, undefined);
+ assert.strictEqual(tokenDataAfterLogin.email_verified, undefined);
+ assert.strictEqual(tokenDataAfterRefresh.email, undefined);
+ assert.strictEqual(tokenDataAfterRefresh.email_verified, undefined);
+ });
+
+ it("should work if the scope phoneNumber is requested for emailpassword user", async function () {
+ const { client } = await createOAuth2Client({
+ scope: "offline_access profile openid phoneNumber",
+ redirectUris: [`${TEST_CLIENT_BASE_URL}/oauth/callback`],
+ accessTokenStrategy: "jwt",
+ tokenEndpointAuthMethod: "none",
+ grantTypes: ["authorization_code", "refresh_token"],
+ responseTypes: ["code", "id_token"],
+ skipConsent: true,
+ // The library refreshes the token 60 seconds before it expires.
+ // We set the token lifespan to 63 seconds to force a refresh in 3 seconds.
+ authorizationCodeGrantAccessTokenLifespan: "63s",
+ });
+
+ await setOAuth2ClientInfo(page, client.clientId, "offline_access profile openid phoneNumber");
+
+ await Promise.all([
+ page.waitForNavigation({ waitUntil: "networkidle0" }),
+ page.goto(`${TEST_CLIENT_BASE_URL}/oauth/login`),
+ ]);
+
+ let loginButton = await getOAuth2LoginButton(page);
+ await loginButton.click();
+
+ await waitForUrl(page, "/auth");
+
+ await toggleSignInSignUp(page);
+ const { fieldValues, postValues } = getDefaultSignUpFieldValues({ email: getTestEmail() });
+ await signUp(page, fieldValues, postValues, "emailpassword");
+
+ await waitForUrl(page, "/oauth/callback");
+
+ // Validate token data
+ const tokenDataAfterLogin = await getOAuth2TokenData(page);
+ assert.deepStrictEqual(tokenDataAfterLogin.aud, client.clientId);
+
+ // Although the react-oidc-context library automatically refreshes the
+ // token, we wait for 4 seconds and reload the page to ensure a refresh.
+ await waitFor(4000);
+ await Promise.all([page.reload(), page.waitForNavigation({ waitUntil: "networkidle0" })]);
+
+ const tokenDataAfterRefresh = await getOAuth2TokenData(page);
+ assert.deepStrictEqual(tokenDataAfterRefresh.aud, client.clientId);
+
+ // Validate the token was refreshed
+ assert(tokenDataAfterLogin.iat !== tokenDataAfterRefresh.iat);
+ assert(tokenDataAfterLogin.exp < tokenDataAfterRefresh.exp);
+
+ assert.strictEqual(tokenDataAfterLogin.email, undefined);
+ assert.strictEqual(tokenDataAfterLogin.email_verified, undefined);
+ assert.strictEqual(tokenDataAfterRefresh.email, undefined);
+ assert.strictEqual(tokenDataAfterRefresh.email_verified, undefined);
+ assert.strictEqual(tokenDataAfterLogin.phoneNumber, undefined);
+ assert.notStrictEqual(tokenDataAfterLogin.phoneNumber_verified, undefined);
+ assert.strictEqual(tokenDataAfterRefresh.phoneNumber, undefined);
+ assert.notStrictEqual(tokenDataAfterRefresh.phoneNumber_verified, undefined);
+ });
+
+ it("should reject the login if the wrong scope is requested", async function () {
+ const { client } = await createOAuth2Client({
+ scope: "offline_access profile openid",
+ redirectUris: [`${TEST_CLIENT_BASE_URL}/oauth/callback`],
+ accessTokenStrategy: "jwt",
+ tokenEndpointAuthMethod: "none",
+ grantTypes: ["authorization_code", "refresh_token"],
+ responseTypes: ["code", "id_token"],
+ skipConsent: true,
+ // The library refreshes the token 60 seconds before it expires.
+ // We set the token lifespan to 63 seconds to force a refresh in 3 seconds.
+ authorizationCodeGrantAccessTokenLifespan: "63s",
+ });
+
+ await setOAuth2ClientInfo(page, client.clientId, "offline_access profile openid roles permissions");
+
+ await Promise.all([
+ page.waitForNavigation({ waitUntil: "networkidle0" }),
+ page.goto(`${TEST_CLIENT_BASE_URL}/oauth/login`),
+ ]);
+
+ let loginButton = await getOAuth2LoginButton(page);
+ await loginButton.click();
+
+ assert.strictEqual(
+ await getOAuth2Error(page),
+ `Error: The requested scope is invalid, unknown, or malformed. The OAuth 2.0 Client is not allowed to request scope 'roles'.`
+ );
+ });
+
+ it("should work even if the supertokens session is expired", async function () {
+ const { client } = await createOAuth2Client({
+ scope: "offline_access profile openid email",
+ redirectUris: [`${TEST_CLIENT_BASE_URL}/oauth/callback`],
+ accessTokenStrategy: "jwt",
+ tokenEndpointAuthMethod: "none",
+ grantTypes: ["authorization_code", "refresh_token"],
+ responseTypes: ["code", "id_token"],
+ skipConsent: true,
+ // The library refreshes the token 60 seconds before it expires.
+ // We set the token lifespan to 63 seconds to force a refresh in 3 seconds.
+ authorizationCodeGrantAccessTokenLifespan: "63s",
+ });
+
+ await setOAuth2ClientInfo(page, client.clientId);
+
+ await toggleSignInSignUp(page);
+ const { fieldValues, postValues } = getDefaultSignUpFieldValues({ email: getTestEmail() });
+ await signUp(page, fieldValues, postValues, "emailpassword");
+
+ await waitFor(6000);
+
+ await Promise.all([
+ page.waitForNavigation({ waitUntil: "networkidle0" }),
+ page.goto(`${TEST_CLIENT_BASE_URL}/oauth/login`),
+ ]);
+
+ let loginButton = await getOAuth2LoginButton(page);
+ await loginButton.click();
+
+ await waitForUrl(page, "/oauth/callback");
+
+ // Validate token data
+ const tokenDataAfterLogin = await getOAuth2TokenData(page);
+ assert.deepStrictEqual(tokenDataAfterLogin.aud, client.clientId);
+
+ // Although the react-oidc-context library automatically refreshes the
+ // token, we wait for 6 seconds and reload the page to ensure a refresh.
+ await waitFor(6000);
+ await Promise.all([page.reload(), page.waitForNavigation({ waitUntil: "networkidle0" })]);
+
+ const tokenDataAfterRefresh = await getOAuth2TokenData(page);
+ assert.deepStrictEqual(tokenDataAfterRefresh.aud, client.clientId);
+
+ // Validate the token was refreshed
+ assert(tokenDataAfterLogin.iat !== tokenDataAfterRefresh.iat);
+ assert(tokenDataAfterLogin.exp < tokenDataAfterRefresh.exp);
+ });
+ });
+});
diff --git a/test/end-to-end/passwordless.test_gen.js b/test/end-to-end/passwordless.test_gen.js
index cb9f41e14..4d21d8c7f 100644
--- a/test/end-to-end/passwordless.test_gen.js
+++ b/test/end-to-end/passwordless.test_gen.js
@@ -37,6 +37,7 @@ import {
isAccountLinkingSupported,
backendBeforeEach,
waitForUrl,
+ setupBrowser,
} from "../helpers";
import { TEST_CLIENT_BASE_URL, TEST_SERVER_BASE_URL, SOMETHING_WENT_WRONG_ERROR } from "../constants";
@@ -1907,10 +1908,7 @@ async function initBrowser(contactMethod, consoleLogs, authRecipe, { defaultCoun
}),
}).catch(console.error);
- const browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox", "--remote-debugging-port=9222"],
- headless: true,
- });
+ const browser = await setupBrowser();
const page = await browser.newPage();
page.on("console", (consoleObj) => {
const log = consoleObj.text();
diff --git a/test/end-to-end/refresherrors.test.js b/test/end-to-end/refresherrors.test.js
index 06909e4cf..259ef4c1f 100644
--- a/test/end-to-end/refresherrors.test.js
+++ b/test/end-to-end/refresherrors.test.js
@@ -19,7 +19,12 @@
import assert from "assert";
import puppeteer from "puppeteer";
-import { clearBrowserCookiesWithoutAffectingConsole, getTextInDashboardNoAuth, screenshotOnFailure } from "../helpers";
+import {
+ clearBrowserCookiesWithoutAffectingConsole,
+ getTextInDashboardNoAuth,
+ screenshotOnFailure,
+ setupBrowser,
+} from "../helpers";
import { TEST_CLIENT_BASE_URL } from "../constants";
@@ -29,10 +34,7 @@ describe("Refresh errors", function () {
let page;
before(async function () {
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
- headless: true,
- });
+ browser = await setupBrowser();
});
after(async function () {
diff --git a/test/end-to-end/resetpasswordusingtoken.test.js b/test/end-to-end/resetpasswordusingtoken.test.js
index 54b7cf7dc..d8ebe60b6 100644
--- a/test/end-to-end/resetpasswordusingtoken.test.js
+++ b/test/end-to-end/resetpasswordusingtoken.test.js
@@ -55,6 +55,7 @@ import {
backendBeforeEach,
waitForText,
waitForUrl,
+ setupBrowser,
} from "../helpers";
/*
@@ -72,10 +73,7 @@ describe("SuperTokens Reset password", function () {
method: "POST",
}).catch(console.error);
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
- headless: true,
- });
+ browser = await setupBrowser();
page = await browser.newPage();
diff --git a/test/end-to-end/routing.test.js b/test/end-to-end/routing.test.js
index 7071ef669..27dd56570 100644
--- a/test/end-to-end/routing.test.js
+++ b/test/end-to-end/routing.test.js
@@ -32,6 +32,7 @@ import {
clearBrowserCookiesWithoutAffectingConsole,
screenshotOnFailure,
waitForUrl,
+ setupBrowser,
} from "../helpers";
/*
* Tests.
@@ -40,10 +41,7 @@ describe("SuperTokens Routing in Test App", function () {
let browser, page;
before(async function () {
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
- headless: true,
- });
+ browser = await setupBrowser();
page = await browser.newPage();
});
diff --git a/test/end-to-end/signin-rrdv5.test.js b/test/end-to-end/signin-rrdv5.test.js
index bb9b1ab8a..3c29a2edb 100644
--- a/test/end-to-end/signin-rrdv5.test.js
+++ b/test/end-to-end/signin-rrdv5.test.js
@@ -52,6 +52,7 @@ import {
backendBeforeEach,
setEnabledRecipes,
waitForUrl,
+ setupBrowser,
} from "../helpers";
import fetch from "isomorphic-fetch";
import { SOMETHING_WENT_WRONG_ERROR } from "../constants";
@@ -77,10 +78,7 @@ describe("SuperTokens SignIn with react router dom v5", function () {
method: "POST",
}).catch(console.error);
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
- headless: true,
- });
+ browser = await setupBrowser();
});
after(async function () {
@@ -655,10 +653,7 @@ describe("SuperTokens SignIn => Server Error", function () {
before(async function () {
await setEnabledRecipes(["emailpassword"], []);
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
- headless: true,
- });
+ browser = await setupBrowser();
});
after(async function () {
diff --git a/test/end-to-end/signin-rrdv6.test.js b/test/end-to-end/signin-rrdv6.test.js
index ab595eba7..5222f2e62 100644
--- a/test/end-to-end/signin-rrdv6.test.js
+++ b/test/end-to-end/signin-rrdv6.test.js
@@ -53,6 +53,7 @@ import {
getInvalidClaimsJSON,
expectErrorThrown,
waitForUrl,
+ setupBrowser,
} from "../helpers";
import fetch from "isomorphic-fetch";
import { SOMETHING_WENT_WRONG_ERROR } from "../constants";
@@ -74,10 +75,7 @@ describe("SuperTokens SignIn with react router dom v6", function () {
method: "POST",
}).catch(console.error);
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
- headless: true,
- });
+ browser = await setupBrowser();
});
after(async function () {
@@ -186,7 +184,7 @@ describe("SuperTokens SignIn with react router dom v6", function () {
assert.strictEqual(request.headers().rid, "emailpassword");
assert.strictEqual(
request.postData(),
- '{"formFields":[{"id":"email","value":"john@gmail.com"},{"id":"password","value":"********"}]}'
+ '{"formFields":[{"id":"email","value":"john@gmail.com"},{"id":"password","value":"********"}],"shouldTryLinkingWithSessionUser":false}'
);
assert.strictEqual(response.status, "WRONG_CREDENTIALS_ERROR");
@@ -258,7 +256,7 @@ describe("SuperTokens SignIn with react router dom v6", function () {
assert.strictEqual(request.headers().rid, "emailpassword");
assert.strictEqual(
request.postData(),
- '{"formFields":[{"id":"email","value":"john.doe@supertokens.io"},{"id":"password","value":"Str0ngP@ssw0rd"}]}'
+ '{"formFields":[{"id":"email","value":"john.doe@supertokens.io"},{"id":"password","value":"Str0ngP@ssw0rd"}],"shouldTryLinkingWithSessionUser":false}'
);
assert.strictEqual(response.status, "OK");
@@ -403,7 +401,7 @@ describe("SuperTokens SignIn with react router dom v6", function () {
assert.strictEqual(request.headers().rid, "emailpassword");
assert.strictEqual(
request.postData(),
- '{"formFields":[{"id":"email","value":"john.doe@supertokens.io"},{"id":"password","value":"Str0ngP@ssw0rd"}]}'
+ '{"formFields":[{"id":"email","value":"john.doe@supertokens.io"},{"id":"password","value":"Str0ngP@ssw0rd"}],"shouldTryLinkingWithSessionUser":false}'
);
assert.strictEqual(response.status, "OK");
@@ -802,10 +800,7 @@ describe("SuperTokens SignIn => Server Error", function () {
let consoleLogs;
before(async function () {
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
- headless: true,
- });
+ browser = await setupBrowser();
});
after(async function () {
diff --git a/test/end-to-end/signin.test.js b/test/end-to-end/signin.test.js
index 46a4fcbad..a410e3f08 100644
--- a/test/end-to-end/signin.test.js
+++ b/test/end-to-end/signin.test.js
@@ -56,6 +56,7 @@ import {
getInputField,
isReact16,
waitForUrl,
+ setupBrowser,
} from "../helpers";
import fetch from "isomorphic-fetch";
import { SOMETHING_WENT_WRONG_ERROR } from "../constants";
@@ -77,10 +78,7 @@ describe("SuperTokens SignIn", function () {
method: "POST",
}).catch(console.error);
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
- headless: true,
- });
+ browser = await setupBrowser();
});
after(async function () {
@@ -187,7 +185,7 @@ describe("SuperTokens SignIn", function () {
assert.strictEqual(request.headers().rid, "emailpassword");
assert.strictEqual(
request.postData(),
- '{"formFields":[{"id":"email","value":"john@gmail.com"},{"id":"password","value":"********"}]}'
+ '{"formFields":[{"id":"email","value":"john@gmail.com"},{"id":"password","value":"********"}],"shouldTryLinkingWithSessionUser":false}'
);
assert.strictEqual(response.status, "WRONG_CREDENTIALS_ERROR");
@@ -300,7 +298,7 @@ describe("SuperTokens SignIn", function () {
assert.strictEqual(request.headers().rid, "emailpassword");
assert.strictEqual(
request.postData(),
- '{"formFields":[{"id":"email","value":"john.doe@supertokens.io"},{"id":"password","value":"Str0ngP@ssw0rd"}]}'
+ '{"formFields":[{"id":"email","value":"john.doe@supertokens.io"},{"id":"password","value":"Str0ngP@ssw0rd"}],"shouldTryLinkingWithSessionUser":false}'
);
assert.strictEqual(response.status, "OK");
@@ -445,7 +443,7 @@ describe("SuperTokens SignIn", function () {
assert.strictEqual(request.headers().rid, "emailpassword");
assert.strictEqual(
request.postData(),
- '{"formFields":[{"id":"email","value":"john.doe@supertokens.io"},{"id":"password","value":"Str0ngP@ssw0rd"}]}'
+ '{"formFields":[{"id":"email","value":"john.doe@supertokens.io"},{"id":"password","value":"Str0ngP@ssw0rd"}],"shouldTryLinkingWithSessionUser":false}'
);
assert.strictEqual(response.status, "OK");
@@ -512,7 +510,7 @@ describe("SuperTokens SignIn", function () {
await assertSignInRedirectTo(
page,
`${TEST_CLIENT_BASE_URL}/auth?rid=emailpassword&redirectToPath=%2Fredirect-here`,
- `${TEST_CLIENT_BASE_URL}/redirect-here`
+ `/redirect-here`
);
// test that if we visit auth again, we end up in redirect-heree again with query params kept
@@ -529,7 +527,7 @@ describe("SuperTokens SignIn", function () {
await assertSignInRedirectTo(
page,
`${TEST_CLIENT_BASE_URL}/auth?rid=emailpassword&redirectToPath=redirect-here`,
- `${TEST_CLIENT_BASE_URL}/redirect-here`
+ `/redirect-here`
);
});
@@ -560,7 +558,7 @@ describe("SuperTokens SignIn", function () {
await assertSignInRedirectTo(
page,
`${TEST_CLIENT_BASE_URL}/auth?rid=emailpassword&redirectToPath=https://attacker.com/path`,
- `${TEST_CLIENT_BASE_URL}/path`
+ `/path`
);
});
@@ -569,7 +567,7 @@ describe("SuperTokens SignIn", function () {
await assertSignInRedirectTo(
page,
`${TEST_CLIENT_BASE_URL}/auth?rid=emailpassword&redirectToPath=javascript:alert(1)`,
- `${TEST_CLIENT_BASE_URL}/javascript:alert(1)`
+ `/javascript:alert(1)`
);
});
@@ -903,10 +901,7 @@ describe("SuperTokens SignIn => Server Error", function () {
let consoleLogs;
before(async function () {
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
- headless: true,
- });
+ browser = await setupBrowser();
});
after(async function () {
@@ -1083,11 +1078,5 @@ async function assertSignInRedirectTo(page, startUrl, finalUrl) {
]);
// Submit.
- await Promise.all([
- submitFormReturnRequestAndResponse(page, SIGN_IN_API),
- page.waitForNavigation({ waitUntil: "networkidle0" }),
- ]);
-
- let href = await page.evaluate(() => window.location.href);
- assert.deepStrictEqual(href, finalUrl);
+ await Promise.all([submitFormReturnRequestAndResponse(page, SIGN_IN_API), waitForUrl(page, finalUrl, false)]);
}
diff --git a/test/end-to-end/signup.test.js b/test/end-to-end/signup.test.js
index 486719c84..2d4f1389b 100644
--- a/test/end-to-end/signup.test.js
+++ b/test/end-to-end/signup.test.js
@@ -44,6 +44,7 @@ import {
isReact16,
getDefaultSignUpFieldValues,
waitForUrl,
+ setupBrowser,
} from "../helpers";
import {
@@ -69,10 +70,7 @@ describe("SuperTokens SignUp", function () {
method: "POST",
}).catch(console.error);
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
- headless: true,
- });
+ browser = await setupBrowser();
page = await browser.newPage();
page.on("console", (consoleObj) => {
const log = consoleObj.text();
@@ -880,10 +878,7 @@ describe("SuperTokens SignUp => Server Error", function () {
let consoleLogs;
before(async function () {
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
- headless: true,
- });
+ browser = await setupBrowser();
});
after(async function () {
diff --git a/test/end-to-end/thirdparty.test.js b/test/end-to-end/thirdparty.test.js
index dac9a98b1..49411419b 100644
--- a/test/end-to-end/thirdparty.test.js
+++ b/test/end-to-end/thirdparty.test.js
@@ -33,6 +33,7 @@ import {
clickOnProviderButtonWithoutWaiting,
backendBeforeEach,
waitForUrl,
+ setupBrowser,
} from "../helpers";
import { TEST_CLIENT_BASE_URL, TEST_SERVER_BASE_URL, SIGN_IN_UP_API, GET_AUTH_URL_API } from "../constants";
@@ -60,10 +61,7 @@ export function getThirdPartyTestCases({ authRecipe, rid, signInUpPageLoadLogs,
method: "POST",
}).catch(console.error);
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
- headless: true,
- });
+ browser = await setupBrowser();
page = await browser.newPage();
page.on("console", (consoleObj) => {
const log = consoleObj.text();
diff --git a/test/end-to-end/thirdpartyemailpassword.test.js b/test/end-to-end/thirdpartyemailpassword.test.js
index ae102d88d..fb4bdef59 100644
--- a/test/end-to-end/thirdpartyemailpassword.test.js
+++ b/test/end-to-end/thirdpartyemailpassword.test.js
@@ -49,6 +49,7 @@ import {
getLabelsText,
isReact16,
waitForUrl,
+ setupBrowser,
} from "../helpers";
import {
TEST_CLIENT_BASE_URL,
@@ -77,10 +78,7 @@ describe("SuperTokens Third Party Email Password", function () {
method: "POST",
}).catch(console.error);
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
- headless: true,
- });
+ browser = await setupBrowser();
page = await browser.newPage();
page.on("console", (consoleObj) => {
const log = consoleObj.text();
@@ -332,7 +330,7 @@ describe("SuperTokens Third Party Email Password", function () {
{ name: "name", value: "John Doe" },
{ name: "age", value: "20" },
],
- '{"formFields":[{"id":"email","value":"bradparishdoh@gmail.com"},{"id":"password","value":"Str0ngP@ssw0rd"},{"id":"name","value":"John Doe"},{"id":"age","value":"20"},{"id":"country","value":""}]}',
+ '{"formFields":[{"id":"email","value":"bradparishdoh@gmail.com"},{"id":"password","value":"Str0ngP@ssw0rd"},{"id":"name","value":"John Doe"},{"id":"age","value":"20"},{"id":"country","value":""}],"shouldTryLinkingWithSessionUser":false}',
"thirdpartyemailpassword"
);
await waitForUrl(page, "/dashboard");
diff --git a/test/end-to-end/thirdpartypasswordless.test.js b/test/end-to-end/thirdpartypasswordless.test.js
index 80fc4c485..d97f74d34 100644
--- a/test/end-to-end/thirdpartypasswordless.test.js
+++ b/test/end-to-end/thirdpartypasswordless.test.js
@@ -38,6 +38,7 @@ import {
getGeneralError,
backendBeforeEach,
waitForUrl,
+ setupBrowser,
} from "../helpers";
import { TEST_CLIENT_BASE_URL, TEST_SERVER_BASE_URL, SIGN_IN_UP_API, GET_AUTH_URL_API } from "../constants";
@@ -71,10 +72,7 @@ describe("SuperTokens Third Party Passwordless", function () {
method: "POST",
}).catch(console.error);
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
- headless: true,
- });
+ browser = await setupBrowser();
page = await browser.newPage();
page.on("console", (consoleObj) => {
const log = consoleObj.text();
diff --git a/test/end-to-end/userContext.test.js b/test/end-to-end/userContext.test.js
index 3903415c8..2a5e120f8 100644
--- a/test/end-to-end/userContext.test.js
+++ b/test/end-to-end/userContext.test.js
@@ -26,6 +26,7 @@ import {
loginWithAuth0,
backendBeforeEach,
waitForUrl,
+ setupBrowser,
} from "../helpers";
import {
TEST_CLIENT_BASE_URL,
@@ -48,10 +49,7 @@ describe("SuperTokens userContext with UI components test", function () {
method: "POST",
}).catch(console.error);
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
- headless: true,
- });
+ browser = await setupBrowser();
page = await browser.newPage();
page.on("console", (consoleObj) => {
const log = consoleObj.text();
diff --git a/test/end-to-end/userroles.test.js b/test/end-to-end/userroles.test.js
index 1587e5804..96bb1648d 100644
--- a/test/end-to-end/userroles.test.js
+++ b/test/end-to-end/userroles.test.js
@@ -32,6 +32,7 @@ import {
waitForText,
backendBeforeEach,
waitForUrl,
+ setupBrowser,
} from "../helpers";
import { TEST_APPLICATION_SERVER_BASE_URL, TEST_CLIENT_BASE_URL, TEST_SERVER_BASE_URL } from "../constants";
@@ -54,10 +55,7 @@ describe("User Roles in the frontend", function () {
method: "POST",
}).catch(console.error);
- browser = await puppeteer.launch({
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
- headless: true,
- });
+ browser = await setupBrowser();
page = await browser.newPage();
await Promise.all([
page.goto(`${TEST_CLIENT_BASE_URL}/auth?authRecipe=emailpassword`),
diff --git a/test/helpers.js b/test/helpers.js
index 4cbaf99d3..c9ddfeb08 100644
--- a/test/helpers.js
+++ b/test/helpers.js
@@ -27,7 +27,9 @@ import {
import path from "path";
import assert from "assert";
+import { appendFile } from "fs/promises";
import mkdirp from "mkdirp";
+import Puppeteer from "puppeteer";
const SESSION_STORAGE_STATE_KEY = "supertokens-oauth-state";
@@ -649,7 +651,7 @@ export async function defaultSignUp(page, rid = "emailpassword") {
{ name: "name", value: "John Doe" },
{ name: "age", value: "20" },
],
- '{"formFields":[{"id":"email","value":"john.doe@supertokens.io"},{"id":"password","value":"Str0ngP@ssw0rd"},{"id":"name","value":"John Doe"},{"id":"age","value":"20"},{"id":"country","value":""}]}',
+ '{"formFields":[{"id":"email","value":"john.doe@supertokens.io"},{"id":"password","value":"Str0ngP@ssw0rd"},{"id":"name","value":"John Doe"},{"id":"age","value":"20"},{"id":"country","value":""}],"shouldTryLinkingWithSessionUser":false}',
rid
);
}
@@ -666,7 +668,7 @@ export function getDefaultSignUpFieldValues({
{ name: "name", value: name },
{ name: "age", value: age },
];
- const postValues = `{"formFields":[{"id":"email","value":"${email}"},{"id":"password","value":"${password}"},{"id":"name","value":"${name}"},{"id":"age","value":"${age}"},{"id":"country","value":""}]}`;
+ const postValues = `{"formFields":[{"id":"email","value":"${email}"},{"id":"password","value":"${password}"},{"id":"name","value":"${name}"},{"id":"age","value":"${age}"},{"id":"country","value":""}],"shouldTryLinkingWithSessionUser":false}`;
return { fieldValues, postValues };
}
@@ -752,12 +754,114 @@ export async function getTextInDashboardNoAuth(page) {
return await page.evaluate(() => document.querySelector("#root > div > div.fill > div.not-logged-in").innerText);
}
+export async function setupBrowser() {
+ const browser = await Puppeteer.launch({
+ args: [
+ "--no-sandbox",
+ "--disable-setuid-sandbox",
+ "--disable-web-security",
+ "--host-resolver-rules=MAP example.com 127.0.0.1, MAP *.example.com 127.0.0.1",
+ ],
+ headless: process.env.HEADLESS !== "false",
+ });
+ browser.logs = [];
+ function addLog(str) {
+ if (process.env.BROWSER_LOGS !== undefined) {
+ console.log(str);
+ }
+ browser.logs.push(str);
+ }
+ const origNewPage = browser.newPage.bind(browser);
+ browser.newPage = async () => {
+ const page = await origNewPage();
+ page.on("console", (msg) => {
+ if (msg.text().startsWith("com.supertokens")) {
+ addLog(msg.text());
+ } else {
+ addLog(
+ `browserlog.console ${JSON.stringify({
+ t: new Date().toISOString(),
+ message: msg.text(),
+ pageurl: page.url(),
+ })}`
+ );
+ }
+ });
+
+ page.on("request", (req) => {
+ addLog(
+ `browserlog.network ${JSON.stringify({
+ t: new Date().toISOString(),
+ message: `Requested: ${req.method()} ${req.url()} (${req.postData()})`,
+ pageurl: page.url(),
+ })}`
+ );
+ });
+ page.on("requestfinished", async (req) => {
+ if (req.method() === "OPTION") {
+ return;
+ }
+ const resp = await req.response();
+ let respText;
+ try {
+ respText = req.url().startsWith(TEST_APPLICATION_SERVER_BASE_URL)
+ ? await resp.text()
+ : "response omitted";
+ } catch (e) {
+ respText = "response loading failed " + e.message;
+ }
+ addLog(
+ `browserlog.network ${JSON.stringify({
+ t: new Date().toISOString(),
+ message: `Request done: ${req.method()} ${req.url()}: ${resp.status()} ${respText}`,
+ pageurl: page.url(),
+ })}`
+ );
+ });
+ page.on("requestfailed", async (req) => {
+ if (req.method() === "OPTION") {
+ return;
+ }
+ const resp = await req.response();
+ let respText;
+ try {
+ respText = req.url().startsWith(TEST_APPLICATION_SERVER_BASE_URL)
+ ? await resp.text()
+ : "response omitted";
+ } catch (e) {
+ respText = "response loading failed " + e.message;
+ }
+ addLog(
+ `browserlog.network ${JSON.stringify({
+ t: new Date().toISOString(),
+ message: `Request failed: ${req.method()} ${req.url()}: ${resp.status()} ${respText}`,
+ pageurl: page.url(),
+ })}`
+ );
+ });
+ return page;
+ };
+ browser.on("disconnected", async () => {
+ if (process.env.MOCHA_FILE !== undefined) {
+ const reportFile = path.parse(process.env.MOCHA_FILE);
+ const logFile = path.join(reportFile.dir, "logs", "browser.log");
+ await appendFile(logFile, browser.logs.join("\n"));
+ }
+ });
+ return browser;
+}
+
/**
* @param {import("mocha").Context} ctx
* @param {import("puppeteer").Browser} browser
*/
export async function screenshotOnFailure(ctx, browser) {
if (ctx.currentTest?.isFailed()) {
+ console.log(
+ `${ctx.currentTest.fullTitle()} failed ${new Date(
+ Date.now() - ctx.currentTest.duration
+ ).toISOString()} - ${new Date().toISOString()}`
+ );
const pages = await browser.pages();
let screenshotRoot;
@@ -947,6 +1051,15 @@ export async function isMFASupported() {
return true;
}
+export async function isOauth2Supported() {
+ const features = await getFeatureFlags();
+ if (!features.includes("oauth2")) {
+ return false;
+ }
+
+ return true;
+}
+
/**
* For example setGeneralErrorToLocalStorage("EMAIL_PASSWORD", "EMAIL_PASSWORD_SIGN_UP", page) to
* set for signUp in email password
@@ -958,7 +1071,7 @@ export async function setGeneralErrorToLocalStorage(recipeName, action, page) {
});
}
-export async function getTestEmail(post) {
+export function getTestEmail(post) {
return `john.doe+${Date.now()}-${post ?? "0"}@supertokens.io`;
}
@@ -1105,3 +1218,65 @@ export async function expectErrorThrown(page, cb) {
await Promise.all([hitErrorBoundary, cb()]);
assert(hitErrorBoundary);
}
+
+export async function createOAuth2Client(input) {
+ const resp = await fetch(`${TEST_APPLICATION_SERVER_BASE_URL}/test/create-oauth2-client`, {
+ method: "POST",
+ headers: { "content-type": "application/json" },
+ body: JSON.stringify(input),
+ });
+ return await resp.json();
+}
+
+// For the OAuth2 end-to-end test, we need to provide the created clientId to both the OAuth2 login and callback pages.
+// We use localStorage to store the clientId instead of query params, as it must be available on the callback page as well.
+export async function setOAuth2ClientInfo(page, clientId, scopes, extraConfig, extraSignInParams, extraSignOutParams) {
+ await page.evaluate((clientId) => localStorage.setItem("oauth2-client-id", clientId), clientId);
+ if (scopes) {
+ await page.evaluate((scopes) => localStorage.setItem("oauth2-scopes", scopes), scopes);
+ }
+ if (extraConfig) {
+ await page.evaluate((extraConfig) => localStorage.setItem("oauth2-extra-config", extraConfig), extraConfig);
+ }
+ if (extraSignInParams) {
+ await page.evaluate(
+ (extraSignInParams) => localStorage.setItem("oauth2-extra-sign-in-params", extraSignInParams),
+ extraSignInParams
+ );
+ }
+ if (extraSignOutParams) {
+ await page.evaluate(
+ (extraSignOutParams) => localStorage.setItem("oauth2-extra-sign-out-params", extraSignOutParams),
+ extraSignOutParams
+ );
+ }
+}
+
+export async function removeOAuth2ClientInfo(page) {
+ await page.evaluate(() => localStorage.removeItem("oauth2-client-id"));
+ await page.evaluate(() => localStorage.removeItem("oauth2-scopes"));
+ await page.evaluate(() => localStorage.removeItem("oauth2-extra-config"));
+ await page.evaluate(() => localStorage.removeItem("oauth2-extra-sign-in-params"));
+ await page.evaluate(() => localStorage.removeItem("oauth2-extra-sign-out-params"));
+}
+
+export async function getOAuth2LoginButton(page, type = "default") {
+ const id = type === "default" ? "#oauth2-login-button" : `#oauth2-login-button-${type}`;
+ return page.waitForSelector(id);
+}
+
+export async function getOAuth2Error(page) {
+ const ele = await page.waitForSelector("#oauth2-error-message");
+ return await ele.evaluate((el) => el.textContent);
+}
+
+export async function getOAuth2LogoutButton(page, type = "silent") {
+ const id = type === "silent" ? "#oauth2-logout-button" : `#oauth2-logout-button-${type}`;
+ return page.waitForSelector(id);
+}
+
+export async function getOAuth2TokenData(page) {
+ const element = await page.waitForSelector("#oauth2-token-data");
+ const tokenData = await element.evaluate((el) => el.textContent);
+ return JSON.parse(tokenData);
+}
diff --git a/test/prepTestApp.sh b/test/prepTestApp.sh
index d42f26602..a628f362a 100755
--- a/test/prepTestApp.sh
+++ b/test/prepTestApp.sh
@@ -2,14 +2,17 @@
# pack-unpack repo to simulate an install
npm pack
+
+REPO=$(pwd)
+
cd $1
rm -rf node_modules/.cache
rm -rf node_modules/supertokens-auth-react/lib || true
rm -rf node_modules/supertokens-auth-react/recipe || true
mkdir -p node_modules/supertokens-auth-react
-tar -xf ../../supertokens-auth-react-*.tgz --strip-components=1 -C node_modules/supertokens-auth-react
-rm ../../supertokens-auth-react-*.tgz
+tar -xf $REPO/supertokens-auth-react-*.tgz --strip-components=1 -C node_modules/supertokens-auth-react
+rm $REPO/supertokens-auth-react-*.tgz
cd node_modules/supertokens-auth-react
@@ -22,9 +25,9 @@ rm -rf node_modules/supertokens-web-js || true
rm -rf node_modules/supertokens-website || true
# We symlink the supertokens-web-js dep to ensure it's the same version (maybe linked locally)
-ln -s ../../../../../node_modules/supertokens-web-js node_modules/supertokens-web-js
+ln -s $REPO/node_modules/supertokens-web-js node_modules/supertokens-web-js
# We symlink the supertokens-website dep to ensure it's the same version (maybe linked locally)
-ln -s ../../../../../node_modules/supertokens-website node_modules/supertokens-website
+ln -s $REPO/node_modules/supertokens-website node_modules/supertokens-website
echo "$1 prepped."
diff --git a/test/server/index.js b/test/server/index.js
index fdaf08e7a..27a675c17 100644
--- a/test/server/index.js
+++ b/test/server/index.js
@@ -52,7 +52,7 @@ const UserRolesRaw = require("supertokens-node/lib/build/recipe/userroles/recipe
const UserRoles = require("supertokens-node/recipe/userroles");
const MultitenancyRaw = require("supertokens-node/lib/build/recipe/multitenancy/recipe").default;
-const Multitenancy = require("supertokens-node/lib/build/recipe/multitenancy/index");
+const Multitenancy = require("supertokens-node/recipe/multitenancy");
const AccountLinkingRaw = require("supertokens-node/lib/build/recipe/accountlinking/recipe").default;
const AccountLinking = require("supertokens-node/recipe/accountlinking");
@@ -66,6 +66,15 @@ const MultiFactorAuth = require("supertokens-node/recipe/multifactorauth");
const TOTPRaw = require("supertokens-node/lib/build/recipe/totp/recipe").default;
const TOTP = require("supertokens-node/recipe/totp");
+let OAuth2ProviderRaw = undefined;
+let OAuth2Provider = undefined;
+try {
+ OAuth2ProviderRaw = require("supertokens-node/lib/build/recipe/oauth2provider/recipe").default;
+ OAuth2Provider = require("supertokens-node/recipe/oauth2provider");
+} catch {
+ // OAuth2Provider is not supported by the tested version of the node SDK
+}
+
const OTPAuth = require("otpauth");
let generalErrorSupported;
@@ -491,6 +500,7 @@ app.get("/test/featureFlags", (req, res) => {
available.push("accountlinking");
available.push("mfa");
available.push("recipeConfig");
+ available.push("oauth2");
available.push("accountlinking-fixes");
res.send({
@@ -498,6 +508,15 @@ app.get("/test/featureFlags", (req, res) => {
});
});
+app.post("/test/create-oauth2-client", async (req, res, next) => {
+ try {
+ const { client } = await OAuth2Provider.createOAuth2Client(req.body);
+ res.send({ client });
+ } catch (e) {
+ next(e);
+ }
+});
+
app.use(errorHandler());
app.use(async (err, req, res, next) => {
@@ -541,6 +560,9 @@ function initST() {
UserMetadataRaw.reset();
MultiFactorAuthRaw.reset();
TOTPRaw.reset();
+ if (OAuth2ProviderRaw) {
+ OAuth2ProviderRaw.reset();
+ }
EmailVerificationRaw.reset();
EmailPasswordRaw.reset();
@@ -740,6 +762,9 @@ function initST() {
}),
],
];
+ if (OAuth2Provider) {
+ recipeList.push(["oauth2provider", OAuth2Provider.init()]);
+ }
passwordlessConfig = {
contactMethod: "EMAIL_OR_PHONE",
diff --git a/test/server/package-lock.json b/test/server/package-lock.json
index bcca9a74c..6cf95278b 100644
--- a/test/server/package-lock.json
+++ b/test/server/package-lock.json
@@ -16,7 +16,7 @@
"express": "4.17.1",
"morgan": "^1.10.0",
"otpauth": "^9.2.0",
- "supertokens-node": "latest"
+ "supertokens-node": "github:supertokens/supertokens-node#feat/oauth2/base"
}
},
"node_modules/accepts": {
@@ -995,6 +995,11 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/set-cookie-parser": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.0.tgz",
+ "integrity": "sha512-lXLOiqpkUumhRdFF3k1osNXCy9akgx/dyPZ5p8qAg9seJzXr5ZrlqZuWIMuY6ejOsVLE6flJ5/h3lsn57fQ/PQ=="
+ },
"node_modules/set-function-length": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz",
@@ -1041,9 +1046,8 @@
"integrity": "sha512-r0JFBjkMIdep3Lbk3JA+MpnpuOtw4RSyrlRAbrzMcxwiYco3GFWl/daimQZ5b1forOiUODpOlXbSOljP/oyurg=="
},
"node_modules/supertokens-node": {
- "version": "18.0.2",
- "resolved": "https://registry.npmjs.org/supertokens-node/-/supertokens-node-18.0.2.tgz",
- "integrity": "sha512-ihmCLz9FnA05gniBvUTjoeW9c8WZsMwYBNxWnwN9QICNYfu32giBtQP2ncaTBnO9vqImagBcuCtMA/3v8G9AGg==",
+ "version": "20.0.2",
+ "resolved": "git+ssh://git@github.com/supertokens/supertokens-node.git#905b5cd6e9babe50488318e32295a353523b8069",
"dependencies": {
"content-type": "^1.0.5",
"cookie": "0.4.0",
@@ -1055,6 +1059,7 @@
"nodemailer": "^6.7.2",
"pkce-challenge": "^3.0.0",
"psl": "1.8.0",
+ "set-cookie-parser": "^2.6.0",
"supertokens-js-override": "^0.0.4",
"twilio": "^4.19.3"
}
@@ -1976,6 +1981,11 @@
"send": "0.17.1"
}
},
+ "set-cookie-parser": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.0.tgz",
+ "integrity": "sha512-lXLOiqpkUumhRdFF3k1osNXCy9akgx/dyPZ5p8qAg9seJzXr5ZrlqZuWIMuY6ejOsVLE6flJ5/h3lsn57fQ/PQ=="
+ },
"set-function-length": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz",
@@ -2013,9 +2023,8 @@
"integrity": "sha512-r0JFBjkMIdep3Lbk3JA+MpnpuOtw4RSyrlRAbrzMcxwiYco3GFWl/daimQZ5b1forOiUODpOlXbSOljP/oyurg=="
},
"supertokens-node": {
- "version": "18.0.2",
- "resolved": "https://registry.npmjs.org/supertokens-node/-/supertokens-node-18.0.2.tgz",
- "integrity": "sha512-ihmCLz9FnA05gniBvUTjoeW9c8WZsMwYBNxWnwN9QICNYfu32giBtQP2ncaTBnO9vqImagBcuCtMA/3v8G9AGg==",
+ "version": "git+ssh://git@github.com/supertokens/supertokens-node.git#905b5cd6e9babe50488318e32295a353523b8069",
+ "from": "supertokens-node@github:supertokens/supertokens-node#feat/oauth2/base",
"requires": {
"content-type": "^1.0.5",
"cookie": "0.4.0",
@@ -2027,6 +2036,7 @@
"nodemailer": "^6.7.2",
"pkce-challenge": "^3.0.0",
"psl": "1.8.0",
+ "set-cookie-parser": "^2.6.0",
"supertokens-js-override": "^0.0.4",
"twilio": "^4.19.3"
},
diff --git a/test/server/package.json b/test/server/package.json
index 3bce6a99c..a36e4efd1 100644
--- a/test/server/package.json
+++ b/test/server/package.json
@@ -16,6 +16,6 @@
"express": "4.17.1",
"morgan": "^1.10.0",
"otpauth": "^9.2.0",
- "supertokens-node": "latest"
+ "supertokens-node": "github:supertokens/supertokens-node#feat/oauth2/base"
}
}
diff --git a/test/server/utils.js b/test/server/utils.js
index 5e7bb8c8a..64e242071 100644
--- a/test/server/utils.js
+++ b/test/server/utils.js
@@ -20,8 +20,8 @@ let axios = require("axios").default;
module.exports.executeCommand = async function (cmd) {
return new Promise((resolve, reject) => {
exec(cmd, (err, stdout, stderr) => {
- console.log(err, stderr, stdout);
if (err) {
+ // console.log({ err });
reject(err);
return;
}
@@ -180,9 +180,14 @@ module.exports.startST = async function (config = {}) {
},
body: JSON.stringify({
appId,
- emailPasswordEnabled: true,
- thirdPartyEnabled: true,
- passwordlessEnabled: true,
+ firstFactors: [
+ "emailpassword",
+ "thirdparty",
+ "otp-phone",
+ "link-phone",
+ "otp-email",
+ "link-email",
+ ],
coreConfig: config.coreConfig,
}),
});
diff --git a/test/unit/componentOverrides.test.tsx b/test/unit/componentOverrides.test.tsx
index b83c106bf..b3025c76d 100644
--- a/test/unit/componentOverrides.test.tsx
+++ b/test/unit/componentOverrides.test.tsx
@@ -10,6 +10,7 @@ import { ComponentOverrideMap as PasswordlessOverrideMap } from "../../lib/ts/re
import { ComponentOverrideMap as TOTPOverrideMap } from "../../lib/ts/recipe/totp/types";
import { ComponentOverrideMap as MFAOverrideMap } from "../../lib/ts/recipe/multifactorauth/types";
import { ComponentOverrideMap as AuthRecipeOverrideMap } from "../../lib/ts/recipe/authRecipe/types";
+import { ComponentOverrideMap as OAuth2ProviderOverrideMap } from "../../lib/ts/recipe/oauth2provider/types";
import "@testing-library/jest-dom";
import EmailPassword from "../../lib/ts/recipe/emailpassword/recipe";
@@ -56,6 +57,7 @@ import { FactorChooserHeader } from "../../lib/ts/recipe/multifactorauth/compone
import { FactorList } from "../../lib/ts/recipe/multifactorauth/components/themes/factorChooser/factorList";
import { FactorOption } from "../../lib/ts/recipe/multifactorauth/components/themes/factorChooser/factorOption";
import { AuthPageComponentList, AuthPageFooter, AuthPageHeader } from "../../lib/ts/ui";
+import { OAuth2LogoutScreenInner } from "../../lib/ts/recipe/oauth2provider/components/themes/oauth2LogoutScreen/OAuth2LogoutScreenInner";
type AllComponentsOverrideMap = AuthRecipeOverrideMap &
EmailPasswordOverrideMap &
@@ -63,7 +65,8 @@ type AllComponentsOverrideMap = AuthRecipeOverrideMap &
EmailVerificationOverrideMap &
PasswordlessOverrideMap &
TOTPOverrideMap &
- MFAOverrideMap;
+ MFAOverrideMap &
+ OAuth2ProviderOverrideMap;
const makeOverride = () => () => Override ;
const WithProvider: React.FC = ({ overrideMap, children }) => {
@@ -131,6 +134,7 @@ describe("Theme component overrides", () => {
AuthPageComponentList_Override: AuthPageComponentList,
AuthPageFooter_Override: AuthPageFooter,
AuthPageHeader_Override: AuthPageHeader,
+ OAuth2LogoutScreenInner_Override: OAuth2LogoutScreenInner,
};
Object.entries(overrides).forEach(([key, comp]) => {
@@ -157,6 +161,7 @@ describe("Theme component overrides", () => {
},
verifyEmailLinkClickedScreen: { style: `` },
sendVerifyEmailScreen: { style: `` },
+ oauth2LogoutScreen: { style: `` },
},
},
];
diff --git a/test/unit/recipe/emailpassword/emailPassword.test.tsx b/test/unit/recipe/emailpassword/emailPassword.test.tsx
index da30ea14c..52e7473f6 100644
--- a/test/unit/recipe/emailpassword/emailPassword.test.tsx
+++ b/test/unit/recipe/emailpassword/emailPassword.test.tsx
@@ -628,6 +628,11 @@ describe("EmailPassword", function () {
},
}).authReact(SuperTokens.getInstanceOrThrow().appInfo, false);
- assert((await EmailPassword.getInstanceOrThrow().getRedirectUrl({ action: "RESET_PASSWORD" }, {})) === null);
+ assert(
+ (await EmailPassword.getInstanceOrThrow().getRedirectUrl(
+ { action: "RESET_PASSWORD", tenantIdFromQueryParams: undefined },
+ {}
+ )) === null
+ );
});
});
diff --git a/test/unit/recipe/thirdparty/thirdParty.test.ts b/test/unit/recipe/thirdparty/thirdParty.test.ts
index 05fc6a43b..6b454b42e 100644
--- a/test/unit/recipe/thirdparty/thirdParty.test.ts
+++ b/test/unit/recipe/thirdparty/thirdParty.test.ts
@@ -386,6 +386,7 @@ describe("ThirdParty", function () {
userContext: {
key: "value",
},
+ shouldTryLinkingWithSessionUser: false,
});
throw new Error("redirectToThirdPartyLogin should have failed but didnt");
} catch (e) {
diff --git a/test/with-typescript/src/App.tsx b/test/with-typescript/src/App.tsx
index 4f4565349..4adf3b83a 100644
--- a/test/with-typescript/src/App.tsx
+++ b/test/with-typescript/src/App.tsx
@@ -37,6 +37,8 @@ import { SessionPreBuiltUI, AccessDeniedScreen } from "../../../recipe/session/p
import { LinkClicked as PasswordlessLinkClicked } from "../../../recipe/passwordless/prebuiltui";
import EmailVerification from "../../../recipe/emailverification";
import MultiFactorAuth from "../../../recipe/multifactorauth";
+import OAuth2Provider from "../../../recipe/oauth2provider";
+import { OAuth2ProviderPreBuiltUI } from "../../../recipe/oauth2provider/prebuiltui";
import { DateProviderReference } from "../../../utils/dateProvider";
import { DateProviderInput, DateProviderInterface } from "../../../utils/dateProvider/types";
@@ -281,6 +283,9 @@ function getRecipeList() {
}
return context;
},
+ postAPIHook: async (context) => {
+ context.userContext;
+ },
override: {
functions: (oI) => {
return {
@@ -1105,8 +1110,41 @@ function testAuthPagePropTypes() {
// @ts-expect-error This has to be a valid first factor
,
,
];
}
+
+SuperTokens.init({
+ appInfo: {} as any,
+ recipeList: [
+ OAuth2Provider.init({
+ oauth2LogoutScreen: {
+ style: "",
+ },
+ style: "",
+ getRedirectionURL: async (context, userContext) => {
+ if (context.action === "SUCCESS_OAUTH2") {
+ return undefined;
+ }
+ if (context.action === "CONTINUE_OAUTH2_AFTER_REFRESH") {
+ return undefined;
+ }
+ if (context.action === "POST_OAUTH2_LOGOUT_REDIRECT") {
+ return undefined;
+ }
+ return undefined;
+ },
+ }),
+ ],
+});
+
+EmailPassword.init({
+ async getRedirectionURL(context) {
+ if (context.action === "RESET_PASSWORD") {
+ return `/reset-password?tenantId=${context.tenantIdFromQueryParams}`;
+ }
+ return "";
+ },
+});
diff --git a/webJsInterfaceSupported.json b/webJsInterfaceSupported.json
index e13f2000f..e1f80b63d 100644
--- a/webJsInterfaceSupported.json
+++ b/webJsInterfaceSupported.json
@@ -1,4 +1,4 @@
{
"_comment": "contains the web js interface version that this package supports",
- "version": "0.9"
+ "version": "0.11"
}