@supertokens-plugins/rownd-nodejs 0.3.0-beta.6 → 0.3.0-beta.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -273,6 +273,7 @@ __export(index_exports, {
273
273
  HUB_LOGIN_PAGE_PATH: () => HUB_LOGIN_PAGE_PATH,
274
274
  HUB_VERIFY_EMAIL_PAGE_PATH: () => HUB_VERIFY_EMAIL_PAGE_PATH,
275
275
  INSTANT_AUTH_METHOD_ID: () => INSTANT_AUTH_METHOD_ID,
276
+ PASSWORDLESS_BYPASS_DEVICE_CONFIRMATION_PARAM: () => PASSWORDLESS_BYPASS_DEVICE_CONFIRMATION_PARAM,
276
277
  PLUGIN_ID: () => PLUGIN_ID,
277
278
  PLUGIN_SDK_VERSION: () => PLUGIN_SDK_VERSION,
278
279
  PLUGIN_VERSION: () => PLUGIN_VERSION,
@@ -280,6 +281,7 @@ __export(index_exports, {
280
281
  ROWND_JWT_CLAIMS: () => ROWND_JWT_CLAIMS,
281
282
  ROWND_PLUGIN_ERROR_MESSAGES: () => ROWND_PLUGIN_ERROR_MESSAGES,
282
283
  RowndPluginError: () => RowndPluginError,
284
+ createMagicLinkWithConfirmationBypass: () => createMagicLinkWithConfirmationBypass,
283
285
  default: () => index_default,
284
286
  getRowndClient: () => getRowndClient,
285
287
  init: () => init,
@@ -724,6 +726,7 @@ var DEFAULT_ROWND_SCHEMA = {
724
726
  };
725
727
  var HUB_LOGIN_PAGE_PATH = "/account/login";
726
728
  var HUB_VERIFY_EMAIL_PAGE_PATH = "/account/verify-email";
729
+ var PASSWORDLESS_BYPASS_DEVICE_CONFIRMATION_PARAM = "bypassDeviceConfirmation";
727
730
 
728
731
  // src/logger.ts
729
732
  var { logDebugMessage, enableDebugLogs } = buildLogger(
@@ -966,6 +969,109 @@ function getStringList(value) {
966
969
  function getErrorMessage(error) {
967
970
  return error instanceof Error ? error.message : "Unknown error";
968
971
  }
972
+ function getAppInfoString(value) {
973
+ return value.getAsStringDangerous();
974
+ }
975
+ function getWebsiteDomain(input) {
976
+ return getAppInfoString(input.stConfig.appInfo.getOrigin({
977
+ request: input.request,
978
+ userContext: input.userContext ?? {}
979
+ }));
980
+ }
981
+ function normalizeClientDomain(value) {
982
+ if (value.endsWith("://")) {
983
+ return value;
984
+ }
985
+ const parsed = new URL(value);
986
+ if (parsed.protocol === "http:" || parsed.protocol === "https:") {
987
+ return parsed.origin;
988
+ }
989
+ return `${parsed.protocol}//${parsed.host}`;
990
+ }
991
+ function resolveClientDomain(input) {
992
+ if (!input.clientDomain) {
993
+ return input.websiteDomain;
994
+ }
995
+ const resolved = input.pluginConfig.clientDomains?.[input.clientDomain];
996
+ if (!resolved) {
997
+ throw new Error(`Unknown clientDomain key: ${input.clientDomain}`);
998
+ }
999
+ return resolved;
1000
+ }
1001
+ function resolveAllowedClientDomain(input) {
1002
+ const websiteDomain = getWebsiteDomain(input);
1003
+ const resolvedClientDomain = resolveClientDomain({
1004
+ clientDomain: input.clientDomain,
1005
+ pluginConfig: input.pluginConfig,
1006
+ websiteDomain
1007
+ });
1008
+ const normalizedClientDomain = normalizeClientDomain(resolvedClientDomain);
1009
+ const allowed = [
1010
+ websiteDomain,
1011
+ ...Object.values(input.pluginConfig.clientDomains ?? {})
1012
+ ].map(normalizeClientDomain);
1013
+ if (!allowed.includes(normalizedClientDomain)) {
1014
+ throw new Error(`clientDomain is not allowed: ${resolvedClientDomain}`);
1015
+ }
1016
+ return normalizedClientDomain;
1017
+ }
1018
+ function normalizeRedirectToPathForClientDomain(redirectToPath, clientDomain) {
1019
+ if (!redirectToPath) {
1020
+ return void 0;
1021
+ }
1022
+ if (redirectToPath === "NATIVE_APP") {
1023
+ return redirectToPath;
1024
+ }
1025
+ if (redirectToPath.startsWith("//")) {
1026
+ throw new Error("redirectToPath cannot be schemaless");
1027
+ }
1028
+ const normalizedClientDomain = normalizeClientDomain(clientDomain);
1029
+ const redirectUrl = new URL(
1030
+ redirectToPath,
1031
+ normalizedClientDomain.endsWith("://") ? "http://localhost" : normalizedClientDomain
1032
+ );
1033
+ const hasExplicitScheme = /^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(redirectToPath);
1034
+ if (hasExplicitScheme) {
1035
+ if (redirectUrl.protocol !== "http:" && redirectUrl.protocol !== "https:") {
1036
+ throw new Error("redirectToPath must be http(s) or relative");
1037
+ }
1038
+ if (redirectUrl.origin !== normalizedClientDomain) {
1039
+ throw new Error("redirectToPath must match clientDomain");
1040
+ }
1041
+ }
1042
+ return `${redirectUrl.pathname}${redirectUrl.search}${redirectUrl.hash}`;
1043
+ }
1044
+ function assertAllowedBypassRedirectPath(pluginConfig2, redirectToPath) {
1045
+ if (!redirectToPath) {
1046
+ throw new Error("redirectToPath is required for confirmation bypass magic links");
1047
+ }
1048
+ const allowedRedirectPaths = pluginConfig2.crossDeviceConfirmationBypass?.allowedRedirectPaths ?? [];
1049
+ if (allowedRedirectPaths.length === 0) {
1050
+ throw new Error("crossDeviceConfirmationBypass.allowedRedirectPaths must be configured");
1051
+ }
1052
+ if (!allowedRedirectPaths.includes(redirectToPath)) {
1053
+ throw new Error(`redirectToPath is not allowed for confirmation bypass: ${redirectToPath}`);
1054
+ }
1055
+ }
1056
+ function getMagicLinkBootstrapParams(input) {
1057
+ return {
1058
+ appKey: input.appKey,
1059
+ apiDomain: input.apiDomain,
1060
+ apiBasePath: input.apiBasePath,
1061
+ ...input.appVariantId ? { appVariantId: input.appVariantId } : {},
1062
+ ...input.displayContext ? { displayContext: input.displayContext } : {},
1063
+ ...input.redirectToPath ? { redirectToPath: input.redirectToPath } : {},
1064
+ ...input.clientDomainKey ? { clientDomain: input.clientDomainKey } : {}
1065
+ };
1066
+ }
1067
+ function rewriteMagicLink(input) {
1068
+ return rewriteLinkToBaseUrl(
1069
+ input.magicLink,
1070
+ HUB_LOGIN_PAGE_PATH,
1071
+ input.clientDomain,
1072
+ input.bootstrapParams
1073
+ );
1074
+ }
969
1075
  function getRequestedAppVariantIdFromRequest(req) {
970
1076
  return req.getKeyValueFromQuery("app_variant_id");
971
1077
  }
@@ -984,12 +1090,19 @@ function getRequestedRedirectToPathFromRequest(req) {
984
1090
 
985
1091
  // src/config.ts
986
1092
  var pluginConfig;
1093
+ var superTokensConfig;
987
1094
  function setPluginConfig(config2) {
988
1095
  pluginConfig = config2;
989
1096
  }
990
1097
  function getPluginConfig() {
991
1098
  return pluginConfig;
992
1099
  }
1100
+ function setSuperTokensConfig(config2) {
1101
+ superTokensConfig = config2;
1102
+ }
1103
+ function getSuperTokensConfig() {
1104
+ return superTokensConfig;
1105
+ }
993
1106
  function assertRowndAppVariantIsConfigured(appVariantId) {
994
1107
  if (!appVariantId) {
995
1108
  return;
@@ -1070,7 +1183,10 @@ function buildSignInMethodsConfig(methodsArray) {
1070
1183
  },
1071
1184
  apple: {
1072
1185
  enabled: !!appleMethod,
1073
- client_id: getStringMethodProperty(appleMethod, "clientId") ?? ""
1186
+ client_id: getStringMethodProperty(appleMethod, "clientId") ?? "",
1187
+ ...getStringMethodProperty(appleMethod, "webClientType") !== void 0 ? { web_client_type: getStringMethodProperty(appleMethod, "webClientType") } : {},
1188
+ ...getStringMethodProperty(appleMethod, "iosClientType") !== void 0 ? { ios_client_type: getStringMethodProperty(appleMethod, "iosClientType") } : {},
1189
+ ...getStringMethodProperty(appleMethod, "androidClientType") !== void 0 ? { android_client_type: getStringMethodProperty(appleMethod, "androidClientType") } : {}
1074
1190
  },
1075
1191
  anonymous: {
1076
1192
  enabled: !!anonymousMethod && anonymousType !== "instant",
@@ -1344,6 +1460,7 @@ function buildAuthMobileConfig(authMobile) {
1344
1460
 
1345
1461
  // src/rownd-compatibility.ts
1346
1462
  var import_supertokens_node = __toESM(require("supertokens-node"));
1463
+ var import_usermetadata2 = __toESM(require("supertokens-node/recipe/usermetadata"));
1347
1464
  var IDENTITY_USER_DATA_FIELDS = /* @__PURE__ */ new Set([
1348
1465
  "user_id",
1349
1466
  "email",
@@ -1518,6 +1635,140 @@ function buildRowndSessionClaimPayload(input) {
1518
1635
  ...anonymousId ? { anonymous_id: anonymousId } : {}
1519
1636
  };
1520
1637
  }
1638
+ function normalizeRowndOAuthScopes(scopes) {
1639
+ return [...new Set(scopes.filter((scope) => scope.length > 0))];
1640
+ }
1641
+ function getRowndOAuthAudience(input) {
1642
+ const requested = input.requestedResource ?? input.requestedAudience;
1643
+ if (requested?.startsWith("app:")) {
1644
+ return requested;
1645
+ }
1646
+ return void 0;
1647
+ }
1648
+ function applyRowndOAuthResourceParams(input) {
1649
+ const resource = firstString(input.params.resource);
1650
+ const audience = firstString(input.params.audience);
1651
+ const rowndAudience = getRowndOAuthAudience({
1652
+ requestedResource: resource,
1653
+ requestedAudience: audience
1654
+ });
1655
+ if (!rowndAudience) {
1656
+ return;
1657
+ }
1658
+ input.userContext.rowndOAuthAudience = rowndAudience;
1659
+ input.params.audience = audience ?? rowndAudience;
1660
+ delete input.params.resource;
1661
+ }
1662
+ async function buildRowndOAuthPayload(input) {
1663
+ const currentPayload = input.currentPayload ?? {};
1664
+ const standardClaims = input.user ? await buildStandardOAuthClaims(input.user, input.scopes) : {};
1665
+ const rowndClaims = input.user ? await buildRowndOAuthSessionClaims(input.user, currentPayload) : {};
1666
+ const audience = getRowndOAuthAudience({
1667
+ requestedAudience: typeof input.userContext?.rowndOAuthAudience === "string" ? input.userContext.rowndOAuthAudience : void 0
1668
+ });
1669
+ return {
1670
+ ...currentPayload,
1671
+ ...standardClaims,
1672
+ ...rowndClaims,
1673
+ ...audience ? { aud: audience } : {}
1674
+ };
1675
+ }
1676
+ async function buildRowndOAuthUserInfo(input) {
1677
+ const standardClaims = await buildStandardOAuthClaims(
1678
+ input.user,
1679
+ input.scopes
1680
+ );
1681
+ const rowndClaims = pickOAuthUserInfoRowndClaims(input.accessTokenPayload);
1682
+ return {
1683
+ ...input.currentPayload,
1684
+ ...standardClaims,
1685
+ ...rowndClaims
1686
+ };
1687
+ }
1688
+ async function buildStandardOAuthClaims(user, scopes) {
1689
+ const claims = {};
1690
+ const metadata = await getRowndMetadata(user.id);
1691
+ const rowndData = isJsonRecord(metadata.original_rownd_user?.data) ? metadata.original_rownd_user.data : {};
1692
+ const verifiedData = isJsonRecord(metadata.original_rownd_user?.verified_data) ? metadata.original_rownd_user.verified_data : {};
1693
+ if (scopes.includes("email")) {
1694
+ const email = firstString(rowndData.email) ?? user.emails[0];
1695
+ if (email) {
1696
+ claims.email = email;
1697
+ claims.email_verified = isOAuthClaimVerified(
1698
+ verifiedData.email,
1699
+ email,
1700
+ user.loginMethods.some(
1701
+ (method) => method.hasSameEmailAs(email) && method.verified
1702
+ )
1703
+ );
1704
+ }
1705
+ }
1706
+ if (scopes.includes("phone")) {
1707
+ const phoneNumber = firstString(rowndData.phone_number) ?? user.phoneNumbers[0];
1708
+ if (phoneNumber) {
1709
+ claims.phone_number = phoneNumber;
1710
+ claims.phone_number_verified = isOAuthClaimVerified(
1711
+ verifiedData.phone_number,
1712
+ phoneNumber,
1713
+ user.loginMethods.some(
1714
+ (method) => method.hasSamePhoneNumberAs(phoneNumber) && method.verified
1715
+ )
1716
+ );
1717
+ }
1718
+ }
1719
+ if (scopes.includes("profile")) {
1720
+ const givenName = firstString(rowndData.first_name);
1721
+ const familyName = firstString(rowndData.last_name);
1722
+ const name = [givenName, familyName].filter(Boolean).join(" ");
1723
+ if (name) claims.name = name;
1724
+ if (givenName) claims.given_name = givenName;
1725
+ if (familyName) claims.family_name = familyName;
1726
+ if (typeof metadata.original_rownd_user?.data?.updated_at === "string") {
1727
+ claims.updated_at = metadata.original_rownd_user.data.updated_at;
1728
+ }
1729
+ }
1730
+ return claims;
1731
+ }
1732
+ async function getRowndMetadata(userId) {
1733
+ const metadata = await import_usermetadata2.default.getUserMetadata(userId);
1734
+ return metadata.metadata || {};
1735
+ }
1736
+ function pickOAuthUserInfoRowndClaims(payload) {
1737
+ const claims = {};
1738
+ for (const key of [
1739
+ "app_user_id",
1740
+ "auth_level",
1741
+ "is_verified_user",
1742
+ "is_anonymous",
1743
+ "anonymous_id",
1744
+ "https://auth.rownd.io/app_user_id",
1745
+ "https://auth.rownd.io/auth_level",
1746
+ "https://auth.rownd.io/is_verified_user",
1747
+ "https://auth.rownd.io/is_anonymous"
1748
+ ]) {
1749
+ if (payload[key] !== void 0) {
1750
+ claims[key] = payload[key];
1751
+ }
1752
+ }
1753
+ return claims;
1754
+ }
1755
+ function firstString(value) {
1756
+ if (Array.isArray(value)) {
1757
+ return value.find((entry) => typeof entry === "string");
1758
+ }
1759
+ return typeof value === "string" && value.length > 0 ? value : void 0;
1760
+ }
1761
+ function isOAuthClaimVerified(value, expectedValue, fallback) {
1762
+ return value === true || value === expectedValue || fallback;
1763
+ }
1764
+ async function buildRowndOAuthSessionClaims(user, currentPayload) {
1765
+ return buildRowndSessionClaimPayload({
1766
+ userId: user.id,
1767
+ user,
1768
+ metadata: await getRowndMetadata(user.id),
1769
+ currentPayload
1770
+ });
1771
+ }
1521
1772
  async function shouldLinkRowndAccounts(input) {
1522
1773
  const [newAccountInfo, , session] = input;
1523
1774
  if (!session) {
@@ -1665,7 +1916,7 @@ var import_emailverification = __toESM(require("supertokens-node/recipe/emailver
1665
1916
  var import_passwordless = __toESM(require("supertokens-node/recipe/passwordless"));
1666
1917
  var import_session = __toESM(require("supertokens-node/recipe/session"));
1667
1918
  var import_claims = require("supertokens-node/recipe/session/claims");
1668
- var import_usermetadata2 = __toESM(require("supertokens-node/recipe/usermetadata"));
1919
+ var import_usermetadata3 = __toESM(require("supertokens-node/recipe/usermetadata"));
1669
1920
  async function importUser(stUser, config2) {
1670
1921
  const headers = {
1671
1922
  "Content-Type": "application/json"
@@ -1704,7 +1955,7 @@ async function recordRowndAppVariantForUser(userId, appVariantId) {
1704
1955
  if (appVariants.includes(appVariantId)) {
1705
1956
  return;
1706
1957
  }
1707
- await import_usermetadata2.default.updateUserMetadata(userId, {
1958
+ await import_usermetadata3.default.updateUserMetadata(userId, {
1708
1959
  ...metadata,
1709
1960
  original_rownd_user: {
1710
1961
  ...originalRowndUser,
@@ -1736,8 +1987,78 @@ async function buildRowndSessionClaims(userId, currentPayload = {}, appVariantId
1736
1987
  appVariantId
1737
1988
  });
1738
1989
  }
1990
+ async function createMagicLinkWithConfirmationBypass(input) {
1991
+ const hasEmail = typeof input.email === "string" && input.email.length > 0;
1992
+ const hasPhoneNumber = typeof input.phoneNumber === "string" && input.phoneNumber.length > 0;
1993
+ if (hasEmail === hasPhoneNumber) {
1994
+ throw new Error("Exactly one of email or phoneNumber is required");
1995
+ }
1996
+ const stConfig = getSuperTokensConfig();
1997
+ if (!stConfig) {
1998
+ throw new Error("SuperTokens config is not initialized");
1999
+ }
2000
+ const pluginConfig2 = getPluginConfig();
2001
+ if (!pluginConfig2) {
2002
+ throw new Error("Rownd plugin config is not initialized");
2003
+ }
2004
+ const tenantId = input.tenantId ?? PUBLIC_TENANT_ID;
2005
+ const appVariantId = input.appVariantId;
2006
+ assertRowndAppVariantIsConfigured(appVariantId);
2007
+ const clientDomain = resolveAllowedClientDomain({
2008
+ clientDomain: input.clientDomain,
2009
+ pluginConfig: pluginConfig2,
2010
+ stConfig,
2011
+ request: input.request,
2012
+ userContext: input.userContext
2013
+ });
2014
+ const redirectToPath = normalizeRedirectToPathForClientDomain(input.redirectToPath, clientDomain);
2015
+ assertAllowedBypassRedirectPath(pluginConfig2, redirectToPath);
2016
+ const userContext = {
2017
+ ...input.userContext ?? {},
2018
+ ...input.displayContext ? { rowndDisplayContext: input.displayContext } : {},
2019
+ rowndRedirectToPath: redirectToPath,
2020
+ ...input.clientDomain ? { rowndClientDomain: input.clientDomain } : {},
2021
+ ...appVariantId ? { rowndAppVariantId: appVariantId } : {}
2022
+ };
2023
+ const codeInfo = hasEmail ? await import_passwordless.default.createCode({
2024
+ email: input.email,
2025
+ tenantId,
2026
+ session: input.session,
2027
+ userContext
2028
+ }) : await import_passwordless.default.createCode({
2029
+ phoneNumber: input.phoneNumber,
2030
+ tenantId,
2031
+ session: input.session,
2032
+ userContext
2033
+ });
2034
+ if (codeInfo.status !== "OK") {
2035
+ throw new Error("Failed to create magic link");
2036
+ }
2037
+ const magicLink = `${getWebsiteDomain({
2038
+ stConfig,
2039
+ request: input.request,
2040
+ userContext
2041
+ })}${getAppInfoString(stConfig.appInfo.websiteBasePath)}/verify?preAuthSessionId=${encodeURIComponent(
2042
+ codeInfo.preAuthSessionId
2043
+ )}&tenantId=${encodeURIComponent(tenantId)}#${encodeURIComponent(codeInfo.linkCode)}`;
2044
+ const rewrittenUrl = new URL(rewriteMagicLink({
2045
+ magicLink,
2046
+ clientDomain,
2047
+ bootstrapParams: getMagicLinkBootstrapParams({
2048
+ appKey: pluginConfig2.rowndAppKey,
2049
+ apiDomain: getAppInfoString(stConfig.appInfo.apiDomain),
2050
+ apiBasePath: getAppInfoString(stConfig.appInfo.apiBasePath),
2051
+ appVariantId,
2052
+ displayContext: input.displayContext,
2053
+ redirectToPath,
2054
+ clientDomainKey: input.clientDomain
2055
+ })
2056
+ }));
2057
+ rewrittenUrl.searchParams.set(PASSWORDLESS_BYPASS_DEVICE_CONFIRMATION_PARAM, "true");
2058
+ return rewrittenUrl.toString();
2059
+ }
1739
2060
  async function getUserMetadata(userId) {
1740
- const metadata = await import_usermetadata2.default.getUserMetadata(userId);
2061
+ const metadata = await import_usermetadata3.default.getUserMetadata(userId);
1741
2062
  return metadata.metadata || {};
1742
2063
  }
1743
2064
  function getPendingVerifications(metadata) {
@@ -1894,7 +2215,7 @@ async function updateUserData(userId, inputData) {
1894
2215
  ...metadata,
1895
2216
  ...inputData
1896
2217
  };
1897
- await import_usermetadata2.default.updateUserMetadata(userId, updatedMetadata);
2218
+ await import_usermetadata3.default.updateUserMetadata(userId, updatedMetadata);
1898
2219
  return getUserById(userId);
1899
2220
  }
1900
2221
  async function startPendingEmailVerification(input) {
@@ -1914,7 +2235,7 @@ async function startPendingEmailVerification(input) {
1914
2235
  );
1915
2236
  }
1916
2237
  if (pendingEmailVerifications.length > 0) {
1917
- await import_usermetadata2.default.updateUserMetadata(input.userId, {
2238
+ await import_usermetadata3.default.updateUserMetadata(input.userId, {
1918
2239
  ...metadata,
1919
2240
  rownd_pending_verification: pendingVerifications.filter(
1920
2241
  (pendingVerification2) => pendingVerification2.field !== "email"
@@ -1937,7 +2258,7 @@ async function startPendingEmailVerification(input) {
1937
2258
  value: input.email,
1938
2259
  created_at: (/* @__PURE__ */ new Date()).toISOString()
1939
2260
  };
1940
- await import_usermetadata2.default.updateUserMetadata(input.userId, {
2261
+ await import_usermetadata3.default.updateUserMetadata(input.userId, {
1941
2262
  ...metadata,
1942
2263
  rownd_pending_verification: [
1943
2264
  ...pendingVerifications.filter(
@@ -2058,7 +2379,7 @@ async function completePendingEmailVerification(input) {
2058
2379
  )
2059
2380
  )
2060
2381
  };
2061
- await import_usermetadata2.default.updateUserMetadata(metadataUserId, updatedMetadata);
2382
+ await import_usermetadata3.default.updateUserMetadata(metadataUserId, updatedMetadata);
2062
2383
  }
2063
2384
  function isMatchingPendingEmailVerification(verification, email) {
2064
2385
  return verification.field === "email" && verification.value === email;
@@ -2069,7 +2390,7 @@ async function updateUserMetadata(userId, inputMeta) {
2069
2390
  ...metadata,
2070
2391
  ...inputMeta
2071
2392
  };
2072
- await import_usermetadata2.default.updateUserMetadata(userId, updatedMetadata);
2393
+ await import_usermetadata3.default.updateUserMetadata(userId, updatedMetadata);
2073
2394
  return {
2074
2395
  id: userId,
2075
2396
  meta: Object.fromEntries(
@@ -2090,6 +2411,9 @@ var import_crypto = require("crypto");
2090
2411
  var import_supertokens_node3 = __toESM(require("supertokens-node"));
2091
2412
  var import_session2 = __toESM(require("supertokens-node/recipe/session"));
2092
2413
  var import_thirdparty = __toESM(require("supertokens-node/recipe/thirdparty"));
2414
+ function isBodyString(body, key) {
2415
+ return isRecord(body) && typeof body[key] === "string" && body[key].length > 0;
2416
+ }
2093
2417
  function handleGetAppConfig(deps) {
2094
2418
  return async (req) => {
2095
2419
  const appVariantId = getRequestedAppVariantIdFromRequest(req);
@@ -2110,6 +2434,43 @@ function handleGetAppConfig(deps) {
2110
2434
  };
2111
2435
  };
2112
2436
  }
2437
+ function handleValidatePasswordlessConfirmationBypass(deps) {
2438
+ return async (req) => {
2439
+ try {
2440
+ const body = await getJsonBody(req);
2441
+ const clientDomain = isBodyString(body, "clientDomain") ? body.clientDomain : void 0;
2442
+ const redirectToPath = isBodyString(body, "redirectToPath") ? body.redirectToPath : void 0;
2443
+ const appVariantId = isBodyString(body, "appVariantId") ? body.appVariantId : void 0;
2444
+ assertRowndAppVariantIsConfigured(appVariantId);
2445
+ const resolvedClientDomain = resolveAllowedClientDomain({
2446
+ clientDomain,
2447
+ pluginConfig: deps.pluginConfig,
2448
+ stConfig: deps.stConfig,
2449
+ request: req
2450
+ });
2451
+ const normalizedRedirectToPath = normalizeRedirectToPathForClientDomain(
2452
+ redirectToPath,
2453
+ resolvedClientDomain
2454
+ );
2455
+ assertAllowedBypassRedirectPath(
2456
+ deps.pluginConfig,
2457
+ normalizedRedirectToPath
2458
+ );
2459
+ return {
2460
+ status: "OK",
2461
+ bypass: true
2462
+ };
2463
+ } catch (error) {
2464
+ logDebugMessage(
2465
+ `Passwordless confirmation bypass validation failed. Error: ${getErrorMessage(error)}`
2466
+ );
2467
+ return {
2468
+ status: "ERROR",
2469
+ bypass: false
2470
+ };
2471
+ }
2472
+ };
2473
+ }
2113
2474
  function handleGuestLogin(deps) {
2114
2475
  return async (req, res, _session, userContext) => {
2115
2476
  const startedAt = Date.now();
@@ -2507,6 +2868,7 @@ var init = createPluginInitFunction(
2507
2868
  }
2508
2869
  },
2509
2870
  routeHandlers(stConfig) {
2871
+ setSuperTokensConfig(stConfig);
2510
2872
  const apiBasePath = stConfig.appInfo.apiBasePath.getAsStringDangerous();
2511
2873
  hubBootstrapParams = {
2512
2874
  apiDomain: stConfig.appInfo.apiDomain.getAsStringDangerous(),
@@ -2537,6 +2899,13 @@ var init = createPluginInitFunction(
2537
2899
  method: "post",
2538
2900
  handler: withRequestHandler(handleMigrate(routeHandlerDeps))
2539
2901
  },
2902
+ {
2903
+ path: `${apiBasePath}/plugin/passwordless-cross-device-confirmation/validate`,
2904
+ method: "post",
2905
+ handler: withRequestHandler(
2906
+ handleValidatePasswordlessConfirmationBypass(routeHandlerDeps)
2907
+ )
2908
+ },
2540
2909
  {
2541
2910
  path: `${apiBasePath}/plugin/migrate-session`,
2542
2911
  method: "post",
@@ -2597,6 +2966,74 @@ var init = createPluginInitFunction(
2597
2966
  };
2598
2967
  },
2599
2968
  overrideMap: {
2969
+ oauth2provider: {
2970
+ recipeInitRequired: false,
2971
+ functions: (originalImplementation) => ({
2972
+ ...originalImplementation,
2973
+ getRequestedScopes: async (input) => {
2974
+ const scopes = await originalImplementation.getRequestedScopes(
2975
+ input
2976
+ );
2977
+ return normalizeRowndOAuthScopes(scopes);
2978
+ },
2979
+ buildAccessTokenPayload: async (input) => {
2980
+ const payload = await originalImplementation.buildAccessTokenPayload(
2981
+ input
2982
+ );
2983
+ return buildRowndOAuthPayload({
2984
+ user: input.user,
2985
+ client: input.client,
2986
+ scopes: input.scopes,
2987
+ currentPayload: payload,
2988
+ userContext: input.userContext
2989
+ });
2990
+ },
2991
+ buildIdTokenPayload: async (input) => {
2992
+ const payload = await originalImplementation.buildIdTokenPayload(
2993
+ input
2994
+ );
2995
+ return buildRowndOAuthPayload({
2996
+ user: input.user,
2997
+ client: input.client,
2998
+ scopes: input.scopes,
2999
+ currentPayload: payload,
3000
+ userContext: input.userContext
3001
+ });
3002
+ },
3003
+ buildUserInfo: async (input) => {
3004
+ const payload = await originalImplementation.buildUserInfo(input);
3005
+ return buildRowndOAuthUserInfo({
3006
+ user: input.user,
3007
+ accessTokenPayload: input.accessTokenPayload,
3008
+ scopes: input.scopes,
3009
+ currentPayload: payload
3010
+ });
3011
+ }
3012
+ }),
3013
+ apis: (originalImplementation) => ({
3014
+ ...originalImplementation,
3015
+ authGET: async (input) => {
3016
+ if (originalImplementation.authGET === void 0) {
3017
+ throw new Error("OAuth2Provider authGET is unavailable");
3018
+ }
3019
+ applyRowndOAuthResourceParams({
3020
+ params: input.params,
3021
+ userContext: input.userContext
3022
+ });
3023
+ return originalImplementation.authGET(input);
3024
+ },
3025
+ tokenPOST: async (input) => {
3026
+ if (originalImplementation.tokenPOST === void 0) {
3027
+ throw new Error("OAuth2Provider tokenPOST is unavailable");
3028
+ }
3029
+ applyRowndOAuthResourceParams({
3030
+ params: input.body,
3031
+ userContext: input.userContext
3032
+ });
3033
+ return originalImplementation.tokenPOST(input);
3034
+ }
3035
+ })
3036
+ },
2600
3037
  passwordless: {
2601
3038
  config: (config2) => {
2602
3039
  const originalEmailDeliveryOverride = config2.emailDelivery?.override;
@@ -2859,6 +3296,7 @@ var init = createPluginInitFunction(
2859
3296
  rowndAppSecret: config2.rowndAppSecret,
2860
3297
  enableDebugLogs: config2.enableDebugLogs,
2861
3298
  clientDomains: config2.clientDomains,
3299
+ crossDeviceConfirmationBypass: config2.crossDeviceConfirmationBypass,
2862
3300
  telemetry: config2.telemetry,
2863
3301
  schema: config2.schema,
2864
3302
  appConfig: config2.appConfig,
@@ -2887,6 +3325,7 @@ var index_default = { init };
2887
3325
  HUB_LOGIN_PAGE_PATH,
2888
3326
  HUB_VERIFY_EMAIL_PAGE_PATH,
2889
3327
  INSTANT_AUTH_METHOD_ID,
3328
+ PASSWORDLESS_BYPASS_DEVICE_CONFIRMATION_PARAM,
2890
3329
  PLUGIN_ID,
2891
3330
  PLUGIN_SDK_VERSION,
2892
3331
  PLUGIN_VERSION,
@@ -2894,6 +3333,7 @@ var index_default = { init };
2894
3333
  ROWND_JWT_CLAIMS,
2895
3334
  ROWND_PLUGIN_ERROR_MESSAGES,
2896
3335
  RowndPluginError,
3336
+ createMagicLinkWithConfirmationBypass,
2897
3337
  getRowndClient,
2898
3338
  init,
2899
3339
  setRowndClient