@robelest/convex-auth 0.0.4-preview.13 → 0.0.4-preview.15
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 +140 -9
- package/dist/bin.cjs +5957 -5478
- package/dist/client/index.d.ts +3 -7
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +27 -26
- package/dist/client/index.js.map +1 -1
- package/dist/component/_generated/api.d.ts +14 -0
- package/dist/component/_generated/api.d.ts.map +1 -1
- package/dist/component/_generated/api.js.map +1 -1
- package/dist/component/_generated/component.d.ts +1513 -3
- package/dist/component/_generated/component.d.ts.map +1 -1
- package/dist/component/convex.config.d.ts +2 -2
- package/dist/component/convex.config.d.ts.map +1 -1
- package/dist/component/model.d.ts +153 -0
- package/dist/component/model.d.ts.map +1 -0
- package/dist/component/model.js +327 -0
- package/dist/component/model.js.map +1 -0
- package/dist/component/providers/sso.d.ts +1 -1
- package/dist/component/public/enterprise.d.ts +49 -0
- package/dist/component/public/enterprise.d.ts.map +1 -0
- package/dist/component/public/enterprise.js +450 -0
- package/dist/component/public/enterprise.js.map +1 -0
- package/dist/component/public/factors.d.ts +52 -0
- package/dist/component/public/factors.d.ts.map +1 -0
- package/dist/component/public/factors.js +285 -0
- package/dist/component/public/factors.js.map +1 -0
- package/dist/component/public/groups.d.ts +118 -0
- package/dist/component/public/groups.d.ts.map +1 -0
- package/dist/component/public/groups.js +599 -0
- package/dist/component/public/groups.js.map +1 -0
- package/dist/component/public/identity.d.ts +93 -0
- package/dist/component/public/identity.d.ts.map +1 -0
- package/dist/component/public/identity.js +426 -0
- package/dist/component/public/identity.js.map +1 -0
- package/dist/component/public/keys.d.ts +41 -0
- package/dist/component/public/keys.d.ts.map +1 -0
- package/dist/component/public/keys.js +157 -0
- package/dist/component/public/keys.js.map +1 -0
- package/dist/component/public/shared.d.ts +26 -0
- package/dist/component/public/shared.d.ts.map +1 -0
- package/dist/component/public/shared.js +32 -0
- package/dist/component/public/shared.js.map +1 -0
- package/dist/component/public.d.ts +9 -321
- package/dist/component/public.d.ts.map +1 -1
- package/dist/component/public.js +6 -2145
- package/dist/component/schema.d.ts +368 -258
- package/dist/component/schema.js +23 -27
- package/dist/component/schema.js.map +1 -1
- package/dist/component/server/auth.d.ts +42 -7
- package/dist/component/server/auth.d.ts.map +1 -1
- package/dist/component/server/auth.js +70 -6
- package/dist/component/server/auth.js.map +1 -1
- package/dist/component/server/cookies.js +3 -0
- package/dist/component/server/cookies.js.map +1 -1
- package/dist/component/server/db.js +1 -0
- package/dist/component/server/db.js.map +1 -1
- package/dist/component/server/device.js +3 -1
- package/dist/component/server/device.js.map +1 -1
- package/dist/component/server/domains/core.js +466 -0
- package/dist/component/server/domains/core.js.map +1 -0
- package/dist/component/server/domains/sso.js +689 -0
- package/dist/component/server/domains/sso.js.map +1 -0
- package/dist/component/server/factory.d.ts +136 -0
- package/dist/component/server/factory.d.ts.map +1 -0
- package/dist/component/server/factory.js +1128 -0
- package/dist/component/server/factory.js.map +1 -0
- package/dist/component/server/fx.js +2 -1
- package/dist/component/server/fx.js.map +1 -1
- package/dist/component/server/http.js +287 -0
- package/dist/component/server/http.js.map +1 -0
- package/dist/component/server/identity.js +13 -0
- package/dist/component/server/identity.js.map +1 -0
- package/dist/component/server/keys.js +4 -0
- package/dist/component/server/keys.js.map +1 -1
- package/dist/component/server/mutations/account.js +1 -1
- package/dist/component/server/mutations/index.js +2 -2
- package/dist/component/server/mutations/index.js.map +1 -1
- package/dist/component/server/mutations/invalidate.js +1 -1
- package/dist/component/server/mutations/oauth.js +10 -7
- package/dist/component/server/mutations/oauth.js.map +1 -1
- package/dist/component/server/mutations/refresh.js +1 -1
- package/dist/component/server/mutations/register.js +1 -1
- package/dist/component/server/mutations/retrieve.js +1 -1
- package/dist/component/server/mutations/signature.js +1 -1
- package/dist/component/server/mutations/store.js +6 -3
- package/dist/component/server/mutations/store.js.map +1 -1
- package/dist/component/server/mutations/verify.js +1 -1
- package/dist/component/server/oauth.js +3 -0
- package/dist/component/server/oauth.js.map +1 -1
- package/dist/component/server/passkey.js +3 -2
- package/dist/component/server/passkey.js.map +1 -1
- package/dist/component/server/provider.js +2 -0
- package/dist/component/server/provider.js.map +1 -1
- package/dist/component/server/providers.js +3 -0
- package/dist/component/server/providers.js.map +1 -1
- package/dist/component/server/ratelimit.js +3 -0
- package/dist/component/server/ratelimit.js.map +1 -1
- package/dist/component/server/redirects.js +2 -0
- package/dist/component/server/redirects.js.map +1 -1
- package/dist/component/server/refresh.js +5 -0
- package/dist/component/server/refresh.js.map +1 -1
- package/dist/component/server/sessions.js +5 -0
- package/dist/component/server/sessions.js.map +1 -1
- package/dist/component/server/signin.js +2 -1
- package/dist/component/server/signin.js.map +1 -1
- package/dist/component/server/sso.js +166 -19
- package/dist/component/server/sso.js.map +1 -1
- package/dist/component/server/tokens.js +1 -0
- package/dist/component/server/tokens.js.map +1 -1
- package/dist/component/server/totp.js +4 -2
- package/dist/component/server/totp.js.map +1 -1
- package/dist/component/server/types.d.ts +50 -35
- package/dist/component/server/types.d.ts.map +1 -1
- package/dist/component/server/types.js.map +1 -1
- package/dist/component/server/users.js +1 -0
- package/dist/component/server/users.js.map +1 -1
- package/dist/component/server/utils.js +44 -2
- package/dist/component/server/utils.js.map +1 -1
- package/dist/providers/anonymous.d.ts +1 -1
- package/dist/providers/credentials.d.ts +1 -1
- package/dist/providers/password.d.ts +1 -1
- package/dist/providers/sso.d.ts +1 -1
- package/dist/providers/sso.js.map +1 -1
- package/dist/server/auth.d.ts +44 -9
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +70 -6
- package/dist/server/auth.js.map +1 -1
- package/dist/server/cookies.d.ts +1 -38
- package/dist/server/cookies.js +3 -0
- package/dist/server/cookies.js.map +1 -1
- package/dist/server/db.d.ts +1 -125
- package/dist/server/db.js +1 -0
- package/dist/server/db.js.map +1 -1
- package/dist/server/device.d.ts +1 -24
- package/dist/server/device.js +3 -1
- package/dist/server/device.js.map +1 -1
- package/dist/server/domains/core.d.ts +320 -0
- package/dist/server/domains/core.d.ts.map +1 -0
- package/dist/server/domains/core.js +466 -0
- package/dist/server/domains/core.js.map +1 -0
- package/dist/server/domains/sso.d.ts +340 -0
- package/dist/server/domains/sso.d.ts.map +1 -0
- package/dist/server/domains/sso.js +689 -0
- package/dist/server/domains/sso.js.map +1 -0
- package/dist/server/enterpriseValidators.d.ts +1 -0
- package/dist/server/enterpriseValidators.js +56 -0
- package/dist/server/enterpriseValidators.js.map +1 -0
- package/dist/server/factory.d.ts +136 -0
- package/dist/server/factory.d.ts.map +1 -0
- package/dist/server/factory.js +1128 -0
- package/dist/server/factory.js.map +1 -0
- package/dist/server/fx.d.ts +1 -16
- package/dist/server/fx.d.ts.map +1 -1
- package/dist/server/fx.js +1 -0
- package/dist/server/fx.js.map +1 -1
- package/dist/server/http.d.ts +59 -0
- package/dist/server/http.d.ts.map +1 -0
- package/dist/server/http.js +287 -0
- package/dist/server/http.js.map +1 -0
- package/dist/server/identity.d.ts +1 -0
- package/dist/server/identity.js +13 -0
- package/dist/server/identity.js.map +1 -0
- package/dist/server/index.d.ts +432 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +486 -36
- package/dist/server/index.js.map +1 -1
- package/dist/server/keys.d.ts +1 -57
- package/dist/server/keys.js +4 -0
- package/dist/server/keys.js.map +1 -1
- package/dist/server/mutations/account.d.ts +7 -7
- package/dist/server/mutations/account.d.ts.map +1 -1
- package/dist/server/mutations/code.d.ts +13 -13
- package/dist/server/mutations/index.d.ts +107 -107
- package/dist/server/mutations/index.d.ts.map +1 -1
- package/dist/server/mutations/index.js +1 -1
- package/dist/server/mutations/index.js.map +1 -1
- package/dist/server/mutations/invalidate.d.ts +5 -5
- package/dist/server/mutations/oauth.d.ts +10 -10
- package/dist/server/mutations/oauth.d.ts.map +1 -1
- package/dist/server/mutations/oauth.js +9 -6
- package/dist/server/mutations/oauth.js.map +1 -1
- package/dist/server/mutations/refresh.d.ts +4 -4
- package/dist/server/mutations/register.d.ts +12 -12
- package/dist/server/mutations/register.d.ts.map +1 -1
- package/dist/server/mutations/retrieve.d.ts +1 -1
- package/dist/server/mutations/signature.d.ts +5 -5
- package/dist/server/mutations/signature.d.ts.map +1 -1
- package/dist/server/mutations/signin.d.ts +1 -1
- package/dist/server/mutations/signout.d.ts +1 -1
- package/dist/server/mutations/store.d.ts +3 -2
- package/dist/server/mutations/store.d.ts.map +1 -1
- package/dist/server/mutations/store.js +6 -3
- package/dist/server/mutations/store.js.map +1 -1
- package/dist/server/mutations/verifier.d.ts +1 -1
- package/dist/server/mutations/verify.d.ts +4 -4
- package/dist/server/oauth.d.ts +1 -59
- package/dist/server/oauth.js +3 -0
- package/dist/server/oauth.js.map +1 -1
- package/dist/server/passkey.d.ts.map +1 -1
- package/dist/server/passkey.js +3 -2
- package/dist/server/passkey.js.map +1 -1
- package/dist/server/provider.d.ts +1 -14
- package/dist/server/provider.d.ts.map +1 -1
- package/dist/server/provider.js +2 -0
- package/dist/server/provider.js.map +1 -1
- package/dist/server/providers.js +3 -0
- package/dist/server/providers.js.map +1 -1
- package/dist/server/ratelimit.d.ts +1 -22
- package/dist/server/ratelimit.js +3 -0
- package/dist/server/ratelimit.js.map +1 -1
- package/dist/server/redirects.d.ts +1 -10
- package/dist/server/redirects.js +2 -0
- package/dist/server/redirects.js.map +1 -1
- package/dist/server/refresh.d.ts +1 -37
- package/dist/server/refresh.js +5 -0
- package/dist/server/refresh.js.map +1 -1
- package/dist/server/sessions.d.ts +1 -28
- package/dist/server/sessions.js +5 -0
- package/dist/server/sessions.js.map +1 -1
- package/dist/server/signin.d.ts +1 -55
- package/dist/server/signin.js +2 -1
- package/dist/server/signin.js.map +1 -1
- package/dist/server/sso.d.ts +1 -348
- package/dist/server/sso.js +165 -18
- package/dist/server/sso.js.map +1 -1
- package/dist/server/templates.d.ts +1 -21
- package/dist/server/templates.js +1 -0
- package/dist/server/templates.js.map +1 -1
- package/dist/server/tokens.d.ts +1 -11
- package/dist/server/tokens.js +1 -0
- package/dist/server/tokens.js.map +1 -1
- package/dist/server/totp.d.ts +1 -23
- package/dist/server/totp.js +4 -2
- package/dist/server/totp.js.map +1 -1
- package/dist/server/types.d.ts +55 -71
- package/dist/server/types.d.ts.map +1 -1
- package/dist/server/types.js.map +1 -1
- package/dist/server/users.d.ts +1 -31
- package/dist/server/users.js +1 -0
- package/dist/server/users.js.map +1 -1
- package/dist/server/utils.d.ts +1 -27
- package/dist/server/utils.js +44 -2
- package/dist/server/utils.js.map +1 -1
- package/dist/server/version.d.ts +1 -1
- package/dist/server/version.js +1 -1
- package/dist/server/version.js.map +1 -1
- package/package.json +4 -5
- package/src/cli/bin.ts +5 -0
- package/src/cli/index.ts +22 -9
- package/src/cli/keys.ts +3 -0
- package/src/client/index.ts +36 -37
- package/src/component/_generated/api.ts +14 -0
- package/src/component/_generated/component.ts +1920 -3
- package/src/component/index.ts +2 -0
- package/src/component/model.ts +424 -0
- package/src/component/public/enterprise.ts +654 -0
- package/src/component/public/factors.ts +332 -0
- package/src/component/public/groups.ts +951 -0
- package/src/component/public/identity.ts +566 -0
- package/src/component/public/keys.ts +209 -0
- package/src/component/public/shared.ts +117 -0
- package/src/component/public.ts +5 -2965
- package/src/component/schema.ts +47 -57
- package/src/providers/sso.ts +1 -1
- package/src/server/auth.ts +192 -9
- package/src/server/cookies.ts +3 -0
- package/src/server/db.ts +3 -0
- package/src/server/device.ts +3 -1
- package/src/server/domains/core.ts +916 -0
- package/src/server/domains/sso.ts +1462 -0
- package/src/server/enterpriseValidators.ts +88 -0
- package/src/server/factory.ts +2168 -0
- package/src/server/fx.ts +1 -0
- package/src/server/http.ts +529 -0
- package/src/server/identity.ts +18 -0
- package/src/server/index.ts +712 -40
- package/src/server/keys.ts +4 -0
- package/src/server/mutations/index.ts +1 -1
- package/src/server/mutations/oauth.ts +36 -8
- package/src/server/mutations/store.ts +6 -3
- package/src/server/oauth.ts +6 -0
- package/src/server/passkey.ts +3 -2
- package/src/server/provider.ts +2 -0
- package/src/server/providers.ts +3 -0
- package/src/server/ratelimit.ts +3 -0
- package/src/server/redirects.ts +2 -0
- package/src/server/refresh.ts +5 -0
- package/src/server/sessions.ts +5 -0
- package/src/server/signin.ts +1 -0
- package/src/server/sso.ts +251 -17
- package/src/server/templates.ts +1 -0
- package/src/server/tokens.ts +1 -0
- package/src/server/totp.ts +4 -2
- package/src/server/types.ts +85 -77
- package/src/server/users.ts +1 -0
- package/src/server/utils.ts +71 -1
- package/src/server/version.ts +1 -1
- package/dist/component/public.js.map +0 -1
- package/dist/component/server/implementation.d.ts +0 -1264
- package/dist/component/server/implementation.d.ts.map +0 -1
- package/dist/component/server/implementation.js +0 -2365
- package/dist/component/server/implementation.js.map +0 -1
- package/dist/server/cookies.d.ts.map +0 -1
- package/dist/server/db.d.ts.map +0 -1
- package/dist/server/device.d.ts.map +0 -1
- package/dist/server/implementation.d.ts +0 -1264
- package/dist/server/implementation.d.ts.map +0 -1
- package/dist/server/implementation.js +0 -2365
- package/dist/server/implementation.js.map +0 -1
- package/dist/server/keys.d.ts.map +0 -1
- package/dist/server/oauth.d.ts.map +0 -1
- package/dist/server/ratelimit.d.ts.map +0 -1
- package/dist/server/redirects.d.ts.map +0 -1
- package/dist/server/refresh.d.ts.map +0 -1
- package/dist/server/sessions.d.ts.map +0 -1
- package/dist/server/signin.d.ts.map +0 -1
- package/dist/server/sso.d.ts.map +0 -1
- package/dist/server/templates.d.ts.map +0 -1
- package/dist/server/tokens.d.ts.map +0 -1
- package/dist/server/totp.d.ts.map +0 -1
- package/dist/server/users.d.ts.map +0 -1
- package/dist/server/utils.d.ts.map +0 -1
- package/src/server/implementation.ts +0 -5336
package/src/component/schema.ts
CHANGED
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
import { defineSchema, defineTable } from "convex/server";
|
|
2
2
|
import { v } from "convex/values";
|
|
3
3
|
|
|
4
|
+
import {
|
|
5
|
+
vApiKeyRateLimit,
|
|
6
|
+
vApiKeyRateLimitState,
|
|
7
|
+
vApiKeyScope,
|
|
8
|
+
vAuditActorType,
|
|
9
|
+
vAuditStatus,
|
|
10
|
+
vDeviceStatus,
|
|
11
|
+
vEnterprisePolicy,
|
|
12
|
+
vEnterpriseSecretKind,
|
|
13
|
+
vEnterpriseStatus,
|
|
14
|
+
vInviteStatus,
|
|
15
|
+
vScimResourceType,
|
|
16
|
+
vScimStatus,
|
|
17
|
+
vTag,
|
|
18
|
+
vWebhookDeliveryStatus,
|
|
19
|
+
vWebhookEndpointStatus,
|
|
20
|
+
} from "./model";
|
|
21
|
+
|
|
4
22
|
/**
|
|
5
23
|
* Schema for the auth component.
|
|
6
24
|
*
|
|
@@ -166,11 +184,7 @@ export default defineSchema({
|
|
|
166
184
|
/** Minimum polling interval in seconds. */
|
|
167
185
|
interval: v.number(),
|
|
168
186
|
/** Current status of this device authorization session. */
|
|
169
|
-
status:
|
|
170
|
-
v.literal("pending"),
|
|
171
|
-
v.literal("authorized"),
|
|
172
|
-
v.literal("denied"),
|
|
173
|
-
),
|
|
187
|
+
status: vDeviceStatus,
|
|
174
188
|
/** Set when the user authorizes — links to the authorizing user. */
|
|
175
189
|
userId: v.optional(v.id("User")),
|
|
176
190
|
/** Set when the user authorizes — the session created for the device. */
|
|
@@ -201,7 +215,7 @@ export default defineSchema({
|
|
|
201
215
|
type: v.optional(v.string()),
|
|
202
216
|
parentGroupId: v.optional(v.id("Group")),
|
|
203
217
|
/** Faceted classification tags. Normalized at write time (trimmed, lowercased). */
|
|
204
|
-
tags: v.optional(v.array(
|
|
218
|
+
tags: v.optional(v.array(vTag)),
|
|
205
219
|
extend: v.optional(v.any()),
|
|
206
220
|
})
|
|
207
221
|
.index("slug", ["slug"])
|
|
@@ -253,12 +267,7 @@ export default defineSchema({
|
|
|
253
267
|
email: v.optional(v.string()),
|
|
254
268
|
tokenHash: v.string(),
|
|
255
269
|
role: v.optional(v.string()),
|
|
256
|
-
status:
|
|
257
|
-
v.literal("pending"),
|
|
258
|
-
v.literal("accepted"),
|
|
259
|
-
v.literal("revoked"),
|
|
260
|
-
v.literal("expired"),
|
|
261
|
-
),
|
|
270
|
+
status: vInviteStatus,
|
|
262
271
|
expiresTime: v.optional(v.number()),
|
|
263
272
|
acceptedByUserId: v.optional(v.id("User")),
|
|
264
273
|
acceptedTime: v.optional(v.number()),
|
|
@@ -287,11 +296,8 @@ export default defineSchema({
|
|
|
287
296
|
groupId: v.id("Group"),
|
|
288
297
|
slug: v.optional(v.string()),
|
|
289
298
|
name: v.optional(v.string()),
|
|
290
|
-
status:
|
|
291
|
-
|
|
292
|
-
v.literal("active"),
|
|
293
|
-
v.literal("disabled"),
|
|
294
|
-
),
|
|
299
|
+
status: vEnterpriseStatus,
|
|
300
|
+
policy: v.optional(vEnterprisePolicy),
|
|
295
301
|
config: v.optional(v.any()),
|
|
296
302
|
extend: v.optional(v.any()),
|
|
297
303
|
})
|
|
@@ -313,21 +319,30 @@ export default defineSchema({
|
|
|
313
319
|
.index("group_id", ["groupId"])
|
|
314
320
|
.index("domain", ["domain"]),
|
|
315
321
|
|
|
322
|
+
/**
|
|
323
|
+
* Encrypted enterprise secrets stored separately from protocol config.
|
|
324
|
+
*/
|
|
325
|
+
EnterpriseSecret: defineTable({
|
|
326
|
+
enterpriseId: v.id("Enterprise"),
|
|
327
|
+
groupId: v.id("Group"),
|
|
328
|
+
kind: vEnterpriseSecretKind,
|
|
329
|
+
ciphertext: v.string(),
|
|
330
|
+
updatedAt: v.number(),
|
|
331
|
+
})
|
|
332
|
+
.index("enterprise_id", ["enterpriseId"])
|
|
333
|
+
.index("enterprise_id_kind", ["enterpriseId", "kind"])
|
|
334
|
+
.index("group_id", ["groupId"]),
|
|
335
|
+
|
|
316
336
|
/**
|
|
317
337
|
* SCIM configuration for an enterprise tenant.
|
|
318
338
|
*/
|
|
319
339
|
EnterpriseScimConfig: defineTable({
|
|
320
340
|
enterpriseId: v.id("Enterprise"),
|
|
321
341
|
groupId: v.id("Group"),
|
|
322
|
-
status:
|
|
323
|
-
v.literal("draft"),
|
|
324
|
-
v.literal("active"),
|
|
325
|
-
v.literal("disabled"),
|
|
326
|
-
),
|
|
342
|
+
status: vScimStatus,
|
|
327
343
|
basePath: v.string(),
|
|
328
344
|
tokenHash: v.string(),
|
|
329
345
|
lastRotatedAt: v.optional(v.number()),
|
|
330
|
-
deprovisionMode: v.optional(v.union(v.literal("soft"), v.literal("hard"))),
|
|
331
346
|
extend: v.optional(v.any()),
|
|
332
347
|
})
|
|
333
348
|
.index("enterprise_id", ["enterpriseId"])
|
|
@@ -341,7 +356,7 @@ export default defineSchema({
|
|
|
341
356
|
EnterpriseScimIdentity: defineTable({
|
|
342
357
|
enterpriseId: v.id("Enterprise"),
|
|
343
358
|
groupId: v.id("Group"),
|
|
344
|
-
resourceType:
|
|
359
|
+
resourceType: vScimResourceType,
|
|
345
360
|
externalId: v.string(),
|
|
346
361
|
userId: v.optional(v.id("User")),
|
|
347
362
|
mappedGroupId: v.optional(v.id("Group")),
|
|
@@ -356,6 +371,7 @@ export default defineSchema({
|
|
|
356
371
|
"resourceType",
|
|
357
372
|
"externalId",
|
|
358
373
|
])
|
|
374
|
+
.index("enterprise_id_user_id", ["enterpriseId", "userId"])
|
|
359
375
|
.index("user_id", ["userId"])
|
|
360
376
|
.index("mapped_group_id", ["mappedGroupId"]),
|
|
361
377
|
|
|
@@ -366,17 +382,11 @@ export default defineSchema({
|
|
|
366
382
|
enterpriseId: v.id("Enterprise"),
|
|
367
383
|
groupId: v.id("Group"),
|
|
368
384
|
eventType: v.string(),
|
|
369
|
-
actorType:
|
|
370
|
-
v.literal("user"),
|
|
371
|
-
v.literal("system"),
|
|
372
|
-
v.literal("scim"),
|
|
373
|
-
v.literal("api_key"),
|
|
374
|
-
v.literal("webhook"),
|
|
375
|
-
),
|
|
385
|
+
actorType: vAuditActorType,
|
|
376
386
|
actorId: v.optional(v.string()),
|
|
377
387
|
subjectType: v.string(),
|
|
378
388
|
subjectId: v.optional(v.string()),
|
|
379
|
-
status:
|
|
389
|
+
status: vAuditStatus,
|
|
380
390
|
occurredAt: v.number(),
|
|
381
391
|
requestId: v.optional(v.string()),
|
|
382
392
|
ip: v.optional(v.string()),
|
|
@@ -393,7 +403,7 @@ export default defineSchema({
|
|
|
393
403
|
enterpriseId: v.id("Enterprise"),
|
|
394
404
|
groupId: v.id("Group"),
|
|
395
405
|
url: v.string(),
|
|
396
|
-
status:
|
|
406
|
+
status: vWebhookEndpointStatus,
|
|
397
407
|
secretHash: v.string(),
|
|
398
408
|
subscriptions: v.array(v.string()),
|
|
399
409
|
createdByUserId: v.optional(v.id("User")),
|
|
@@ -414,12 +424,7 @@ export default defineSchema({
|
|
|
414
424
|
endpointId: v.id("EnterpriseWebhookEndpoint"),
|
|
415
425
|
auditEventId: v.optional(v.id("EnterpriseAuditEvent")),
|
|
416
426
|
eventType: v.string(),
|
|
417
|
-
status:
|
|
418
|
-
v.literal("pending"),
|
|
419
|
-
v.literal("processing"),
|
|
420
|
-
v.literal("delivered"),
|
|
421
|
-
v.literal("failed"),
|
|
422
|
-
),
|
|
427
|
+
status: vWebhookDeliveryStatus,
|
|
423
428
|
attemptCount: v.number(),
|
|
424
429
|
nextAttemptAt: v.number(),
|
|
425
430
|
lastAttemptAt: v.optional(v.number()),
|
|
@@ -454,26 +459,11 @@ export default defineSchema({
|
|
|
454
459
|
/** User-assigned name (e.g. "CI Pipeline", "Production API"). */
|
|
455
460
|
name: v.string(),
|
|
456
461
|
/** Scoped permissions: [{ resource: "users", actions: ["read", "list"] }]. */
|
|
457
|
-
scopes: v.array(
|
|
458
|
-
v.object({
|
|
459
|
-
resource: v.string(),
|
|
460
|
-
actions: v.array(v.string()),
|
|
461
|
-
}),
|
|
462
|
-
),
|
|
462
|
+
scopes: v.array(vApiKeyScope),
|
|
463
463
|
/** Optional per-key rate limit configuration. */
|
|
464
|
-
rateLimit: v.optional(
|
|
465
|
-
v.object({
|
|
466
|
-
maxRequests: v.number(),
|
|
467
|
-
windowMs: v.number(),
|
|
468
|
-
}),
|
|
469
|
-
),
|
|
464
|
+
rateLimit: v.optional(vApiKeyRateLimit),
|
|
470
465
|
/** Rate limit state tracking (token-bucket). */
|
|
471
|
-
rateLimitState: v.optional(
|
|
472
|
-
v.object({
|
|
473
|
-
attemptsLeft: v.number(),
|
|
474
|
-
lastAttemptTime: v.number(),
|
|
475
|
-
}),
|
|
476
|
-
),
|
|
466
|
+
rateLimitState: v.optional(vApiKeyRateLimitState),
|
|
477
467
|
/** Expiration timestamp. Null/undefined = never expires. */
|
|
478
468
|
expiresAt: v.optional(v.number()),
|
|
479
469
|
lastUsedAt: v.optional(v.number()),
|
package/src/providers/sso.ts
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* });
|
|
15
15
|
*
|
|
16
16
|
* // auth.sso is now available
|
|
17
|
-
* await auth.sso.oidc.configure(ctx, { enterpriseId, clientId, ... });
|
|
17
|
+
* await auth.sso.admin.oidc.configure(ctx, { enterpriseId, clientId, ... });
|
|
18
18
|
* ```
|
|
19
19
|
*
|
|
20
20
|
* Without `new SSO()` in the providers list, `auth.sso` is not
|
package/src/server/auth.ts
CHANGED
|
@@ -8,9 +8,9 @@ import type { UserIdentity } from "convex/server";
|
|
|
8
8
|
import type { GenericId } from "convex/values";
|
|
9
9
|
|
|
10
10
|
import type { AuthApiRefs } from "../client/index";
|
|
11
|
+
import { Auth as AuthFactory } from "./factory";
|
|
11
12
|
import { Fx } from "./fx";
|
|
12
13
|
import { AuthError } from "./fx";
|
|
13
|
-
import { Auth as AuthFactory } from "./implementation";
|
|
14
14
|
import type { Doc } from "./types";
|
|
15
15
|
import type {
|
|
16
16
|
AuthProviderConfig,
|
|
@@ -47,14 +47,58 @@ export type AuthApiBase = {
|
|
|
47
47
|
http: ReturnType<typeof AuthFactory>["auth"]["http"];
|
|
48
48
|
};
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
type InternalSsoApi = ReturnType<typeof AuthFactory>["auth"]["sso"];
|
|
51
|
+
|
|
52
|
+
type PublicSsoAdminApi = {
|
|
53
|
+
connection: InternalSsoApi["connection"] & {
|
|
54
|
+
domain: {
|
|
55
|
+
list: InternalSsoApi["domain"]["list"];
|
|
56
|
+
validate: InternalSsoApi["domain"]["validate"];
|
|
57
|
+
set: (
|
|
58
|
+
ctx: Parameters<InternalSsoApi["connection"]["create"]>[0],
|
|
59
|
+
enterpriseId: string,
|
|
60
|
+
domains: Array<{
|
|
61
|
+
domain: string;
|
|
62
|
+
isPrimary?: boolean;
|
|
63
|
+
verifiedAt?: number;
|
|
64
|
+
}>,
|
|
65
|
+
) => Promise<void>;
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
oidc: Omit<InternalSsoApi["oidc"], "signIn">;
|
|
69
|
+
saml: Omit<InternalSsoApi["saml"], "metadata">;
|
|
70
|
+
policy: InternalSsoApi["policy"];
|
|
71
|
+
audit: {
|
|
72
|
+
list: InternalSsoApi["audit"]["list"];
|
|
73
|
+
};
|
|
74
|
+
webhook: {
|
|
75
|
+
endpoint: InternalSsoApi["webhook"]["endpoint"];
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
type PublicSsoClientApi = {
|
|
80
|
+
signIn: InternalSsoApi["oidc"]["signIn"];
|
|
81
|
+
metadata: InternalSsoApi["saml"]["metadata"];
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
type PublicSsoApi = {
|
|
85
|
+
admin: PublicSsoAdminApi;
|
|
86
|
+
client: PublicSsoClientApi;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
type PublicScimApi = {
|
|
90
|
+
admin: Omit<InternalSsoApi["scim"], "getConfigByToken" | "identity">;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
/** Auth API with enterprise namespaces — present only when `new SSO()` is in providers. */
|
|
51
94
|
export type AuthApi = AuthApiBase & {
|
|
52
|
-
sso:
|
|
95
|
+
sso: PublicSsoApi;
|
|
96
|
+
scim: PublicScimApi;
|
|
53
97
|
};
|
|
54
98
|
|
|
55
99
|
/**
|
|
56
100
|
* The return type of `createAuth`. Conditional namespaces:
|
|
57
|
-
* - `auth.sso` — only when `new SSO()` is in providers
|
|
101
|
+
* - `auth.sso` and `auth.scim` — only when `new SSO()` is in providers
|
|
58
102
|
* - `auth.clientApi` — typed API refs for the client SDK with capabilities
|
|
59
103
|
*/
|
|
60
104
|
export type ConvexAuthResult<P extends AuthProviderConfig[]> =
|
|
@@ -72,7 +116,7 @@ export type ConvexAuthResult<P extends AuthProviderConfig[]> =
|
|
|
72
116
|
* // Frontend
|
|
73
117
|
* import type { auth } from "../convex/auth";
|
|
74
118
|
* import type { InferClientApi } from "@robelest/convex-auth/component";
|
|
75
|
-
* const c = client<InferClientApi<typeof auth>>({ convex, api:
|
|
119
|
+
* const c = client<InferClientApi<typeof auth>>({ convex, api: api.auth });
|
|
76
120
|
* ```
|
|
77
121
|
*/
|
|
78
122
|
export type InferClientApi<T> =
|
|
@@ -94,9 +138,9 @@ export type AuthLike = Pick<AuthApiBase, "user">;
|
|
|
94
138
|
/**
|
|
95
139
|
* Create an auth API object.
|
|
96
140
|
*
|
|
97
|
-
* When `new SSO()` is included in providers, `auth.sso`
|
|
98
|
-
* on the returned object. Without it,
|
|
99
|
-
* accessing
|
|
141
|
+
* When `new SSO()` is included in providers, `auth.sso` and `auth.scim`
|
|
142
|
+
* are available on the returned object. Without it, those namespaces are
|
|
143
|
+
* absent and accessing them is a TypeScript compile error.
|
|
100
144
|
*/
|
|
101
145
|
export function createAuth<P extends AuthProviderConfig[]>(
|
|
102
146
|
component: ConvexAuthConfig["component"],
|
|
@@ -107,6 +151,138 @@ export function createAuth<P extends AuthProviderConfig[]>(
|
|
|
107
151
|
component,
|
|
108
152
|
providers: [...config.providers],
|
|
109
153
|
});
|
|
154
|
+
const {
|
|
155
|
+
domain: domainApi,
|
|
156
|
+
scim: scimApi,
|
|
157
|
+
connection: connectionApi,
|
|
158
|
+
audit: auditApi,
|
|
159
|
+
webhook: webhookApi,
|
|
160
|
+
oidc: oidcApi,
|
|
161
|
+
saml: samlApi,
|
|
162
|
+
...restSso
|
|
163
|
+
} = authResult.auth.sso as InternalSsoApi;
|
|
164
|
+
|
|
165
|
+
type SetEnterpriseDomains = PublicSsoAdminApi["connection"]["domain"]["set"];
|
|
166
|
+
type EnterpriseDomainInput = Array<{
|
|
167
|
+
domain: string;
|
|
168
|
+
isPrimary?: boolean;
|
|
169
|
+
verifiedAt?: number;
|
|
170
|
+
}>;
|
|
171
|
+
const setEnterpriseDomains: PublicSsoAdminApi["connection"]["domain"]["set"] =
|
|
172
|
+
async (
|
|
173
|
+
ctx: Parameters<SetEnterpriseDomains>[0],
|
|
174
|
+
enterpriseId: Parameters<SetEnterpriseDomains>[1],
|
|
175
|
+
domains: EnterpriseDomainInput,
|
|
176
|
+
) => {
|
|
177
|
+
const enterprise = await connectionApi.get(ctx, enterpriseId);
|
|
178
|
+
if (enterprise === null) {
|
|
179
|
+
throw new AuthError(
|
|
180
|
+
"INVALID_PARAMETERS",
|
|
181
|
+
"Enterprise not found.",
|
|
182
|
+
).toConvexError();
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const normalized = domains.map((entry: (typeof domains)[number]) => ({
|
|
186
|
+
...entry,
|
|
187
|
+
domain: entry.domain.trim().toLowerCase(),
|
|
188
|
+
}));
|
|
189
|
+
const deduped = new Map<string, (typeof normalized)[number]>();
|
|
190
|
+
for (const entry of normalized) {
|
|
191
|
+
if (entry.domain.length === 0) {
|
|
192
|
+
throw new AuthError(
|
|
193
|
+
"INVALID_PARAMETERS",
|
|
194
|
+
"Domain must not be empty.",
|
|
195
|
+
).toConvexError();
|
|
196
|
+
}
|
|
197
|
+
if (deduped.has(entry.domain)) {
|
|
198
|
+
throw new AuthError(
|
|
199
|
+
"INVALID_PARAMETERS",
|
|
200
|
+
`Duplicate domain: ${entry.domain}`,
|
|
201
|
+
).toConvexError();
|
|
202
|
+
}
|
|
203
|
+
deduped.set(entry.domain, entry);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const nextDomains = [...deduped.values()];
|
|
207
|
+
const primaryCount = nextDomains.filter(
|
|
208
|
+
(entry) => entry.isPrimary,
|
|
209
|
+
).length;
|
|
210
|
+
if (primaryCount > 1) {
|
|
211
|
+
throw new AuthError(
|
|
212
|
+
"INVALID_PARAMETERS",
|
|
213
|
+
"Only one primary domain may be set.",
|
|
214
|
+
).toConvexError();
|
|
215
|
+
}
|
|
216
|
+
if (nextDomains.length > 0 && primaryCount === 0) {
|
|
217
|
+
nextDomains[0] = { ...nextDomains[0], isPrimary: true };
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const currentDomains = await domainApi.list(ctx, enterpriseId);
|
|
221
|
+
const currentByDomain = new Map<string, (typeof currentDomains)[number]>(
|
|
222
|
+
currentDomains.map((entry: (typeof currentDomains)[number]) => [
|
|
223
|
+
entry.domain.toLowerCase(),
|
|
224
|
+
entry,
|
|
225
|
+
]),
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
for (const existing of currentDomains) {
|
|
229
|
+
if (!deduped.has(existing.domain.toLowerCase())) {
|
|
230
|
+
await domainApi.remove(ctx, existing._id);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
for (const nextDomain of nextDomains) {
|
|
235
|
+
const current = currentByDomain.get(nextDomain.domain);
|
|
236
|
+
if (
|
|
237
|
+
current &&
|
|
238
|
+
current.isPrimary === Boolean(nextDomain.isPrimary) &&
|
|
239
|
+
current.verifiedAt === (nextDomain.verifiedAt ?? current.verifiedAt)
|
|
240
|
+
) {
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
if (current) {
|
|
244
|
+
await domainApi.remove(ctx, current._id);
|
|
245
|
+
}
|
|
246
|
+
await domainApi.add(ctx, {
|
|
247
|
+
enterpriseId: enterprise._id,
|
|
248
|
+
groupId: enterprise.groupId,
|
|
249
|
+
domain: nextDomain.domain,
|
|
250
|
+
isPrimary: nextDomain.isPrimary,
|
|
251
|
+
verifiedAt: nextDomain.verifiedAt ?? current?.verifiedAt,
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
const publicSso: PublicSsoApi = {
|
|
257
|
+
admin: {
|
|
258
|
+
...restSso,
|
|
259
|
+
oidc: {
|
|
260
|
+
...oidcApi,
|
|
261
|
+
},
|
|
262
|
+
saml: {
|
|
263
|
+
...samlApi,
|
|
264
|
+
},
|
|
265
|
+
connection: {
|
|
266
|
+
...connectionApi,
|
|
267
|
+
domain: {
|
|
268
|
+
list: domainApi.list,
|
|
269
|
+
validate: domainApi.validate,
|
|
270
|
+
set: setEnterpriseDomains,
|
|
271
|
+
},
|
|
272
|
+
},
|
|
273
|
+
policy: restSso.policy,
|
|
274
|
+
audit: {
|
|
275
|
+
list: auditApi.list,
|
|
276
|
+
},
|
|
277
|
+
webhook: {
|
|
278
|
+
endpoint: webhookApi.endpoint,
|
|
279
|
+
},
|
|
280
|
+
},
|
|
281
|
+
client: {
|
|
282
|
+
signIn: oidcApi.signIn,
|
|
283
|
+
metadata: samlApi.metadata,
|
|
284
|
+
},
|
|
285
|
+
};
|
|
110
286
|
|
|
111
287
|
return {
|
|
112
288
|
signIn: authResult.signIn,
|
|
@@ -120,7 +296,14 @@ export function createAuth<P extends AuthProviderConfig[]>(
|
|
|
120
296
|
member: authResult.auth.member,
|
|
121
297
|
invite: authResult.auth.invite,
|
|
122
298
|
key: authResult.auth.key,
|
|
123
|
-
sso:
|
|
299
|
+
sso: publicSso,
|
|
300
|
+
scim: {
|
|
301
|
+
admin: {
|
|
302
|
+
configure: scimApi.configure,
|
|
303
|
+
get: scimApi.get,
|
|
304
|
+
validate: scimApi.validate,
|
|
305
|
+
},
|
|
306
|
+
},
|
|
124
307
|
http: authResult.auth.http,
|
|
125
308
|
} as ConvexAuthResult<P>;
|
|
126
309
|
}
|
package/src/server/cookies.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { isLocalHost } from "./utils";
|
|
2
2
|
|
|
3
|
+
/** @internal */
|
|
3
4
|
export const SHARED_COOKIE_OPTIONS = {
|
|
4
5
|
httpOnly: true,
|
|
5
6
|
sameSite: "none" as const,
|
|
@@ -9,6 +10,7 @@ export const SHARED_COOKIE_OPTIONS = {
|
|
|
9
10
|
};
|
|
10
11
|
|
|
11
12
|
const REDIRECT_MAX_AGE = 60 * 15; // 15 minutes in seconds
|
|
13
|
+
/** @internal */
|
|
12
14
|
export function redirectToParamCookie(providerId: string, redirectTo: string) {
|
|
13
15
|
return {
|
|
14
16
|
name: redirectToParamCookieName(providerId),
|
|
@@ -17,6 +19,7 @@ export function redirectToParamCookie(providerId: string, redirectTo: string) {
|
|
|
17
19
|
};
|
|
18
20
|
}
|
|
19
21
|
|
|
22
|
+
/** @internal */
|
|
20
23
|
export function useRedirectToParam(
|
|
21
24
|
providerId: string,
|
|
22
25
|
cookies: Record<string, string | undefined>,
|
package/src/server/db.ts
CHANGED
|
@@ -56,10 +56,13 @@ type AuthComponentApiLike = {
|
|
|
56
56
|
};
|
|
57
57
|
};
|
|
58
58
|
|
|
59
|
+
/** @internal */
|
|
59
60
|
export type AuthDbConfig = { component: AuthComponentApiLike };
|
|
60
61
|
|
|
62
|
+
/** @internal */
|
|
61
63
|
export type AuthDb = ReturnType<typeof authDb>;
|
|
62
64
|
|
|
65
|
+
/** @internal */
|
|
63
66
|
export function authDb(ctx: CtxLike, config: AuthDbConfig) {
|
|
64
67
|
const component = config.component;
|
|
65
68
|
return {
|
package/src/server/device.ts
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
import { Fx } from "@robelest/fx";
|
|
14
14
|
|
|
15
15
|
import { AuthError } from "./fx";
|
|
16
|
+
import { userIdFromIdentitySubject } from "./identity";
|
|
16
17
|
import { callSignIn } from "./mutations/index";
|
|
17
18
|
import { DeviceProviderConfig, GenericActionCtxWithAuthConfig } from "./types";
|
|
18
19
|
import {
|
|
@@ -63,6 +64,7 @@ type DeviceResult =
|
|
|
63
64
|
}
|
|
64
65
|
| { kind: "signedIn"; signedIn: SessionInfo | null };
|
|
65
66
|
|
|
67
|
+
/** @internal */
|
|
66
68
|
export const handleDevice = (
|
|
67
69
|
ctx: EnrichedActionCtx,
|
|
68
70
|
provider: DeviceProviderConfig,
|
|
@@ -187,7 +189,7 @@ export const handleDevice = (
|
|
|
187
189
|
);
|
|
188
190
|
}
|
|
189
191
|
|
|
190
|
-
const userId = identity.subject
|
|
192
|
+
const userId = userIdFromIdentitySubject(identity.subject);
|
|
191
193
|
const doc = await queryDeviceByUserCode(ctx, params.userCode);
|
|
192
194
|
if (doc === null) {
|
|
193
195
|
throw new AuthError("DEVICE_INVALID_USER_CODE");
|