@supertokens-plugins/rownd-nodejs 0.3.0-beta.8 → 0.5.1
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/README.md +17 -16
- package/dist/bulkMigrate.js +15 -11
- package/dist/generateAppConfig.js +3 -1
- package/dist/index.js +44 -18
- package/dist/index.mjs +44 -18
- package/dist/initConfig.js +10 -0
- package/dist/setupCoreInstance.js +111 -46
- package/package.json +11 -1
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ npm install @supertokens-plugins/rownd-nodejs
|
|
|
15
15
|
Initialize the plugin in your SuperTokens backend configuration.
|
|
16
16
|
|
|
17
17
|
> [!IMPORTANT]
|
|
18
|
-
> This plugin requires the `Session` and `UserMetadata` recipes
|
|
18
|
+
> This plugin always requires the `Session` and `UserMetadata` recipes. Enable `Passwordless` for email/phone, `ThirdParty` for Google/Apple/guest/anonymous users, `EmailVerification` for verified email profile updates, and `AccountLinking` when migrated Rownd users may have multiple supported login methods.
|
|
19
19
|
|
|
20
20
|
```typescript
|
|
21
21
|
import SuperTokens from "supertokens-node";
|
|
@@ -128,17 +128,18 @@ const magicLink = await createMagicLinkWithConfirmationBypass({
|
|
|
128
128
|
|
|
129
129
|
Pass exactly one of `email` or `phoneNumber`. The helper returns the rewritten magic link with `bypassDeviceConfirmation=true`.
|
|
130
130
|
|
|
131
|
-
Before skipping the cross-device confirmation prompt, the frontend should validate the callback against the plugin
|
|
131
|
+
Before skipping the cross-device confirmation prompt, the frontend should validate the callback against the plugin. Routes are mounted under your SuperTokens `apiBasePath`, which defaults to `/auth`.
|
|
132
132
|
|
|
133
|
-
- **POST**
|
|
133
|
+
- **POST** `{apiBasePath}/plugin/passwordless-cross-device-confirmation/validate`
|
|
134
|
+
- **Default**: `POST /auth/plugin/passwordless-cross-device-confirmation/validate`
|
|
134
135
|
- **Body**: `{ "clientDomain": "browser", "redirectToPath": "/profile", "appVariantId": "optional_variant" }`
|
|
135
136
|
- **Success response**: `{ "status": "OK", "bypass": true }`
|
|
136
137
|
|
|
137
138
|
If validation fails, the frontend should show the normal cross-device confirmation prompt.
|
|
138
139
|
|
|
139
|
-
## API
|
|
140
|
+
## API Endpoints
|
|
140
141
|
|
|
141
|
-
The plugin exposes
|
|
142
|
+
Routes are mounted under your SuperTokens `apiBasePath`, which defaults to `/auth`. The migration endpoint is the main Rownd-to-SuperTokens session handoff endpoint; the plugin also exposes Rownd-compatible app config, guest, user, metadata, field, and sign-out endpoints under `{apiBasePath}/plugin/rownd/...`.
|
|
142
143
|
|
|
143
144
|
> [!IMPORTANT]
|
|
144
145
|
> The plugin always migrates users and sessions into the `public` tenant.
|
|
@@ -146,7 +147,8 @@ The plugin exposes a single endpoint:
|
|
|
146
147
|
|
|
147
148
|
### Migrate
|
|
148
149
|
|
|
149
|
-
- **POST**
|
|
150
|
+
- **POST** `{apiBasePath}/plugin/rownd/migrate`
|
|
151
|
+
- **Default**: `POST /auth/plugin/rownd/migrate`
|
|
150
152
|
- **Headers**: `Authorization: Bearer <Rownd_JWT>`. Header-token clients should also send `rid: session`, `fdi-version: 1.18`, and `st-auth-mode: header`.
|
|
151
153
|
- **Description**: Validates the Rownd JWT, ensures the user is migrated to SuperTokens in the `public` tenant, syncs Rownd user data to SuperTokens UserMetadata, and then creates a new SuperTokens session for that user. Header-token clients must receive `st-access-token`, `st-refresh-token`, and `front-token` response headers.
|
|
152
154
|
|
|
@@ -164,13 +166,11 @@ The plugin emits exactly one telemetry event per `/migrate` call result.
|
|
|
164
166
|
|
|
165
167
|
Each event includes endpoint outcome data only (not step-by-step events), including:
|
|
166
168
|
|
|
167
|
-
- `operation`: `migrate`
|
|
168
169
|
- `outcome`: `success` or `error`
|
|
169
170
|
- `durationMs`
|
|
170
171
|
- `tenantId` (when available)
|
|
171
172
|
- `rowndUserId` (when available)
|
|
172
173
|
- `superTokensUserId` (when available)
|
|
173
|
-
- `migrationState`: `already-migrated` or `imported-during-request` (when available)
|
|
174
174
|
- for errors: `error.message` and `error.name`
|
|
175
175
|
|
|
176
176
|
> [!NOTE]
|
|
@@ -228,20 +228,21 @@ RowndMigrationPlugin.init({
|
|
|
228
228
|
|
|
229
229
|
The package includes a bulk migration script for importing Rownd users into SuperTokens.
|
|
230
230
|
|
|
231
|
-
The script
|
|
232
|
-
|
|
233
|
-
- config file: `packages/rownd-nodejs/scripts/config.yaml`
|
|
234
|
-
- script: `packages/rownd-nodejs/scripts/bulkMigrate.ts`
|
|
231
|
+
The script runs from a YAML config file generated from the included template.
|
|
235
232
|
|
|
236
233
|
### Usage
|
|
237
234
|
|
|
238
|
-
1.
|
|
239
|
-
2.
|
|
235
|
+
1. Generate a local config file.
|
|
236
|
+
2. Edit the config with your Rownd and SuperTokens credentials.
|
|
237
|
+
3. Run the migration.
|
|
240
238
|
|
|
241
239
|
```bash
|
|
242
|
-
|
|
240
|
+
npx rownd-nodejs init-config --output ./rownd-bulk-migrate.yaml
|
|
241
|
+
npx rownd-nodejs bulk-migrate --config ./rownd-bulk-migrate.yaml
|
|
243
242
|
```
|
|
244
243
|
|
|
244
|
+
For repo-local development, use `npm run cli -- bulk-migrate --config ./rownd-bulk-migrate.yaml` from `packages/rownd-nodejs`.
|
|
245
|
+
|
|
245
246
|
The script:
|
|
246
247
|
|
|
247
248
|
- fetches users from Rownd page by page
|
|
@@ -252,5 +253,5 @@ The script:
|
|
|
252
253
|
|
|
253
254
|
### Config File
|
|
254
255
|
|
|
255
|
-
All runtime config is read from
|
|
256
|
+
All runtime config is read from the YAML file passed with `--config`.
|
|
256
257
|
There is no environment variable parsing.
|
package/dist/bulkMigrate.js
CHANGED
|
@@ -40,6 +40,7 @@ var fs2 = __toESM(require("fs/promises"));
|
|
|
40
40
|
var import_zod2 = require("zod");
|
|
41
41
|
|
|
42
42
|
// src/rownd-compatibility.ts
|
|
43
|
+
var import_node_crypto = require("crypto");
|
|
43
44
|
var import_supertokens_node = __toESM(require("supertokens-node"));
|
|
44
45
|
var import_usermetadata = __toESM(require("supertokens-node/recipe/usermetadata"));
|
|
45
46
|
|
|
@@ -55,6 +56,11 @@ var IDENTITY_USER_DATA_FIELDS = /* @__PURE__ */ new Set([
|
|
|
55
56
|
"google_id",
|
|
56
57
|
"apple_id"
|
|
57
58
|
]);
|
|
59
|
+
var SUPERTOKENS_FAKE_EMAIL_DOMAIN = "stfakeemail.supertokens.com";
|
|
60
|
+
function buildSuperTokensFakeEmail(thirdPartyUserId, thirdPartyId) {
|
|
61
|
+
const hash = (0, import_node_crypto.createHash)("sha256").update(`${thirdPartyId}:${thirdPartyUserId}`).digest("hex").slice(0, 32);
|
|
62
|
+
return `st-${thirdPartyId}-${hash}@${SUPERTOKENS_FAKE_EMAIL_DOMAIN}`;
|
|
63
|
+
}
|
|
58
64
|
function isIdentityField(field) {
|
|
59
65
|
return IDENTITY_USER_DATA_FIELDS.has(field);
|
|
60
66
|
}
|
|
@@ -66,27 +72,23 @@ function mapRowndUserToSuperTokens(rowndUser) {
|
|
|
66
72
|
throw new Error("Rownd user has no user_id");
|
|
67
73
|
}
|
|
68
74
|
if (rowndUserData.google_id) {
|
|
69
|
-
|
|
70
|
-
throw new Error("Rownd Google user is missing email");
|
|
71
|
-
}
|
|
75
|
+
const googleEmail = rowndUserData.email ?? buildSuperTokensFakeEmail(rowndUserData.google_id, "google");
|
|
72
76
|
loginMethods.push({
|
|
73
77
|
recipeId: "thirdparty",
|
|
74
78
|
thirdPartyId: "google",
|
|
75
79
|
thirdPartyUserId: rowndUserData.google_id,
|
|
76
|
-
email:
|
|
77
|
-
isVerified: !!rowndUserVerifiedData.google_id
|
|
80
|
+
email: googleEmail,
|
|
81
|
+
isVerified: !!rowndUserData.email && !!rowndUserVerifiedData.google_id
|
|
78
82
|
});
|
|
79
83
|
}
|
|
80
84
|
if (rowndUserData.apple_id) {
|
|
81
|
-
|
|
82
|
-
throw new Error("Rownd Apple user is missing email");
|
|
83
|
-
}
|
|
85
|
+
const appleEmail = rowndUserData.email ?? buildSuperTokensFakeEmail(rowndUserData.apple_id, "apple");
|
|
84
86
|
loginMethods.push({
|
|
85
87
|
recipeId: "thirdparty",
|
|
86
88
|
thirdPartyId: "apple",
|
|
87
89
|
thirdPartyUserId: rowndUserData.apple_id,
|
|
88
|
-
email:
|
|
89
|
-
isVerified: !!rowndUserVerifiedData.apple_id
|
|
90
|
+
email: appleEmail,
|
|
91
|
+
isVerified: !!rowndUserData.email && !!rowndUserVerifiedData.apple_id
|
|
90
92
|
});
|
|
91
93
|
}
|
|
92
94
|
if (rowndUserData.phone_number) {
|
|
@@ -159,7 +161,9 @@ var ConfigSchema = import_zod.z.object({
|
|
|
159
161
|
appKey: import_zod.z.string(),
|
|
160
162
|
appSecret: import_zod.z.string(),
|
|
161
163
|
bearerToken: import_zod.z.string().optional(),
|
|
162
|
-
pageSize: import_zod.z.number().int().positive()
|
|
164
|
+
pageSize: import_zod.z.number().int().positive(),
|
|
165
|
+
oidcClientSecrets: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).optional(),
|
|
166
|
+
provisionOidcClientIdAliases: import_zod.z.boolean().default(true)
|
|
163
167
|
}),
|
|
164
168
|
supertokens: import_zod.z.object({
|
|
165
169
|
connectionURI: import_zod.z.string(),
|
|
@@ -61,7 +61,9 @@ var ConfigSchema = import_zod.z.object({
|
|
|
61
61
|
appKey: import_zod.z.string(),
|
|
62
62
|
appSecret: import_zod.z.string(),
|
|
63
63
|
bearerToken: import_zod.z.string().optional(),
|
|
64
|
-
pageSize: import_zod.z.number().int().positive()
|
|
64
|
+
pageSize: import_zod.z.number().int().positive(),
|
|
65
|
+
oidcClientSecrets: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).optional(),
|
|
66
|
+
provisionOidcClientIdAliases: import_zod.z.boolean().default(true)
|
|
65
67
|
}),
|
|
66
68
|
supertokens: import_zod.z.object({
|
|
67
69
|
connectionURI: import_zod.z.string(),
|
package/dist/index.js
CHANGED
|
@@ -865,6 +865,7 @@ var RowndPluginError = class extends Error {
|
|
|
865
865
|
};
|
|
866
866
|
|
|
867
867
|
// src/utils.ts
|
|
868
|
+
var ROWND_OAUTH_LOGIN_CHALLENGE_PARAM = "rownd_oauth_login_challenge";
|
|
868
869
|
function rewriteLinkPath(inputUrl, targetPath, searchParams) {
|
|
869
870
|
try {
|
|
870
871
|
const url = new URL(inputUrl);
|
|
@@ -1065,7 +1066,8 @@ function getMagicLinkBootstrapParams(input) {
|
|
|
1065
1066
|
...input.appVariantId ? { appVariantId: input.appVariantId } : {},
|
|
1066
1067
|
...input.displayContext ? { displayContext: input.displayContext } : {},
|
|
1067
1068
|
...input.redirectToPath ? { redirectToPath: input.redirectToPath } : {},
|
|
1068
|
-
...input.clientDomainKey ? { clientDomain: input.clientDomainKey } : {}
|
|
1069
|
+
...input.clientDomainKey ? { clientDomain: input.clientDomainKey } : {},
|
|
1070
|
+
...input.oauthLoginChallenge ? { oauthLoginChallenge: input.oauthLoginChallenge } : {}
|
|
1069
1071
|
};
|
|
1070
1072
|
}
|
|
1071
1073
|
function rewriteMagicLink(input) {
|
|
@@ -1091,6 +1093,10 @@ function getRequestedRedirectToPathFromRequest(req) {
|
|
|
1091
1093
|
const redirectToPath = req.getKeyValueFromQuery("rownd_redirect_to_path");
|
|
1092
1094
|
return typeof redirectToPath === "string" && redirectToPath.length > 0 ? redirectToPath : void 0;
|
|
1093
1095
|
}
|
|
1096
|
+
function getRequestedOAuthLoginChallengeFromRequest(req) {
|
|
1097
|
+
const loginChallenge = req.getKeyValueFromQuery(ROWND_OAUTH_LOGIN_CHALLENGE_PARAM);
|
|
1098
|
+
return typeof loginChallenge === "string" && loginChallenge.length > 0 ? loginChallenge : void 0;
|
|
1099
|
+
}
|
|
1094
1100
|
|
|
1095
1101
|
// src/config.ts
|
|
1096
1102
|
var pluginConfig;
|
|
@@ -1463,6 +1469,7 @@ function buildAuthMobileConfig(authMobile) {
|
|
|
1463
1469
|
}
|
|
1464
1470
|
|
|
1465
1471
|
// src/rownd-compatibility.ts
|
|
1472
|
+
var import_node_crypto = require("crypto");
|
|
1466
1473
|
var import_supertokens_node = __toESM(require("supertokens-node"));
|
|
1467
1474
|
var import_usermetadata2 = __toESM(require("supertokens-node/recipe/usermetadata"));
|
|
1468
1475
|
var IDENTITY_USER_DATA_FIELDS = /* @__PURE__ */ new Set([
|
|
@@ -1476,6 +1483,14 @@ var INTERNAL_METADATA_FIELDS = /* @__PURE__ */ new Set([
|
|
|
1476
1483
|
"original_rownd_user",
|
|
1477
1484
|
"rownd_pending_verification"
|
|
1478
1485
|
]);
|
|
1486
|
+
var SUPERTOKENS_FAKE_EMAIL_DOMAIN = "stfakeemail.supertokens.com";
|
|
1487
|
+
function isSuperTokensFakeEmail(email) {
|
|
1488
|
+
return typeof email === "string" && email.toLowerCase().endsWith(`@${SUPERTOKENS_FAKE_EMAIL_DOMAIN}`);
|
|
1489
|
+
}
|
|
1490
|
+
function buildSuperTokensFakeEmail(thirdPartyUserId, thirdPartyId) {
|
|
1491
|
+
const hash = (0, import_node_crypto.createHash)("sha256").update(`${thirdPartyId}:${thirdPartyUserId}`).digest("hex").slice(0, 32);
|
|
1492
|
+
return `st-${thirdPartyId}-${hash}@${SUPERTOKENS_FAKE_EMAIL_DOMAIN}`;
|
|
1493
|
+
}
|
|
1479
1494
|
function isIdentityField(field) {
|
|
1480
1495
|
return IDENTITY_USER_DATA_FIELDS.has(field);
|
|
1481
1496
|
}
|
|
@@ -1490,27 +1505,23 @@ function mapRowndUserToSuperTokens(rowndUser) {
|
|
|
1490
1505
|
throw new Error("Rownd user has no user_id");
|
|
1491
1506
|
}
|
|
1492
1507
|
if (rowndUserData.google_id) {
|
|
1493
|
-
|
|
1494
|
-
throw new Error("Rownd Google user is missing email");
|
|
1495
|
-
}
|
|
1508
|
+
const googleEmail = rowndUserData.email ?? buildSuperTokensFakeEmail(rowndUserData.google_id, "google");
|
|
1496
1509
|
loginMethods.push({
|
|
1497
1510
|
recipeId: "thirdparty",
|
|
1498
1511
|
thirdPartyId: "google",
|
|
1499
1512
|
thirdPartyUserId: rowndUserData.google_id,
|
|
1500
|
-
email:
|
|
1501
|
-
isVerified: !!rowndUserVerifiedData.google_id
|
|
1513
|
+
email: googleEmail,
|
|
1514
|
+
isVerified: !!rowndUserData.email && !!rowndUserVerifiedData.google_id
|
|
1502
1515
|
});
|
|
1503
1516
|
}
|
|
1504
1517
|
if (rowndUserData.apple_id) {
|
|
1505
|
-
|
|
1506
|
-
throw new Error("Rownd Apple user is missing email");
|
|
1507
|
-
}
|
|
1518
|
+
const appleEmail = rowndUserData.email ?? buildSuperTokensFakeEmail(rowndUserData.apple_id, "apple");
|
|
1508
1519
|
loginMethods.push({
|
|
1509
1520
|
recipeId: "thirdparty",
|
|
1510
1521
|
thirdPartyId: "apple",
|
|
1511
1522
|
thirdPartyUserId: rowndUserData.apple_id,
|
|
1512
|
-
email:
|
|
1513
|
-
isVerified: !!rowndUserVerifiedData.apple_id
|
|
1523
|
+
email: appleEmail,
|
|
1524
|
+
isVerified: !!rowndUserData.email && !!rowndUserVerifiedData.apple_id
|
|
1514
1525
|
});
|
|
1515
1526
|
}
|
|
1516
1527
|
if (rowndUserData.phone_number) {
|
|
@@ -1695,7 +1706,7 @@ async function buildStandardOAuthClaims(user, scopes) {
|
|
|
1695
1706
|
const rowndData = isJsonRecord(metadata.original_rownd_user?.data) ? metadata.original_rownd_user.data : {};
|
|
1696
1707
|
const verifiedData = isJsonRecord(metadata.original_rownd_user?.verified_data) ? metadata.original_rownd_user.verified_data : {};
|
|
1697
1708
|
if (scopes.includes("email")) {
|
|
1698
|
-
const email = firstString(rowndData.email)
|
|
1709
|
+
const email = firstRealEmail(firstString(rowndData.email), ...user.emails);
|
|
1699
1710
|
if (email) {
|
|
1700
1711
|
claims.email = email;
|
|
1701
1712
|
claims.email_verified = isOAuthClaimVerified(
|
|
@@ -1762,6 +1773,11 @@ function firstString(value) {
|
|
|
1762
1773
|
}
|
|
1763
1774
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
1764
1775
|
}
|
|
1776
|
+
function firstRealEmail(...values) {
|
|
1777
|
+
return values.find((entry) => {
|
|
1778
|
+
return typeof entry === "string" && entry.length > 0 && !isSuperTokensFakeEmail(entry);
|
|
1779
|
+
});
|
|
1780
|
+
}
|
|
1765
1781
|
function isOAuthClaimVerified(value, expectedValue, fallback) {
|
|
1766
1782
|
return value === true || value === expectedValue || fallback;
|
|
1767
1783
|
}
|
|
@@ -2045,6 +2061,7 @@ async function createMagicLinkWithConfirmationBypass(input) {
|
|
|
2045
2061
|
})}${getAppInfoString(stConfig.appInfo.websiteBasePath)}/verify?preAuthSessionId=${encodeURIComponent(
|
|
2046
2062
|
codeInfo.preAuthSessionId
|
|
2047
2063
|
)}&tenantId=${encodeURIComponent(tenantId)}#${encodeURIComponent(codeInfo.linkCode)}`;
|
|
2064
|
+
const oauthLoginChallenge = userContext.rowndOAuthLoginChallenge;
|
|
2048
2065
|
const rewrittenUrl = new URL(rewriteMagicLink({
|
|
2049
2066
|
magicLink,
|
|
2050
2067
|
clientDomain,
|
|
@@ -2055,7 +2072,8 @@ async function createMagicLinkWithConfirmationBypass(input) {
|
|
|
2055
2072
|
appVariantId,
|
|
2056
2073
|
displayContext: input.displayContext,
|
|
2057
2074
|
redirectToPath,
|
|
2058
|
-
clientDomainKey: input.clientDomain
|
|
2075
|
+
clientDomainKey: input.clientDomain,
|
|
2076
|
+
oauthLoginChallenge: typeof oauthLoginChallenge === "string" ? oauthLoginChallenge : void 0
|
|
2059
2077
|
})
|
|
2060
2078
|
}));
|
|
2061
2079
|
rewrittenUrl.searchParams.set(PASSWORDLESS_BYPASS_DEVICE_CONFIRMATION_PARAM, "true");
|
|
@@ -2106,7 +2124,7 @@ async function getUserById(userId) {
|
|
|
2106
2124
|
};
|
|
2107
2125
|
for (const method of stUser.loginMethods) {
|
|
2108
2126
|
if (method.recipeId === "passwordless") {
|
|
2109
|
-
if (method.email) {
|
|
2127
|
+
if (method.email && !isSuperTokensFakeEmail(method.email)) {
|
|
2110
2128
|
verifiedData.email = method.email;
|
|
2111
2129
|
if (data.email === void 0) data.email = method.email;
|
|
2112
2130
|
}
|
|
@@ -2118,10 +2136,10 @@ async function getUserById(userId) {
|
|
|
2118
2136
|
} else if (method.recipeId === "thirdparty") {
|
|
2119
2137
|
const thirdPartyId = getThirdPartyId(method);
|
|
2120
2138
|
const thirdPartyUserId = getThirdPartyUserId(method);
|
|
2121
|
-
if (method.verified && method.email) {
|
|
2139
|
+
if (method.verified && method.email && !isSuperTokensFakeEmail(method.email)) {
|
|
2122
2140
|
verifiedData.email = method.email;
|
|
2123
2141
|
}
|
|
2124
|
-
if (method.email && data.email === void 0) {
|
|
2142
|
+
if (method.email && !isSuperTokensFakeEmail(method.email) && data.email === void 0) {
|
|
2125
2143
|
data.email = method.email;
|
|
2126
2144
|
}
|
|
2127
2145
|
if (thirdPartyId === "google" && thirdPartyUserId) {
|
|
@@ -2133,7 +2151,7 @@ async function getUserById(userId) {
|
|
|
2133
2151
|
verifiedData.apple_id = thirdPartyUserId;
|
|
2134
2152
|
}
|
|
2135
2153
|
} else if (method.recipeId === "emailpassword") {
|
|
2136
|
-
if (method.email && data.email === void 0) {
|
|
2154
|
+
if (method.email && !isSuperTokensFakeEmail(method.email) && data.email === void 0) {
|
|
2137
2155
|
data.email = method.email;
|
|
2138
2156
|
}
|
|
2139
2157
|
}
|
|
@@ -2838,6 +2856,7 @@ var init = createPluginInitFunction(
|
|
|
2838
2856
|
const displayContext = input?.userContext?.rowndDisplayContext;
|
|
2839
2857
|
const redirectToPath = input?.userContext?.rowndRedirectToPath;
|
|
2840
2858
|
const clientDomain = input?.userContext?.rowndClientDomain;
|
|
2859
|
+
const oauthLoginChallenge = input?.userContext?.rowndOAuthLoginChallenge;
|
|
2841
2860
|
const clientDomainKey = clientDomain ?? (displayContext === "mobile_app" ? "mobile" : "browser");
|
|
2842
2861
|
const clientBaseUrl = pluginConfig2.clientDomains?.[clientDomainKey];
|
|
2843
2862
|
const bootstrapParams = {
|
|
@@ -2845,7 +2864,8 @@ var init = createPluginInitFunction(
|
|
|
2845
2864
|
...hubBootstrapParams ?? {},
|
|
2846
2865
|
...typeof appVariantId === "string" ? { appVariantId } : {},
|
|
2847
2866
|
...typeof displayContext === "string" ? { displayContext } : {},
|
|
2848
|
-
...typeof redirectToPath === "string" ? { redirectToPath } : {}
|
|
2867
|
+
...typeof redirectToPath === "string" ? { redirectToPath } : {},
|
|
2868
|
+
...typeof oauthLoginChallenge === "string" ? { oauthLoginChallenge } : {}
|
|
2849
2869
|
};
|
|
2850
2870
|
const rewrittenLink = input[linkKey] ? clientBaseUrl ? rewriteLinkToBaseUrl(
|
|
2851
2871
|
input[linkKey],
|
|
@@ -3131,6 +3151,12 @@ var init = createPluginInitFunction(
|
|
|
3131
3151
|
if (appVariantId) {
|
|
3132
3152
|
input.userContext.rowndAppVariantId = appVariantId;
|
|
3133
3153
|
}
|
|
3154
|
+
const oauthLoginChallenge = getRequestedOAuthLoginChallengeFromRequest(
|
|
3155
|
+
input.options.req
|
|
3156
|
+
);
|
|
3157
|
+
if (oauthLoginChallenge) {
|
|
3158
|
+
input.userContext.rowndOAuthLoginChallenge = oauthLoginChallenge;
|
|
3159
|
+
}
|
|
3134
3160
|
assertRowndAppVariantIsConfigured(appVariantId);
|
|
3135
3161
|
return originalImplementation.createCodePOST(input);
|
|
3136
3162
|
},
|
package/dist/index.mjs
CHANGED
|
@@ -842,6 +842,7 @@ var RowndPluginError = class extends Error {
|
|
|
842
842
|
};
|
|
843
843
|
|
|
844
844
|
// src/utils.ts
|
|
845
|
+
var ROWND_OAUTH_LOGIN_CHALLENGE_PARAM = "rownd_oauth_login_challenge";
|
|
845
846
|
function rewriteLinkPath(inputUrl, targetPath, searchParams) {
|
|
846
847
|
try {
|
|
847
848
|
const url = new URL(inputUrl);
|
|
@@ -1042,7 +1043,8 @@ function getMagicLinkBootstrapParams(input) {
|
|
|
1042
1043
|
...input.appVariantId ? { appVariantId: input.appVariantId } : {},
|
|
1043
1044
|
...input.displayContext ? { displayContext: input.displayContext } : {},
|
|
1044
1045
|
...input.redirectToPath ? { redirectToPath: input.redirectToPath } : {},
|
|
1045
|
-
...input.clientDomainKey ? { clientDomain: input.clientDomainKey } : {}
|
|
1046
|
+
...input.clientDomainKey ? { clientDomain: input.clientDomainKey } : {},
|
|
1047
|
+
...input.oauthLoginChallenge ? { oauthLoginChallenge: input.oauthLoginChallenge } : {}
|
|
1046
1048
|
};
|
|
1047
1049
|
}
|
|
1048
1050
|
function rewriteMagicLink(input) {
|
|
@@ -1068,6 +1070,10 @@ function getRequestedRedirectToPathFromRequest(req) {
|
|
|
1068
1070
|
const redirectToPath = req.getKeyValueFromQuery("rownd_redirect_to_path");
|
|
1069
1071
|
return typeof redirectToPath === "string" && redirectToPath.length > 0 ? redirectToPath : void 0;
|
|
1070
1072
|
}
|
|
1073
|
+
function getRequestedOAuthLoginChallengeFromRequest(req) {
|
|
1074
|
+
const loginChallenge = req.getKeyValueFromQuery(ROWND_OAUTH_LOGIN_CHALLENGE_PARAM);
|
|
1075
|
+
return typeof loginChallenge === "string" && loginChallenge.length > 0 ? loginChallenge : void 0;
|
|
1076
|
+
}
|
|
1071
1077
|
|
|
1072
1078
|
// src/config.ts
|
|
1073
1079
|
var pluginConfig;
|
|
@@ -1440,6 +1446,7 @@ function buildAuthMobileConfig(authMobile) {
|
|
|
1440
1446
|
}
|
|
1441
1447
|
|
|
1442
1448
|
// src/rownd-compatibility.ts
|
|
1449
|
+
import { createHash } from "crypto";
|
|
1443
1450
|
import SuperTokens from "supertokens-node";
|
|
1444
1451
|
import UserMetadata2 from "supertokens-node/recipe/usermetadata";
|
|
1445
1452
|
var IDENTITY_USER_DATA_FIELDS = /* @__PURE__ */ new Set([
|
|
@@ -1453,6 +1460,14 @@ var INTERNAL_METADATA_FIELDS = /* @__PURE__ */ new Set([
|
|
|
1453
1460
|
"original_rownd_user",
|
|
1454
1461
|
"rownd_pending_verification"
|
|
1455
1462
|
]);
|
|
1463
|
+
var SUPERTOKENS_FAKE_EMAIL_DOMAIN = "stfakeemail.supertokens.com";
|
|
1464
|
+
function isSuperTokensFakeEmail(email) {
|
|
1465
|
+
return typeof email === "string" && email.toLowerCase().endsWith(`@${SUPERTOKENS_FAKE_EMAIL_DOMAIN}`);
|
|
1466
|
+
}
|
|
1467
|
+
function buildSuperTokensFakeEmail(thirdPartyUserId, thirdPartyId) {
|
|
1468
|
+
const hash = createHash("sha256").update(`${thirdPartyId}:${thirdPartyUserId}`).digest("hex").slice(0, 32);
|
|
1469
|
+
return `st-${thirdPartyId}-${hash}@${SUPERTOKENS_FAKE_EMAIL_DOMAIN}`;
|
|
1470
|
+
}
|
|
1456
1471
|
function isIdentityField(field) {
|
|
1457
1472
|
return IDENTITY_USER_DATA_FIELDS.has(field);
|
|
1458
1473
|
}
|
|
@@ -1467,27 +1482,23 @@ function mapRowndUserToSuperTokens(rowndUser) {
|
|
|
1467
1482
|
throw new Error("Rownd user has no user_id");
|
|
1468
1483
|
}
|
|
1469
1484
|
if (rowndUserData.google_id) {
|
|
1470
|
-
|
|
1471
|
-
throw new Error("Rownd Google user is missing email");
|
|
1472
|
-
}
|
|
1485
|
+
const googleEmail = rowndUserData.email ?? buildSuperTokensFakeEmail(rowndUserData.google_id, "google");
|
|
1473
1486
|
loginMethods.push({
|
|
1474
1487
|
recipeId: "thirdparty",
|
|
1475
1488
|
thirdPartyId: "google",
|
|
1476
1489
|
thirdPartyUserId: rowndUserData.google_id,
|
|
1477
|
-
email:
|
|
1478
|
-
isVerified: !!rowndUserVerifiedData.google_id
|
|
1490
|
+
email: googleEmail,
|
|
1491
|
+
isVerified: !!rowndUserData.email && !!rowndUserVerifiedData.google_id
|
|
1479
1492
|
});
|
|
1480
1493
|
}
|
|
1481
1494
|
if (rowndUserData.apple_id) {
|
|
1482
|
-
|
|
1483
|
-
throw new Error("Rownd Apple user is missing email");
|
|
1484
|
-
}
|
|
1495
|
+
const appleEmail = rowndUserData.email ?? buildSuperTokensFakeEmail(rowndUserData.apple_id, "apple");
|
|
1485
1496
|
loginMethods.push({
|
|
1486
1497
|
recipeId: "thirdparty",
|
|
1487
1498
|
thirdPartyId: "apple",
|
|
1488
1499
|
thirdPartyUserId: rowndUserData.apple_id,
|
|
1489
|
-
email:
|
|
1490
|
-
isVerified: !!rowndUserVerifiedData.apple_id
|
|
1500
|
+
email: appleEmail,
|
|
1501
|
+
isVerified: !!rowndUserData.email && !!rowndUserVerifiedData.apple_id
|
|
1491
1502
|
});
|
|
1492
1503
|
}
|
|
1493
1504
|
if (rowndUserData.phone_number) {
|
|
@@ -1672,7 +1683,7 @@ async function buildStandardOAuthClaims(user, scopes) {
|
|
|
1672
1683
|
const rowndData = isJsonRecord(metadata.original_rownd_user?.data) ? metadata.original_rownd_user.data : {};
|
|
1673
1684
|
const verifiedData = isJsonRecord(metadata.original_rownd_user?.verified_data) ? metadata.original_rownd_user.verified_data : {};
|
|
1674
1685
|
if (scopes.includes("email")) {
|
|
1675
|
-
const email = firstString(rowndData.email)
|
|
1686
|
+
const email = firstRealEmail(firstString(rowndData.email), ...user.emails);
|
|
1676
1687
|
if (email) {
|
|
1677
1688
|
claims.email = email;
|
|
1678
1689
|
claims.email_verified = isOAuthClaimVerified(
|
|
@@ -1739,6 +1750,11 @@ function firstString(value) {
|
|
|
1739
1750
|
}
|
|
1740
1751
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
1741
1752
|
}
|
|
1753
|
+
function firstRealEmail(...values) {
|
|
1754
|
+
return values.find((entry) => {
|
|
1755
|
+
return typeof entry === "string" && entry.length > 0 && !isSuperTokensFakeEmail(entry);
|
|
1756
|
+
});
|
|
1757
|
+
}
|
|
1742
1758
|
function isOAuthClaimVerified(value, expectedValue, fallback) {
|
|
1743
1759
|
return value === true || value === expectedValue || fallback;
|
|
1744
1760
|
}
|
|
@@ -2022,6 +2038,7 @@ async function createMagicLinkWithConfirmationBypass(input) {
|
|
|
2022
2038
|
})}${getAppInfoString(stConfig.appInfo.websiteBasePath)}/verify?preAuthSessionId=${encodeURIComponent(
|
|
2023
2039
|
codeInfo.preAuthSessionId
|
|
2024
2040
|
)}&tenantId=${encodeURIComponent(tenantId)}#${encodeURIComponent(codeInfo.linkCode)}`;
|
|
2041
|
+
const oauthLoginChallenge = userContext.rowndOAuthLoginChallenge;
|
|
2025
2042
|
const rewrittenUrl = new URL(rewriteMagicLink({
|
|
2026
2043
|
magicLink,
|
|
2027
2044
|
clientDomain,
|
|
@@ -2032,7 +2049,8 @@ async function createMagicLinkWithConfirmationBypass(input) {
|
|
|
2032
2049
|
appVariantId,
|
|
2033
2050
|
displayContext: input.displayContext,
|
|
2034
2051
|
redirectToPath,
|
|
2035
|
-
clientDomainKey: input.clientDomain
|
|
2052
|
+
clientDomainKey: input.clientDomain,
|
|
2053
|
+
oauthLoginChallenge: typeof oauthLoginChallenge === "string" ? oauthLoginChallenge : void 0
|
|
2036
2054
|
})
|
|
2037
2055
|
}));
|
|
2038
2056
|
rewrittenUrl.searchParams.set(PASSWORDLESS_BYPASS_DEVICE_CONFIRMATION_PARAM, "true");
|
|
@@ -2083,7 +2101,7 @@ async function getUserById(userId) {
|
|
|
2083
2101
|
};
|
|
2084
2102
|
for (const method of stUser.loginMethods) {
|
|
2085
2103
|
if (method.recipeId === "passwordless") {
|
|
2086
|
-
if (method.email) {
|
|
2104
|
+
if (method.email && !isSuperTokensFakeEmail(method.email)) {
|
|
2087
2105
|
verifiedData.email = method.email;
|
|
2088
2106
|
if (data.email === void 0) data.email = method.email;
|
|
2089
2107
|
}
|
|
@@ -2095,10 +2113,10 @@ async function getUserById(userId) {
|
|
|
2095
2113
|
} else if (method.recipeId === "thirdparty") {
|
|
2096
2114
|
const thirdPartyId = getThirdPartyId(method);
|
|
2097
2115
|
const thirdPartyUserId = getThirdPartyUserId(method);
|
|
2098
|
-
if (method.verified && method.email) {
|
|
2116
|
+
if (method.verified && method.email && !isSuperTokensFakeEmail(method.email)) {
|
|
2099
2117
|
verifiedData.email = method.email;
|
|
2100
2118
|
}
|
|
2101
|
-
if (method.email && data.email === void 0) {
|
|
2119
|
+
if (method.email && !isSuperTokensFakeEmail(method.email) && data.email === void 0) {
|
|
2102
2120
|
data.email = method.email;
|
|
2103
2121
|
}
|
|
2104
2122
|
if (thirdPartyId === "google" && thirdPartyUserId) {
|
|
@@ -2110,7 +2128,7 @@ async function getUserById(userId) {
|
|
|
2110
2128
|
verifiedData.apple_id = thirdPartyUserId;
|
|
2111
2129
|
}
|
|
2112
2130
|
} else if (method.recipeId === "emailpassword") {
|
|
2113
|
-
if (method.email && data.email === void 0) {
|
|
2131
|
+
if (method.email && !isSuperTokensFakeEmail(method.email) && data.email === void 0) {
|
|
2114
2132
|
data.email = method.email;
|
|
2115
2133
|
}
|
|
2116
2134
|
}
|
|
@@ -2815,6 +2833,7 @@ var init = createPluginInitFunction(
|
|
|
2815
2833
|
const displayContext = input?.userContext?.rowndDisplayContext;
|
|
2816
2834
|
const redirectToPath = input?.userContext?.rowndRedirectToPath;
|
|
2817
2835
|
const clientDomain = input?.userContext?.rowndClientDomain;
|
|
2836
|
+
const oauthLoginChallenge = input?.userContext?.rowndOAuthLoginChallenge;
|
|
2818
2837
|
const clientDomainKey = clientDomain ?? (displayContext === "mobile_app" ? "mobile" : "browser");
|
|
2819
2838
|
const clientBaseUrl = pluginConfig2.clientDomains?.[clientDomainKey];
|
|
2820
2839
|
const bootstrapParams = {
|
|
@@ -2822,7 +2841,8 @@ var init = createPluginInitFunction(
|
|
|
2822
2841
|
...hubBootstrapParams ?? {},
|
|
2823
2842
|
...typeof appVariantId === "string" ? { appVariantId } : {},
|
|
2824
2843
|
...typeof displayContext === "string" ? { displayContext } : {},
|
|
2825
|
-
...typeof redirectToPath === "string" ? { redirectToPath } : {}
|
|
2844
|
+
...typeof redirectToPath === "string" ? { redirectToPath } : {},
|
|
2845
|
+
...typeof oauthLoginChallenge === "string" ? { oauthLoginChallenge } : {}
|
|
2826
2846
|
};
|
|
2827
2847
|
const rewrittenLink = input[linkKey] ? clientBaseUrl ? rewriteLinkToBaseUrl(
|
|
2828
2848
|
input[linkKey],
|
|
@@ -3108,6 +3128,12 @@ var init = createPluginInitFunction(
|
|
|
3108
3128
|
if (appVariantId) {
|
|
3109
3129
|
input.userContext.rowndAppVariantId = appVariantId;
|
|
3110
3130
|
}
|
|
3131
|
+
const oauthLoginChallenge = getRequestedOAuthLoginChallengeFromRequest(
|
|
3132
|
+
input.options.req
|
|
3133
|
+
);
|
|
3134
|
+
if (oauthLoginChallenge) {
|
|
3135
|
+
input.userContext.rowndOAuthLoginChallenge = oauthLoginChallenge;
|
|
3136
|
+
}
|
|
3111
3137
|
assertRowndAppVariantIsConfigured(appVariantId);
|
|
3112
3138
|
return originalImplementation.createCodePOST(input);
|
|
3113
3139
|
},
|
package/dist/initConfig.js
CHANGED
|
@@ -49,6 +49,16 @@ rownd:
|
|
|
49
49
|
# bearerToken: <ROWND_API_BEARER_TOKEN>
|
|
50
50
|
# Number of Rownd users to request per page.
|
|
51
51
|
pageSize: 100
|
|
52
|
+
# Rownd stores existing OIDC credential secrets hashed. Provide plaintext
|
|
53
|
+
# values here when migrating OIDC clients. Keys can be credential client IDs
|
|
54
|
+
# (key_...) and OIDC client configuration IDs (oc_...).
|
|
55
|
+
oidcClientSecrets: {}
|
|
56
|
+
# oidcClientSecrets:
|
|
57
|
+
# key_123: ras_plaintext_secret
|
|
58
|
+
# oc_123: ras_plaintext_secret_for_oidc_client_id_alias
|
|
59
|
+
# Rownd accepts the OIDC client configuration ID (oc_...) as a client_id in
|
|
60
|
+
# addition to each linked credential client_id (key_...).
|
|
61
|
+
provisionOidcClientIdAliases: true
|
|
52
62
|
|
|
53
63
|
supertokens:
|
|
54
64
|
connectionURI: <CONNECTION_URI>
|
|
@@ -62,7 +62,9 @@ var ConfigSchema = import_zod.z.object({
|
|
|
62
62
|
appKey: import_zod.z.string(),
|
|
63
63
|
appSecret: import_zod.z.string(),
|
|
64
64
|
bearerToken: import_zod.z.string().optional(),
|
|
65
|
-
pageSize: import_zod.z.number().int().positive()
|
|
65
|
+
pageSize: import_zod.z.number().int().positive(),
|
|
66
|
+
oidcClientSecrets: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).optional(),
|
|
67
|
+
provisionOidcClientIdAliases: import_zod.z.boolean().default(true)
|
|
66
68
|
}),
|
|
67
69
|
supertokens: import_zod.z.object({
|
|
68
70
|
connectionURI: import_zod.z.string(),
|
|
@@ -187,55 +189,118 @@ async function provisionSuperTokensInfrastructure(config, oidcClients) {
|
|
|
187
189
|
if (config.supertokens.apiKey) {
|
|
188
190
|
headers["api-key"] = config.supertokens.apiKey;
|
|
189
191
|
}
|
|
192
|
+
const provisionedClientIds = /* @__PURE__ */ new Set();
|
|
190
193
|
for (const oidcClient of oidcClients) {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
+
const credentials = oidcClient.credentials ?? [];
|
|
195
|
+
for (const credential of credentials) {
|
|
196
|
+
await createSuperTokensOAuthClient({
|
|
197
|
+
config,
|
|
198
|
+
headers,
|
|
199
|
+
oidcClient,
|
|
200
|
+
clientId: credential.client_id,
|
|
201
|
+
clientSecret: resolveOidcClientSecret(
|
|
202
|
+
config,
|
|
203
|
+
credential.client_id,
|
|
204
|
+
credential.secret
|
|
205
|
+
),
|
|
206
|
+
appVariantId: credential.app_variant_id,
|
|
207
|
+
provisionedClientIds
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
if (config.rownd.provisionOidcClientIdAliases && credentials.length > 0) {
|
|
211
|
+
const firstCredential = credentials[0];
|
|
212
|
+
if (!firstCredential) {
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
const firstCredentialSecret = resolveOidcClientSecret(
|
|
216
|
+
config,
|
|
217
|
+
firstCredential.client_id,
|
|
218
|
+
firstCredential.secret
|
|
194
219
|
);
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
).toString(),
|
|
200
|
-
{
|
|
201
|
-
method: "POST",
|
|
202
|
-
headers,
|
|
203
|
-
body: JSON.stringify({
|
|
204
|
-
clientName: oidcClient.name || credential.client_id || "Rownd Client",
|
|
205
|
-
clientId: credential.client_id,
|
|
206
|
-
clientSecret: credential.secret,
|
|
207
|
-
redirectUris: oidcClient.config.redirect_uris || [],
|
|
208
|
-
postLogoutRedirectUris: oidcClient.config.post_logout_uris || [],
|
|
209
|
-
scope: oidcClient.config.allowed_scopes?.join(" "),
|
|
210
|
-
responseTypes: ["code", "token", "id_token"],
|
|
211
|
-
grantTypes: [
|
|
212
|
-
"authorization_code",
|
|
213
|
-
"refresh_token",
|
|
214
|
-
"client_credentials",
|
|
215
|
-
"implicit"
|
|
216
|
-
],
|
|
217
|
-
tokenEndpointAuthMethod: oidcClient.config.token_endpoint_auth_method ?? "client_secret_basic",
|
|
218
|
-
audience: [`app:${config.rownd.appId}`],
|
|
219
|
-
metadata: {
|
|
220
|
-
rowndOidcClientId: oidcClient.id,
|
|
221
|
-
rowndAppVariantId: credential.app_variant_id || void 0,
|
|
222
|
-
rowndAllowedScopes: oidcClient.config.allowed_scopes || [],
|
|
223
|
-
rowndApplicationType: oidcClient.config.application_type,
|
|
224
|
-
rowndIsPkceRequired: oidcClient.config.is_pkce_required,
|
|
225
|
-
rowndIsPkceSupported: oidcClient.config.is_pkce_supported,
|
|
226
|
-
rowndDeviceFlowEnabled: oidcClient.config.device_flow_enabled
|
|
227
|
-
}
|
|
228
|
-
})
|
|
229
|
-
}
|
|
220
|
+
const aliasSecret = resolveOidcClientSecret(
|
|
221
|
+
config,
|
|
222
|
+
oidcClient.id,
|
|
223
|
+
firstCredentialSecret
|
|
230
224
|
);
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
225
|
+
await createSuperTokensOAuthClient({
|
|
226
|
+
config,
|
|
227
|
+
headers,
|
|
228
|
+
oidcClient,
|
|
229
|
+
clientId: oidcClient.id,
|
|
230
|
+
clientSecret: aliasSecret,
|
|
231
|
+
isOidcClientIdAlias: true,
|
|
232
|
+
provisionedClientIds
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
function resolveOidcClientSecret(config, clientId, apiSecret) {
|
|
238
|
+
const secret = config.rownd.oidcClientSecrets?.[clientId] ?? apiSecret;
|
|
239
|
+
if (!secret) {
|
|
240
|
+
throw new Error(
|
|
241
|
+
`Missing plaintext secret for Rownd OIDC client ${clientId}. Add rownd.oidcClientSecrets.${clientId} to the config.`
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
if (secret.startsWith("$argon2")) {
|
|
245
|
+
throw new Error(
|
|
246
|
+
`Rownd returned a hashed secret for OIDC client ${clientId}. Add the plaintext secret under rownd.oidcClientSecrets.${clientId}.`
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
return secret;
|
|
250
|
+
}
|
|
251
|
+
async function createSuperTokensOAuthClient(input) {
|
|
252
|
+
if (input.provisionedClientIds.has(input.clientId)) {
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
input.provisionedClientIds.add(input.clientId);
|
|
256
|
+
console.log(`Provisioning SuperTokens OAuth2 Client: ${input.clientId}`);
|
|
257
|
+
const grantTypes = [
|
|
258
|
+
"authorization_code",
|
|
259
|
+
"refresh_token",
|
|
260
|
+
"client_credentials",
|
|
261
|
+
"implicit"
|
|
262
|
+
];
|
|
263
|
+
if (input.oidcClient.config.device_flow_enabled) {
|
|
264
|
+
grantTypes.push("urn:ietf:params:oauth:grant-type:device_code");
|
|
265
|
+
}
|
|
266
|
+
const oauthRes = await fetch(
|
|
267
|
+
new URL(
|
|
268
|
+
"/recipe/oauth/clients",
|
|
269
|
+
input.config.supertokens.connectionURI
|
|
270
|
+
).toString(),
|
|
271
|
+
{
|
|
272
|
+
method: "POST",
|
|
273
|
+
headers: input.headers,
|
|
274
|
+
body: JSON.stringify({
|
|
275
|
+
clientName: input.oidcClient.name || input.clientId || "Rownd Client",
|
|
276
|
+
clientId: input.clientId,
|
|
277
|
+
clientSecret: input.clientSecret,
|
|
278
|
+
redirectUris: input.oidcClient.config.redirect_uris || [],
|
|
279
|
+
postLogoutRedirectUris: input.oidcClient.config.post_logout_uris || [],
|
|
280
|
+
scope: input.oidcClient.config.allowed_scopes?.join(" "),
|
|
281
|
+
responseTypes: ["code", "token", "id_token"],
|
|
282
|
+
grantTypes,
|
|
283
|
+
tokenEndpointAuthMethod: input.oidcClient.config.token_endpoint_auth_method ?? "client_secret_basic",
|
|
284
|
+
audience: [`app:${input.config.rownd.appId}`],
|
|
285
|
+
metadata: {
|
|
286
|
+
rowndOidcClientId: input.oidcClient.id,
|
|
287
|
+
rowndAppVariantId: input.appVariantId || void 0,
|
|
288
|
+
rowndAllowedScopes: input.oidcClient.config.allowed_scopes || [],
|
|
289
|
+
rowndApplicationType: input.oidcClient.config.application_type,
|
|
290
|
+
rowndIsPkceRequired: input.oidcClient.config.is_pkce_required,
|
|
291
|
+
rowndIsPkceSupported: input.oidcClient.config.is_pkce_supported,
|
|
292
|
+
rowndDeviceFlowEnabled: input.oidcClient.config.device_flow_enabled,
|
|
293
|
+
rowndIsOidcClientIdAlias: input.isOidcClientIdAlias || void 0
|
|
237
294
|
}
|
|
238
|
-
}
|
|
295
|
+
})
|
|
296
|
+
}
|
|
297
|
+
);
|
|
298
|
+
if (!oauthRes.ok) {
|
|
299
|
+
const errorText = await oauthRes.text();
|
|
300
|
+
if (!errorText.includes("already exists") && !errorText.includes("Duplicate")) {
|
|
301
|
+
throw new Error(
|
|
302
|
+
`Failed to create OAuth2 Client ${input.clientId}: ${oauthRes.status} ${errorText}`
|
|
303
|
+
);
|
|
239
304
|
}
|
|
240
305
|
}
|
|
241
306
|
}
|
package/package.json
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@supertokens-plugins/rownd-nodejs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "Rownd User Migration Plugin for SuperTokens",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./package.json": "./package.json"
|
|
15
|
+
},
|
|
8
16
|
"bin": {
|
|
9
17
|
"rownd-nodejs": "./dist/cli.js"
|
|
10
18
|
},
|
|
@@ -15,6 +23,8 @@
|
|
|
15
23
|
"build": "rm -rf dist && tsup",
|
|
16
24
|
"cli": "npm run build && node dist/cli.js",
|
|
17
25
|
"lint": "eslint ./src --ext .ts",
|
|
26
|
+
"prepack": "npm run build",
|
|
27
|
+
"typecheck": "tsc --noEmit",
|
|
18
28
|
"test": "TEST_MODE=testing vitest run --pool=forks"
|
|
19
29
|
},
|
|
20
30
|
"keywords": [
|