@robelest/convex-auth 0.0.4-preview.32 → 0.0.4-preview.34
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/component/_generated/component.d.ts +1611 -2039
- package/dist/component/account.js +3 -0
- package/dist/component/convex.config.d.ts +2 -2
- package/dist/component/factor/device.js +3 -0
- package/dist/component/factor/passkey.js +3 -0
- package/dist/component/factor/totp.js +3 -0
- package/dist/component/group/invite.js +3 -0
- package/dist/component/group/member.js +3 -0
- package/dist/component/group.js +3 -0
- package/dist/component/model.d.ts +342 -30
- package/dist/component/model.js +22 -4
- package/dist/component/modules.js +24 -21
- package/dist/component/public/factors/devices.js +37 -106
- package/dist/component/public/factors/passkeys.js +29 -149
- package/dist/component/public/factors/totp.js +32 -159
- package/dist/component/public/groups/core.js +19 -82
- package/dist/component/public/groups/invites.js +15 -104
- package/dist/component/public/groups/members.js +26 -149
- package/dist/component/public/identity/accounts.js +12 -94
- package/dist/component/public/identity/codes.js +13 -73
- package/dist/component/public/identity/sessions.js +5 -107
- package/dist/component/public/identity/tokens.js +13 -103
- package/dist/component/public/identity/users.js +188 -185
- package/dist/component/public/identity/verifiers.js +17 -80
- package/dist/component/public/security/keys.js +13 -120
- package/dist/component/public/security/limits.js +0 -43
- package/dist/component/public/sso/audit.js +0 -28
- package/dist/component/public/sso/core.js +31 -104
- package/dist/component/public/sso/domains.js +0 -71
- package/dist/component/public/sso/scim.js +63 -239
- package/dist/component/public/sso/secrets.js +0 -30
- package/dist/component/public/sso/webhooks.js +23 -128
- package/dist/component/rateLimit.js +3 -0
- package/dist/component/schema.d.ts +378 -342
- package/dist/component/schema.js +11 -1
- package/dist/component/session.js +3 -0
- package/dist/component/sso/audit.js +3 -0
- package/dist/component/sso/connection/domain/verification.js +3 -0
- package/dist/component/sso/connection/domain.js +3 -0
- package/dist/component/sso/connection/scim/config.js +3 -0
- package/dist/component/sso/connection/scim/identity.js +3 -0
- package/dist/component/sso/connection/secret.js +3 -0
- package/dist/component/sso/connection.js +3 -0
- package/dist/component/sso/webhook/delivery.js +3 -0
- package/dist/component/sso/webhook/endpoint.js +3 -0
- package/dist/component/token/pkce.js +3 -0
- package/dist/component/token/refresh.js +3 -0
- package/dist/component/token/verification.js +3 -0
- package/dist/component/user/email.js +3 -0
- package/dist/component/user/key.js +3 -0
- package/dist/component/user.js +62 -0
- package/dist/core/index.d.ts +131 -28
- package/dist/core/index.js +2 -0
- package/dist/model.js +391 -0
- package/dist/providers/credentials.d.ts +1 -1
- package/dist/providers/github.js +6 -0
- package/dist/providers/password.js +1 -2
- package/dist/server/auth.d.ts +73 -7
- package/dist/server/auth.js +4 -1
- package/dist/server/context.js +30 -3
- package/dist/server/contract.js +42 -42
- package/dist/server/core.js +224 -86
- package/dist/server/db.js +45 -37
- package/dist/server/facade.d.ts +39 -0
- package/dist/server/facade.js +16 -0
- package/dist/server/index.d.ts +5 -3
- package/dist/server/index.js +3 -1
- package/dist/server/mounts.d.ts +101 -101
- package/dist/server/mutations/credentials/signin.js +3 -7
- package/dist/server/mutations/oauth.js +9 -6
- package/dist/server/runtime.d.ts +147 -46
- package/dist/server/runtime.js +10 -8
- package/dist/server/services/group.js +9 -9
- package/dist/server/sso/domain.d.ts +1 -1
- package/dist/server/sso/domain.js +40 -40
- package/dist/server/sso/http.js +18 -18
- package/dist/server/sso/oidc.js +1 -1
- package/dist/server/sso/policies.js +3 -3
- package/dist/server/sso/policy.js +12 -4
- package/dist/server/sso/provision.js +9 -9
- package/dist/server/sso/validators.js +2 -2
- package/dist/server/sso/webhook.js +8 -8
- package/dist/server/types.d.ts +185 -124
- package/dist/server/types.js +29 -24
- package/dist/server/users.js +49 -2
- package/dist/server/validators.d.ts +745 -0
- package/dist/server/validators.js +60 -0
- package/package.json +1 -1
- package/dist/component/public.js +0 -22
|
@@ -74,18 +74,18 @@ function createGroupConnectionDomain(deps) {
|
|
|
74
74
|
connection: {
|
|
75
75
|
create: async (ctx, data) => {
|
|
76
76
|
return {
|
|
77
|
-
connectionId: await createGroupConnection(ctx, config.component.
|
|
77
|
+
connectionId: await createGroupConnection(ctx, config.component.sso, data),
|
|
78
78
|
groupId: data.groupId
|
|
79
79
|
};
|
|
80
80
|
},
|
|
81
81
|
get: async (ctx, connectionId) => {
|
|
82
|
-
return await getGroupConnection(ctx, config.component.
|
|
82
|
+
return await getGroupConnection(ctx, config.component.sso, connectionId);
|
|
83
83
|
},
|
|
84
84
|
getByDomain: async (ctx, domain) => {
|
|
85
|
-
return await getGroupConnectionByDomain(ctx, config.component.
|
|
85
|
+
return await getGroupConnectionByDomain(ctx, config.component.sso, normalizeDomain(domain));
|
|
86
86
|
},
|
|
87
87
|
list: async (ctx, opts) => {
|
|
88
|
-
return await listGroupConnections(ctx, config.component.
|
|
88
|
+
return await listGroupConnections(ctx, config.component.sso, {
|
|
89
89
|
where: opts?.where,
|
|
90
90
|
limit: opts?.limit,
|
|
91
91
|
cursor: opts?.cursor,
|
|
@@ -94,18 +94,18 @@ function createGroupConnectionDomain(deps) {
|
|
|
94
94
|
});
|
|
95
95
|
},
|
|
96
96
|
update: async (ctx, connectionId, data) => {
|
|
97
|
-
await updateGroupConnection(ctx, config.component.
|
|
97
|
+
await updateGroupConnection(ctx, config.component.sso, {
|
|
98
98
|
connectionId,
|
|
99
99
|
data
|
|
100
100
|
});
|
|
101
101
|
return { connectionId };
|
|
102
102
|
},
|
|
103
103
|
delete: async (ctx, connectionId) => {
|
|
104
|
-
await deleteGroupConnection(ctx, config.component.
|
|
104
|
+
await deleteGroupConnection(ctx, config.component.sso, connectionId);
|
|
105
105
|
return { connectionId };
|
|
106
106
|
},
|
|
107
107
|
status: async (ctx, connectionId) => {
|
|
108
|
-
const connection = await getGroupConnection(ctx, config.component.
|
|
108
|
+
const connection = await getGroupConnection(ctx, config.component.sso, connectionId);
|
|
109
109
|
if (!connection) throw convexError({
|
|
110
110
|
code: "INVALID_PARAMETERS",
|
|
111
111
|
message: connectionNotFoundError
|
|
@@ -114,8 +114,8 @@ function createGroupConnectionDomain(deps) {
|
|
|
114
114
|
const oidcConfig = getOidcConfig(connection.config);
|
|
115
115
|
const oidcSecret = await getGroupConnectionSecret(ctx, connection._id, GROUP_CONNECTION_OIDC_CLIENT_SECRET_KIND);
|
|
116
116
|
const samlConfig = getSamlConfig(connection.config);
|
|
117
|
-
const scimConfig = await getScimConfigByConnection(ctx, config.component.
|
|
118
|
-
const domains = await listConnectionDomains(ctx, config.component.
|
|
117
|
+
const scimConfig = await getScimConfigByConnection(ctx, config.component.sso, connectionId);
|
|
118
|
+
const domains = await listConnectionDomains(ctx, config.component.sso, connectionId);
|
|
119
119
|
const oidcReady = oidcConfig?.enabled === true && typeof oidcConfig?.client?.id === "string" && oidcConfig.client.id.length > 0 && oidcSecret !== null && (typeof oidcConfig?.discovery?.issuer === "string" || typeof oidcConfig?.discovery?.discoveryUrl === "string");
|
|
120
120
|
const samlReady = samlConfig?.enabled === true && typeof samlConfig?.idp?.entityId === "string";
|
|
121
121
|
const scimReady = scimConfig?.status === "active";
|
|
@@ -149,21 +149,21 @@ function createGroupConnectionDomain(deps) {
|
|
|
149
149
|
},
|
|
150
150
|
domain: {
|
|
151
151
|
add: async (ctx, data) => {
|
|
152
|
-
return await addConnectionDomain(ctx, config.component.
|
|
152
|
+
return await addConnectionDomain(ctx, config.component.sso, {
|
|
153
153
|
...data,
|
|
154
154
|
domain: normalizeDomain(data.domain)
|
|
155
155
|
});
|
|
156
156
|
},
|
|
157
157
|
list: async (ctx, connectionId) => {
|
|
158
|
-
return await listConnectionDomains(ctx, config.component.
|
|
158
|
+
return await listConnectionDomains(ctx, config.component.sso, connectionId);
|
|
159
159
|
},
|
|
160
160
|
validate: async (ctx, connectionId) => {
|
|
161
|
-
const connection = await getGroupConnection(ctx, config.component.
|
|
161
|
+
const connection = await getGroupConnection(ctx, config.component.sso, connectionId);
|
|
162
162
|
if (connection === null) throw convexError({
|
|
163
163
|
code: "INVALID_PARAMETERS",
|
|
164
164
|
message: connectionNotFoundError
|
|
165
165
|
});
|
|
166
|
-
const domains = await listConnectionDomains(ctx, config.component.
|
|
166
|
+
const domains = await listConnectionDomains(ctx, config.component.sso, connectionId);
|
|
167
167
|
const primaryDomains = domains.filter((domain) => domain.isPrimary);
|
|
168
168
|
const verifiedDomains = domains.filter((domain) => domain.verifiedAt !== void 0);
|
|
169
169
|
const warnings = [];
|
|
@@ -184,7 +184,7 @@ function createGroupConnectionDomain(deps) {
|
|
|
184
184
|
};
|
|
185
185
|
},
|
|
186
186
|
status: async (ctx, connectionId) => {
|
|
187
|
-
const [connection, domains] = await Promise.all([getGroupConnection(ctx, config.component.
|
|
187
|
+
const [connection, domains] = await Promise.all([getGroupConnection(ctx, config.component.sso, connectionId), listConnectionDomains(ctx, config.component.sso, connectionId)]);
|
|
188
188
|
if (connection === null) throw convexError({
|
|
189
189
|
code: "INVALID_PARAMETERS",
|
|
190
190
|
message: connectionNotFoundError
|
|
@@ -192,7 +192,7 @@ function createGroupConnectionDomain(deps) {
|
|
|
192
192
|
const primaryDomain = domains.find((domain) => domain.isPrimary) ?? null;
|
|
193
193
|
const verifiedDomains = domains.filter((domain) => domain.verifiedAt !== void 0);
|
|
194
194
|
const pendingChallenges = (await Promise.all(domains.map(async (domain) => {
|
|
195
|
-
const verification = await getConnectionDomainVerification(ctx, config.component.
|
|
195
|
+
const verification = await getConnectionDomainVerification(ctx, config.component.sso, domain._id);
|
|
196
196
|
if (!verification || verification.expiresAt < Date.now()) return null;
|
|
197
197
|
return {
|
|
198
198
|
domain: domain.domain,
|
|
@@ -245,13 +245,13 @@ function createGroupConnectionDomain(deps) {
|
|
|
245
245
|
};
|
|
246
246
|
},
|
|
247
247
|
remove: async (ctx, domainId) => {
|
|
248
|
-
await deleteConnectionDomain(ctx, config.component.
|
|
248
|
+
await deleteConnectionDomain(ctx, config.component.sso, domainId);
|
|
249
249
|
},
|
|
250
250
|
verification: {
|
|
251
251
|
request: async (ctx, args) => {
|
|
252
252
|
const connection = await loadConnectionOrThrow(ctx, args.connectionId);
|
|
253
253
|
const normalizedDomain = normalizeDomain(args.domain);
|
|
254
|
-
const domain = (await listConnectionDomains(ctx, config.component.
|
|
254
|
+
const domain = (await listConnectionDomains(ctx, config.component.sso, connection._id)).find((entry) => entry.domain === normalizedDomain);
|
|
255
255
|
if (!domain) throw convexError({
|
|
256
256
|
code: "INVALID_PARAMETERS",
|
|
257
257
|
message: "Domain is not attached to this connection."
|
|
@@ -261,7 +261,7 @@ function createGroupConnectionDomain(deps) {
|
|
|
261
261
|
const token = generateRandomString(32, INVITE_TOKEN_ALPHABET);
|
|
262
262
|
const tokenHash = await sha256(token);
|
|
263
263
|
const recordName = getDomainVerificationRecordName(normalizedDomain);
|
|
264
|
-
await upsertConnectionDomainVerification(ctx, config.component.
|
|
264
|
+
await upsertConnectionDomainVerification(ctx, config.component.sso, {
|
|
265
265
|
connectionId: connection._id,
|
|
266
266
|
groupId: connection.groupId,
|
|
267
267
|
domainId: domain._id,
|
|
@@ -301,7 +301,7 @@ function createGroupConnectionDomain(deps) {
|
|
|
301
301
|
confirm: async (ctx, args) => {
|
|
302
302
|
const connection = await loadConnectionOrThrow(ctx, args.connectionId);
|
|
303
303
|
const normalizedDomain = normalizeDomain(args.domain);
|
|
304
|
-
const domain = (await listConnectionDomains(ctx, config.component.
|
|
304
|
+
const domain = (await listConnectionDomains(ctx, config.component.sso, connection._id)).find((entry) => entry.domain === normalizedDomain);
|
|
305
305
|
if (!domain) throw convexError({
|
|
306
306
|
code: "INVALID_PARAMETERS",
|
|
307
307
|
message: "Domain is not attached to this connection."
|
|
@@ -316,7 +316,7 @@ function createGroupConnectionDomain(deps) {
|
|
|
316
316
|
message: "Domain is already verified."
|
|
317
317
|
}]
|
|
318
318
|
};
|
|
319
|
-
const verification = await getConnectionDomainVerification(ctx, config.component.
|
|
319
|
+
const verification = await getConnectionDomainVerification(ctx, config.component.sso, domain._id);
|
|
320
320
|
const checks = [];
|
|
321
321
|
if (!verification) {
|
|
322
322
|
checks.push({
|
|
@@ -335,7 +335,7 @@ function createGroupConnectionDomain(deps) {
|
|
|
335
335
|
ok: true
|
|
336
336
|
});
|
|
337
337
|
if (verification.expiresAt < Date.now()) {
|
|
338
|
-
await deleteConnectionDomainVerification(ctx, config.component.
|
|
338
|
+
await deleteConnectionDomainVerification(ctx, config.component.sso, domain._id);
|
|
339
339
|
checks.push({
|
|
340
340
|
name: "challenge_active",
|
|
341
341
|
ok: false,
|
|
@@ -377,7 +377,7 @@ function createGroupConnectionDomain(deps) {
|
|
|
377
377
|
checks
|
|
378
378
|
};
|
|
379
379
|
const verifiedAt = Date.now();
|
|
380
|
-
await verifyConnectionDomain(ctx, config.component.
|
|
380
|
+
await verifyConnectionDomain(ctx, config.component.sso, {
|
|
381
381
|
domainId: domain._id,
|
|
382
382
|
verifiedAt
|
|
383
383
|
});
|
|
@@ -407,7 +407,7 @@ function createGroupConnectionDomain(deps) {
|
|
|
407
407
|
configure: async (ctx, data) => {
|
|
408
408
|
let connection;
|
|
409
409
|
try {
|
|
410
|
-
connection = await getGroupConnection(ctx, config.component.
|
|
410
|
+
connection = await getGroupConnection(ctx, config.component.sso, data.connectionId);
|
|
411
411
|
} catch {
|
|
412
412
|
throw convexError({
|
|
413
413
|
code: "INTERNAL_ERROR",
|
|
@@ -493,7 +493,7 @@ function createGroupConnectionDomain(deps) {
|
|
|
493
493
|
hasMetadataXml: typeof nextSamlConfig?.idp?.metadataXml === "string"
|
|
494
494
|
});
|
|
495
495
|
try {
|
|
496
|
-
await updateGroupConnection(ctx, config.component.
|
|
496
|
+
await updateGroupConnection(ctx, config.component.sso, {
|
|
497
497
|
connectionId: connection._id,
|
|
498
498
|
data: {
|
|
499
499
|
status: "active",
|
|
@@ -507,7 +507,7 @@ function createGroupConnectionDomain(deps) {
|
|
|
507
507
|
});
|
|
508
508
|
}
|
|
509
509
|
if (normalizedDomains) for (const [index, domain] of normalizedDomains.entries()) try {
|
|
510
|
-
await addConnectionDomain(ctx, config.component.
|
|
510
|
+
await addConnectionDomain(ctx, config.component.sso, {
|
|
511
511
|
connectionId: connection._id,
|
|
512
512
|
groupId: connection.groupId,
|
|
513
513
|
domain,
|
|
@@ -547,7 +547,7 @@ function createGroupConnectionDomain(deps) {
|
|
|
547
547
|
refresh: async (ctx, data) => {
|
|
548
548
|
let connection;
|
|
549
549
|
try {
|
|
550
|
-
connection = await getGroupConnection(ctx, config.component.
|
|
550
|
+
connection = await getGroupConnection(ctx, config.component.sso, data.connectionId);
|
|
551
551
|
} catch {
|
|
552
552
|
throw convexError({
|
|
553
553
|
code: "INTERNAL_ERROR",
|
|
@@ -606,7 +606,7 @@ function createGroupConnectionDomain(deps) {
|
|
|
606
606
|
security: samlConfig.security
|
|
607
607
|
});
|
|
608
608
|
try {
|
|
609
|
-
await updateGroupConnection(ctx, config.component.
|
|
609
|
+
await updateGroupConnection(ctx, config.component.sso, {
|
|
610
610
|
connectionId: connection._id,
|
|
611
611
|
data: {
|
|
612
612
|
status: connection.status,
|
|
@@ -644,7 +644,7 @@ function createGroupConnectionDomain(deps) {
|
|
|
644
644
|
get: async (ctx, connectionId) => {
|
|
645
645
|
let connection;
|
|
646
646
|
try {
|
|
647
|
-
connection = await getGroupConnection(ctx, config.component.
|
|
647
|
+
connection = await getGroupConnection(ctx, config.component.sso, connectionId);
|
|
648
648
|
} catch {
|
|
649
649
|
throw convexError({
|
|
650
650
|
code: "INTERNAL_ERROR",
|
|
@@ -658,7 +658,7 @@ function createGroupConnectionDomain(deps) {
|
|
|
658
658
|
return getSamlConfig(connection.config);
|
|
659
659
|
},
|
|
660
660
|
status: (ctx, connectionId) => {
|
|
661
|
-
return getGroupConnection(ctx, config.component.
|
|
661
|
+
return getGroupConnection(ctx, config.component.sso, connectionId).then((connection) => {
|
|
662
662
|
if (!connection) throw convexError({
|
|
663
663
|
code: "INVALID_PARAMETERS",
|
|
664
664
|
message: connectionNotFoundError
|
|
@@ -679,7 +679,7 @@ function createGroupConnectionDomain(deps) {
|
|
|
679
679
|
});
|
|
680
680
|
},
|
|
681
681
|
metadata: async (ctx, opts) => {
|
|
682
|
-
const connection = await getGroupConnection(ctx, config.component.
|
|
682
|
+
const connection = await getGroupConnection(ctx, config.component.sso, opts.connectionId);
|
|
683
683
|
if (!connection) throw convexError({
|
|
684
684
|
code: "INVALID_PARAMETERS",
|
|
685
685
|
message: "Connection not found."
|
|
@@ -700,7 +700,7 @@ function createGroupConnectionDomain(deps) {
|
|
|
700
700
|
},
|
|
701
701
|
validate: async (ctx, connectionId) => {
|
|
702
702
|
const checks = [];
|
|
703
|
-
const connection = await getGroupConnection(ctx, config.component.
|
|
703
|
+
const connection = await getGroupConnection(ctx, config.component.sso, connectionId);
|
|
704
704
|
if (!connection) return {
|
|
705
705
|
ok: false,
|
|
706
706
|
connectionId,
|
|
@@ -804,7 +804,7 @@ function createGroupConnectionDomain(deps) {
|
|
|
804
804
|
});
|
|
805
805
|
let connection;
|
|
806
806
|
try {
|
|
807
|
-
connection = await getGroupConnection(ctx, config.component.
|
|
807
|
+
connection = await getGroupConnection(ctx, config.component.sso, data.connectionId);
|
|
808
808
|
} catch {
|
|
809
809
|
throw convexError({
|
|
810
810
|
code: "INTERNAL_ERROR",
|
|
@@ -850,7 +850,7 @@ function createGroupConnectionDomain(deps) {
|
|
|
850
850
|
}
|
|
851
851
|
});
|
|
852
852
|
try {
|
|
853
|
-
await updateGroupConnection(ctx, config.component.
|
|
853
|
+
await updateGroupConnection(ctx, config.component.sso, {
|
|
854
854
|
connectionId: data.connectionId,
|
|
855
855
|
data: { config: nextConfig }
|
|
856
856
|
});
|
|
@@ -871,7 +871,7 @@ function createGroupConnectionDomain(deps) {
|
|
|
871
871
|
});
|
|
872
872
|
}
|
|
873
873
|
try {
|
|
874
|
-
await upsertGroupConnectionSecret(ctx, config.component.
|
|
874
|
+
await upsertGroupConnectionSecret(ctx, config.component.sso, {
|
|
875
875
|
connectionId: data.connectionId,
|
|
876
876
|
groupId: connection.groupId,
|
|
877
877
|
kind: GROUP_CONNECTION_OIDC_CLIENT_SECRET_KIND,
|
|
@@ -922,7 +922,7 @@ function createGroupConnectionDomain(deps) {
|
|
|
922
922
|
get: async (ctx, connectionId) => {
|
|
923
923
|
let connection;
|
|
924
924
|
try {
|
|
925
|
-
connection = await getGroupConnection(ctx, config.component.
|
|
925
|
+
connection = await getGroupConnection(ctx, config.component.sso, connectionId);
|
|
926
926
|
} catch {
|
|
927
927
|
throw convexError({
|
|
928
928
|
code: "INTERNAL_ERROR",
|
|
@@ -945,7 +945,7 @@ function createGroupConnectionDomain(deps) {
|
|
|
945
945
|
return withOidcSecretState(getPublicOidcConfig(connection.config), secret !== null);
|
|
946
946
|
},
|
|
947
947
|
status: (ctx, connectionId) => {
|
|
948
|
-
return Promise.all([getGroupConnection(ctx, config.component.
|
|
948
|
+
return Promise.all([getGroupConnection(ctx, config.component.sso, connectionId), getGroupConnectionSecret(ctx, connectionId, GROUP_CONNECTION_OIDC_CLIENT_SECRET_KIND)]).then(([connection, secret]) => {
|
|
949
949
|
if (!connection) throw convexError({
|
|
950
950
|
code: "INVALID_PARAMETERS",
|
|
951
951
|
message: connectionNotFoundError
|
|
@@ -980,7 +980,7 @@ function createGroupConnectionDomain(deps) {
|
|
|
980
980
|
let connection;
|
|
981
981
|
if (data.connectionId !== void 0) {
|
|
982
982
|
try {
|
|
983
|
-
connection = await getGroupConnection(ctx, config.component.
|
|
983
|
+
connection = await getGroupConnection(ctx, config.component.sso, data.connectionId);
|
|
984
984
|
} catch {
|
|
985
985
|
throw convexError({
|
|
986
986
|
code: "INTERNAL_ERROR",
|
|
@@ -994,7 +994,7 @@ function createGroupConnectionDomain(deps) {
|
|
|
994
994
|
} else if (data.domain !== void 0 || data.email !== void 0) {
|
|
995
995
|
let result;
|
|
996
996
|
try {
|
|
997
|
-
result = await getGroupConnectionByDomain(ctx, config.component.
|
|
997
|
+
result = await getGroupConnectionByDomain(ctx, config.component.sso, normalizeDomain(data.domain ?? String(data.email).split("@").pop() ?? ""));
|
|
998
998
|
} catch {
|
|
999
999
|
throw convexError({
|
|
1000
1000
|
code: "INTERNAL_ERROR",
|
|
@@ -1066,7 +1066,7 @@ function createGroupConnectionDomain(deps) {
|
|
|
1066
1066
|
},
|
|
1067
1067
|
validate: async (ctx, connectionId) => {
|
|
1068
1068
|
const checks = [];
|
|
1069
|
-
const connection = await getGroupConnection(ctx, config.component.
|
|
1069
|
+
const connection = await getGroupConnection(ctx, config.component.sso, connectionId);
|
|
1070
1070
|
if (!connection) return {
|
|
1071
1071
|
ok: false,
|
|
1072
1072
|
connectionId,
|
|
@@ -1162,7 +1162,7 @@ function createGroupConnectionDomain(deps) {
|
|
|
1162
1162
|
return await recordGroupAuditEvent(ctx, data);
|
|
1163
1163
|
},
|
|
1164
1164
|
list: async (ctx, data) => {
|
|
1165
|
-
return await listAuditEvents(ctx, config.component.
|
|
1165
|
+
return await listAuditEvents(ctx, config.component.sso, data);
|
|
1166
1166
|
}
|
|
1167
1167
|
},
|
|
1168
1168
|
webhook
|
package/dist/server/sso/http.js
CHANGED
|
@@ -349,7 +349,7 @@ function addGroupHttpRuntime(deps) {
|
|
|
349
349
|
where: { groupId: state$1.connection.groupId },
|
|
350
350
|
limit: 100
|
|
351
351
|
});
|
|
352
|
-
const identities = await listScimIdentitiesByConnection(state$1.ctx, config.component.
|
|
352
|
+
const identities = await listScimIdentitiesByConnection(state$1.ctx, config.component.sso, state$1.connection._id);
|
|
353
353
|
const identityByUserId = new Map(identities.filter((identity) => typeof identity.userId === "string").map((identity) => [identity.userId, identity]));
|
|
354
354
|
const users = (await Promise.all(members.items.map(async (member) => {
|
|
355
355
|
const user = await auth.user.get(state$1.ctx, member.userId);
|
|
@@ -414,7 +414,7 @@ function addGroupHttpRuntime(deps) {
|
|
|
414
414
|
profile: extracted
|
|
415
415
|
}) ?? extracted;
|
|
416
416
|
const externalId = provisionProfile.externalId;
|
|
417
|
-
const existingIdentity = externalId ? await getScimIdentity(state$1.ctx, config.component.
|
|
417
|
+
const existingIdentity = externalId ? await getScimIdentity(state$1.ctx, config.component.sso, {
|
|
418
418
|
connectionId: state$1.connection._id,
|
|
419
419
|
resourceType: "user",
|
|
420
420
|
externalId
|
|
@@ -426,7 +426,7 @@ function addGroupHttpRuntime(deps) {
|
|
|
426
426
|
groups: provisionProfile.groups,
|
|
427
427
|
roles: provisionProfile.roles
|
|
428
428
|
});
|
|
429
|
-
const userId = existingUser?._id ? existingUser._id : await insertUser(state$1.ctx, config.component.
|
|
429
|
+
const userId = existingUser?._id ? existingUser._id : await insertUser(state$1.ctx, config.component.user, {
|
|
430
430
|
name: provisionProfile.name,
|
|
431
431
|
...typeof provisionProfile.firstName === "string" ? { firstName: provisionProfile.firstName } : {},
|
|
432
432
|
...typeof provisionProfile.lastName === "string" ? { lastName: provisionProfile.lastName } : {},
|
|
@@ -438,7 +438,7 @@ function addGroupHttpRuntime(deps) {
|
|
|
438
438
|
});
|
|
439
439
|
if (created && externalId) {
|
|
440
440
|
const providerId = state$1.connection.protocol === "oidc" ? groupOidcProviderId(state$1.connection._id) : groupSamlProviderId(state$1.connection._id);
|
|
441
|
-
await insertAccount(state$1.ctx, config.component.
|
|
441
|
+
await insertAccount(state$1.ctx, config.component.account, {
|
|
442
442
|
userId,
|
|
443
443
|
provider: providerId,
|
|
444
444
|
providerAccountId: externalId
|
|
@@ -461,7 +461,7 @@ function addGroupHttpRuntime(deps) {
|
|
|
461
461
|
policy: state$1.policy.provisioning.user,
|
|
462
462
|
source: "scim"
|
|
463
463
|
});
|
|
464
|
-
if (Object.keys(patchData).length > 0) await patchUser(state$1.ctx, config.component.
|
|
464
|
+
if (Object.keys(patchData).length > 0) await patchUser(state$1.ctx, config.component.user, {
|
|
465
465
|
userId,
|
|
466
466
|
data: patchData
|
|
467
467
|
});
|
|
@@ -477,7 +477,7 @@ function addGroupHttpRuntime(deps) {
|
|
|
477
477
|
roleIds: provisionedRoleIds,
|
|
478
478
|
status: provisionProfile.active === false ? "inactive" : "active"
|
|
479
479
|
});
|
|
480
|
-
if (externalId) await upsertScimIdentity(state$1.ctx, config.component.
|
|
480
|
+
if (externalId) await upsertScimIdentity(state$1.ctx, config.component.sso, {
|
|
481
481
|
connectionId: state$1.connection._id,
|
|
482
482
|
groupId: state$1.connection.groupId,
|
|
483
483
|
resourceType: "user",
|
|
@@ -510,7 +510,7 @@ function addGroupHttpRuntime(deps) {
|
|
|
510
510
|
const userId = state$1.parsedPath.resourceId;
|
|
511
511
|
const existingUser = await auth.user.get(state$1.ctx, userId);
|
|
512
512
|
if (!existingUser) return scimError(404, "notFound", "User not found.");
|
|
513
|
-
const existingIdentity = await getScimIdentityByConnectionAndUser(state$1.ctx, config.component.
|
|
513
|
+
const existingIdentity = await getScimIdentityByConnectionAndUser(state$1.ctx, config.component.sso, {
|
|
514
514
|
connectionId: state$1.connection._id,
|
|
515
515
|
userId
|
|
516
516
|
});
|
|
@@ -593,7 +593,7 @@ function addGroupHttpRuntime(deps) {
|
|
|
593
593
|
policy: state$1.policy.provisioning.user,
|
|
594
594
|
source: "scim"
|
|
595
595
|
});
|
|
596
|
-
if (Object.keys(nextPatchData).length > 0) await patchUser(state$1.ctx, config.component.
|
|
596
|
+
if (Object.keys(nextPatchData).length > 0) await patchUser(state$1.ctx, config.component.user, {
|
|
597
597
|
userId,
|
|
598
598
|
data: nextPatchData
|
|
599
599
|
});
|
|
@@ -606,7 +606,7 @@ function addGroupHttpRuntime(deps) {
|
|
|
606
606
|
}),
|
|
607
607
|
status: provisionProfile.active === false || nextActive === false ? "inactive" : "active"
|
|
608
608
|
});
|
|
609
|
-
await upsertScimIdentity(state$1.ctx, config.component.
|
|
609
|
+
await upsertScimIdentity(state$1.ctx, config.component.sso, {
|
|
610
610
|
connectionId: state$1.connection._id,
|
|
611
611
|
groupId: state$1.connection.groupId,
|
|
612
612
|
resourceType: "user",
|
|
@@ -637,7 +637,7 @@ function addGroupHttpRuntime(deps) {
|
|
|
637
637
|
const missing = requireScimResourceId(state$1.parsedPath.resourceId, "User");
|
|
638
638
|
if (missing) return missing;
|
|
639
639
|
const userId = state$1.parsedPath.resourceId;
|
|
640
|
-
const identity = await getScimIdentityByConnectionAndUser(state$1.ctx, config.component.
|
|
640
|
+
const identity = await getScimIdentityByConnectionAndUser(state$1.ctx, config.component.sso, {
|
|
641
641
|
connectionId: state$1.connection._id,
|
|
642
642
|
userId
|
|
643
643
|
});
|
|
@@ -647,8 +647,8 @@ function addGroupHttpRuntime(deps) {
|
|
|
647
647
|
userId
|
|
648
648
|
});
|
|
649
649
|
if (resolution.membership) await auth.member.delete(state$1.ctx, resolution.membership._id);
|
|
650
|
-
if (state$1.policy.provisioning.deprovision.mode === "hard") await deleteScimIdentity(state$1.ctx, config.component.
|
|
651
|
-
else await upsertScimIdentity(state$1.ctx, config.component.
|
|
650
|
+
if (state$1.policy.provisioning.deprovision.mode === "hard") await deleteScimIdentity(state$1.ctx, config.component.sso, identity._id);
|
|
651
|
+
else await upsertScimIdentity(state$1.ctx, config.component.sso, {
|
|
652
652
|
connectionId: identity.connectionId,
|
|
653
653
|
groupId: identity.groupId,
|
|
654
654
|
resourceType: identity.resourceType,
|
|
@@ -667,7 +667,7 @@ function addGroupHttpRuntime(deps) {
|
|
|
667
667
|
where: { parentGroupId: state$1.connection.groupId },
|
|
668
668
|
limit: 100
|
|
669
669
|
});
|
|
670
|
-
const identities = await listScimIdentitiesByConnection(state$1.ctx, config.component.
|
|
670
|
+
const identities = await listScimIdentitiesByConnection(state$1.ctx, config.component.sso, state$1.connection._id);
|
|
671
671
|
const identityByGroupId = new Map(identities.filter((identity) => typeof identity.mappedGroupId === "string").map((identity) => [identity.mappedGroupId, identity]));
|
|
672
672
|
const groups = await Promise.all(groupsList.items.map(async (group) => {
|
|
673
673
|
const typedGroup = group;
|
|
@@ -727,7 +727,7 @@ function addGroupHttpRuntime(deps) {
|
|
|
727
727
|
const handleGroupsPost = async (state$1) => {
|
|
728
728
|
const body = await readScimJson(state$1.request);
|
|
729
729
|
const externalId = typeof body.externalId === "string" ? body.externalId : void 0;
|
|
730
|
-
const existingIdentity = externalId ? await getScimIdentity(state$1.ctx, config.component.
|
|
730
|
+
const existingIdentity = externalId ? await getScimIdentity(state$1.ctx, config.component.sso, {
|
|
731
731
|
connectionId: state$1.connection._id,
|
|
732
732
|
resourceType: "group",
|
|
733
733
|
externalId
|
|
@@ -760,7 +760,7 @@ function addGroupHttpRuntime(deps) {
|
|
|
760
760
|
})).items.map((member) => ({ value: member.userId }))
|
|
761
761
|
}), 200, { Location: location$1 });
|
|
762
762
|
}
|
|
763
|
-
await upsertScimIdentity(state$1.ctx, config.component.
|
|
763
|
+
await upsertScimIdentity(state$1.ctx, config.component.sso, {
|
|
764
764
|
connectionId: state$1.connection._id,
|
|
765
765
|
groupId: state$1.connection.groupId,
|
|
766
766
|
resourceType: "group",
|
|
@@ -810,7 +810,7 @@ function addGroupHttpRuntime(deps) {
|
|
|
810
810
|
const missing = requireScimResourceId(state$1.parsedPath.resourceId, "Group");
|
|
811
811
|
if (missing) return missing;
|
|
812
812
|
const groupId = state$1.parsedPath.resourceId;
|
|
813
|
-
const identity = await getScimIdentityByMappedGroup(state$1.ctx, config.component.
|
|
813
|
+
const identity = await getScimIdentityByMappedGroup(state$1.ctx, config.component.sso, groupId);
|
|
814
814
|
if (!identity || identity.connectionId !== state$1.connection._id) return scimError(404, "notFound", "Group not found.");
|
|
815
815
|
const body = await readScimJson(state$1.request);
|
|
816
816
|
const operations = Array.isArray(body.Operations) ? body.Operations : unsupportedScimPatch();
|
|
@@ -906,10 +906,10 @@ function addGroupHttpRuntime(deps) {
|
|
|
906
906
|
const missing = requireScimResourceId(state$1.parsedPath.resourceId, "Group");
|
|
907
907
|
if (missing) return missing;
|
|
908
908
|
const groupId = state$1.parsedPath.resourceId;
|
|
909
|
-
const identity = await getScimIdentityByMappedGroup(state$1.ctx, config.component.
|
|
909
|
+
const identity = await getScimIdentityByMappedGroup(state$1.ctx, config.component.sso, groupId);
|
|
910
910
|
if (!identity || identity.connectionId !== state$1.connection._id) return scimError(404, "notFound", "Group not found.");
|
|
911
911
|
await auth.group.delete(state$1.ctx, groupId);
|
|
912
|
-
await deleteScimIdentity(state$1.ctx, config.component.
|
|
912
|
+
await deleteScimIdentity(state$1.ctx, config.component.sso, identity._id);
|
|
913
913
|
await state$1.recordScimEvent("group.sso.scim.group.deleted", true, "group", groupId);
|
|
914
914
|
return new Response(null, { status: 204 });
|
|
915
915
|
};
|
package/dist/server/sso/oidc.js
CHANGED
|
@@ -313,7 +313,7 @@ function createSyntheticOAuthMaterializedConfig(providerId, options) {
|
|
|
313
313
|
type: "oauth",
|
|
314
314
|
provider: null,
|
|
315
315
|
scopes: [],
|
|
316
|
-
accountLinking: options?.accountLinking ?? "
|
|
316
|
+
accountLinking: options?.accountLinking ?? "sameConnection"
|
|
317
317
|
};
|
|
318
318
|
}
|
|
319
319
|
/** @internal */
|
|
@@ -11,13 +11,13 @@ function createGroupPolicyDomain(deps) {
|
|
|
11
11
|
return await loadGroupPolicyOrThrow(ctx, groupId);
|
|
12
12
|
},
|
|
13
13
|
update: async (ctx, groupId, patch) => {
|
|
14
|
-
const group = await getGroup(ctx, config.component.
|
|
14
|
+
const group = await getGroup(ctx, config.component.group, groupId);
|
|
15
15
|
if (!group) throw convexError({
|
|
16
16
|
code: "INVALID_PARAMETERS",
|
|
17
17
|
message: "Group not found."
|
|
18
18
|
});
|
|
19
19
|
const policy = patchGroupConnectionPolicy(group.policy, patch);
|
|
20
|
-
await ctx.runMutation(config.component.
|
|
20
|
+
await ctx.runMutation(config.component.group.update, {
|
|
21
21
|
groupId,
|
|
22
22
|
data: { policy }
|
|
23
23
|
});
|
|
@@ -33,7 +33,7 @@ function createGroupPolicyDomain(deps) {
|
|
|
33
33
|
return policy;
|
|
34
34
|
},
|
|
35
35
|
validate: async (ctx, groupId) => {
|
|
36
|
-
if (!await getGroup(ctx, config.component.
|
|
36
|
+
if (!await getGroup(ctx, config.component.group, groupId)) return {
|
|
37
37
|
ok: false,
|
|
38
38
|
groupId,
|
|
39
39
|
checks: [{
|
|
@@ -4,8 +4,8 @@ import { asRecord } from "./shared.js";
|
|
|
4
4
|
const DEFAULT_GROUP_CONNECTION_POLICY = {
|
|
5
5
|
version: 1,
|
|
6
6
|
identity: { accountLinking: {
|
|
7
|
-
oidc: "
|
|
8
|
-
saml: "
|
|
7
|
+
oidc: "sameConnection",
|
|
8
|
+
saml: "sameConnection"
|
|
9
9
|
} },
|
|
10
10
|
provisioning: {
|
|
11
11
|
user: {
|
|
@@ -56,8 +56,16 @@ function normalizeGroupConnectionPolicy(policy) {
|
|
|
56
56
|
return {
|
|
57
57
|
version: 1,
|
|
58
58
|
identity: { accountLinking: {
|
|
59
|
-
oidc: oneOf(accountLinking.oidc, [
|
|
60
|
-
|
|
59
|
+
oidc: oneOf(accountLinking.oidc, [
|
|
60
|
+
"none",
|
|
61
|
+
"verifiedEmail",
|
|
62
|
+
"sameConnection"
|
|
63
|
+
], d.identity.accountLinking.oidc),
|
|
64
|
+
saml: oneOf(accountLinking.saml, [
|
|
65
|
+
"none",
|
|
66
|
+
"verifiedEmail",
|
|
67
|
+
"sameConnection"
|
|
68
|
+
], d.identity.accountLinking.saml)
|
|
61
69
|
} },
|
|
62
70
|
provisioning: {
|
|
63
71
|
user: {
|
|
@@ -11,7 +11,7 @@ function createGroupScimDomain(deps) {
|
|
|
11
11
|
const getScimBasePath = (connectionId) => `${requireEnv("CONVEX_SITE_URL")}/connections/${connectionId}/scim/v2`;
|
|
12
12
|
const validateScim = async (ctx, connectionId) => {
|
|
13
13
|
const checks = [];
|
|
14
|
-
const connection = await getGroupConnection(ctx, config.component.
|
|
14
|
+
const connection = await getGroupConnection(ctx, config.component.sso, connectionId);
|
|
15
15
|
if (!connection) return {
|
|
16
16
|
ok: false,
|
|
17
17
|
connectionId,
|
|
@@ -22,7 +22,7 @@ function createGroupScimDomain(deps) {
|
|
|
22
22
|
}]
|
|
23
23
|
};
|
|
24
24
|
const policy = await loadGroupPolicyOrThrow(ctx, connection.groupId);
|
|
25
|
-
const scimConfig = await getScimConfigByConnection(ctx, config.component.
|
|
25
|
+
const scimConfig = await getScimConfigByConnection(ctx, config.component.sso, connectionId);
|
|
26
26
|
const hasConfig = scimConfig !== null && scimConfig !== void 0;
|
|
27
27
|
checks.push({
|
|
28
28
|
name: "scim_config_exists",
|
|
@@ -87,7 +87,7 @@ function createGroupScimDomain(deps) {
|
|
|
87
87
|
};
|
|
88
88
|
return {
|
|
89
89
|
configure: async (ctx, data) => {
|
|
90
|
-
const connection = await getGroupConnection(ctx, config.component.
|
|
90
|
+
const connection = await getGroupConnection(ctx, config.component.sso, data.connectionId);
|
|
91
91
|
if (connection === null) throw convexError({
|
|
92
92
|
code: "INVALID_PARAMETERS",
|
|
93
93
|
message: "Connection not found."
|
|
@@ -95,7 +95,7 @@ function createGroupScimDomain(deps) {
|
|
|
95
95
|
const rawToken = generateRandomString(48, INVITE_TOKEN_ALPHABET);
|
|
96
96
|
const tokenHash = await sha256(rawToken);
|
|
97
97
|
const basePath = getScimBasePath(connection._id);
|
|
98
|
-
const configId = await upsertScimConfig(ctx, config.component.
|
|
98
|
+
const configId = await upsertScimConfig(ctx, config.component.sso, {
|
|
99
99
|
connectionId: connection._id,
|
|
100
100
|
groupId: connection.groupId,
|
|
101
101
|
status: data.status ?? "active",
|
|
@@ -133,7 +133,7 @@ function createGroupScimDomain(deps) {
|
|
|
133
133
|
};
|
|
134
134
|
},
|
|
135
135
|
get: async (ctx, connectionId) => {
|
|
136
|
-
const scimConfig = await getScimConfigByConnection(ctx, config.component.
|
|
136
|
+
const scimConfig = await getScimConfigByConnection(ctx, config.component.sso, connectionId);
|
|
137
137
|
if (!scimConfig) return null;
|
|
138
138
|
const shape = getScimConfigShape(scimConfig);
|
|
139
139
|
return {
|
|
@@ -143,7 +143,7 @@ function createGroupScimDomain(deps) {
|
|
|
143
143
|
};
|
|
144
144
|
},
|
|
145
145
|
status: async (ctx, connectionId) => {
|
|
146
|
-
const currentConfig = await getScimConfigByConnection(ctx, config.component.
|
|
146
|
+
const currentConfig = await getScimConfigByConnection(ctx, config.component.sso, connectionId);
|
|
147
147
|
const result = await validateScim(ctx, connectionId);
|
|
148
148
|
return {
|
|
149
149
|
connectionId,
|
|
@@ -155,17 +155,17 @@ function createGroupScimDomain(deps) {
|
|
|
155
155
|
};
|
|
156
156
|
},
|
|
157
157
|
getConfigByToken: async (ctx, token) => {
|
|
158
|
-
return await getScimConfigByTokenHash(ctx, config.component.
|
|
158
|
+
return await getScimConfigByTokenHash(ctx, config.component.sso, await sha256(token));
|
|
159
159
|
},
|
|
160
160
|
validate: async (ctx, connectionId) => {
|
|
161
161
|
return await validateScim(ctx, connectionId);
|
|
162
162
|
},
|
|
163
163
|
identity: {
|
|
164
164
|
get: async (ctx, data) => {
|
|
165
|
-
return await getScimIdentity(ctx, config.component.
|
|
165
|
+
return await getScimIdentity(ctx, config.component.sso, data);
|
|
166
166
|
},
|
|
167
167
|
upsert: async (ctx, data) => {
|
|
168
|
-
return await upsertScimIdentity(ctx, config.component.
|
|
168
|
+
return await upsertScimIdentity(ctx, config.component.sso, {
|
|
169
169
|
...data,
|
|
170
170
|
lastProvisionedAt: Date.now()
|
|
171
171
|
});
|
|
@@ -6,8 +6,8 @@ const groupConnectionStatusValidator = v.union(v.literal("draft"), v.literal("ac
|
|
|
6
6
|
/** @internal Structured validator for mounted group policy patch payloads. */
|
|
7
7
|
const groupPolicyPatchValidator = v.object({
|
|
8
8
|
identity: v.optional(v.object({ accountLinking: v.optional(v.object({
|
|
9
|
-
oidc: v.optional(v.union(v.literal("verifiedEmail"), v.literal("none"))),
|
|
10
|
-
saml: v.optional(v.union(v.literal("verifiedEmail"), v.literal("none")))
|
|
9
|
+
oidc: v.optional(v.union(v.literal("verifiedEmail"), v.literal("none"), v.literal("sameConnection"))),
|
|
10
|
+
saml: v.optional(v.union(v.literal("verifiedEmail"), v.literal("none"), v.literal("sameConnection")))
|
|
11
11
|
})) })),
|
|
12
12
|
provisioning: v.optional(v.object({
|
|
13
13
|
user: v.optional(v.object({
|