@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
|
@@ -64,13 +64,9 @@ async function credentialsSignInInner(ctx, args, getProviderOrThrow, config) {
|
|
|
64
64
|
}
|
|
65
65
|
};
|
|
66
66
|
}
|
|
67
|
-
let hasTotp =
|
|
68
|
-
if (enforceTotp
|
|
69
|
-
|
|
70
|
-
hasTotp = await ctx.runQuery(memberResolveRef, { userId: existingAccount.userId }) !== null;
|
|
71
|
-
await db.users.patch(existingAccount.userId, { hasTotp });
|
|
72
|
-
}
|
|
73
|
-
const totpRequired = enforceTotp && hasTotp === true;
|
|
67
|
+
let hasTotp = false;
|
|
68
|
+
if (enforceTotp) hasTotp = await ctx.runQuery(config.component.factor.totp.get, { verifiedForUserId: existingAccount.userId }) !== null;
|
|
69
|
+
const totpRequired = enforceTotp && hasTotp;
|
|
74
70
|
const [issuance] = await Promise.all([issueSession(ctx, config, {
|
|
75
71
|
userId: existingAccount.userId,
|
|
76
72
|
generateTokens: generateTokens && !totpRequired
|
|
@@ -5,6 +5,7 @@ import { AUTH_STORE_REF } from "./store/refs.js";
|
|
|
5
5
|
import { upsertUserAndAccount } from "../users.js";
|
|
6
6
|
import { getGroup, getGroupConnection } from "../contract.js";
|
|
7
7
|
import { accountExtendValidator, payloadRecordValidator } from "../payloads.js";
|
|
8
|
+
import { vProfileEmail } from "../../component/model.js";
|
|
8
9
|
import { GROUP_OIDC_PROVIDER_PREFIX, GROUP_SAML_PROVIDER_PREFIX, isGroupProviderId } from "../sso/shared.js";
|
|
9
10
|
import { createSyntheticOAuthMaterializedConfig } from "../sso/oidc.js";
|
|
10
11
|
import { normalizeGroupConnectionPolicy, resolveProvisionedRoleIds } from "../sso/policy.js";
|
|
@@ -16,6 +17,7 @@ const userOAuthArgs = v.object({
|
|
|
16
17
|
provider: v.string(),
|
|
17
18
|
providerAccountId: v.string(),
|
|
18
19
|
profile: payloadRecordValidator,
|
|
20
|
+
emails: v.optional(v.array(vProfileEmail)),
|
|
19
21
|
signature: v.string(),
|
|
20
22
|
accountExtend: v.optional(accountExtendValidator)
|
|
21
23
|
});
|
|
@@ -52,17 +54,17 @@ async function jitProvisionMembership(ctx, config, connectionPolicy, connection,
|
|
|
52
54
|
groups: Array.isArray(profile.groups) ? profile.groups : void 0,
|
|
53
55
|
roles: Array.isArray(profile.roles) ? profile.roles : void 0
|
|
54
56
|
});
|
|
55
|
-
const existingMembership = await ctx.runQuery(config.component.
|
|
57
|
+
const existingMembership = await ctx.runQuery(config.component.group.member.get, {
|
|
56
58
|
userId,
|
|
57
59
|
groupId
|
|
58
60
|
});
|
|
59
|
-
if (existingMembership === null) await ctx.runMutation(config.component.
|
|
61
|
+
if (existingMembership === null) await ctx.runMutation(config.component.group.member.create, {
|
|
60
62
|
groupId,
|
|
61
63
|
userId,
|
|
62
64
|
roleIds: provisionedRoleIds,
|
|
63
65
|
status: "active"
|
|
64
66
|
});
|
|
65
|
-
else if (provisionedRoleIds.length > 0) await ctx.runMutation(config.component.
|
|
67
|
+
else if (provisionedRoleIds.length > 0) await ctx.runMutation(config.component.group.member.update, {
|
|
66
68
|
memberId: existingMembership._id,
|
|
67
69
|
data: { roleIds: provisionedRoleIds }
|
|
68
70
|
});
|
|
@@ -75,10 +77,10 @@ async function userOAuthImpl(ctx, args, getProviderOrThrow, config) {
|
|
|
75
77
|
const connectionId = provider.startsWith(GROUP_OIDC_PROVIDER_PREFIX) ? provider.slice(GROUP_OIDC_PROVIDER_PREFIX.length) : provider.startsWith(GROUP_SAML_PROVIDER_PREFIX) ? provider.slice(GROUP_SAML_PROVIDER_PREFIX.length) : null;
|
|
76
78
|
const connectionProtocol = provider.startsWith(GROUP_OIDC_PROVIDER_PREFIX) ? "oidc" : provider.startsWith(GROUP_SAML_PROVIDER_PREFIX) ? "saml" : null;
|
|
77
79
|
const existingAccount = await db.accounts.get(provider, providerAccountId);
|
|
78
|
-
const connection = connectionId !== null ? await getGroupConnection(ctx, config.component.
|
|
79
|
-
const group = connection !== null ? await getGroup(ctx, config.component.
|
|
80
|
+
const connection = connectionId !== null ? await getGroupConnection(ctx, config.component.sso, connectionId) : null;
|
|
81
|
+
const group = connection !== null ? await getGroup(ctx, config.component.group, connection.groupId) : null;
|
|
80
82
|
const connectionPolicy = connection ? normalizeGroupConnectionPolicy(group?.policy) : null;
|
|
81
|
-
const existingScimIdentity = connectionId !== null && existingAccount === null && connectionPolicy?.provisioning.scimReuse.user === "externalId" ? await ctx.runQuery(config.component.
|
|
83
|
+
const existingScimIdentity = connectionId !== null && existingAccount === null && connectionPolicy?.provisioning.scimReuse.user === "externalId" ? await ctx.runQuery(config.component.sso.connection.scim.identity.get, {
|
|
82
84
|
connectionId,
|
|
83
85
|
resourceType: "user",
|
|
84
86
|
externalId: providerAccountId
|
|
@@ -110,6 +112,7 @@ async function userOAuthImpl(ctx, args, getProviderOrThrow, config) {
|
|
|
110
112
|
type: "oauth",
|
|
111
113
|
provider: isGroupProviderId(provider) ? createSyntheticOAuthMaterializedConfig(provider, { accountLinking: connectionProtocol === "oidc" ? connectionPolicy?.identity.accountLinking.oidc : connectionProtocol === "saml" ? connectionPolicy?.identity.accountLinking.saml : void 0 }) : getProviderOrThrow(provider),
|
|
112
114
|
profile: profileForProvisioning,
|
|
115
|
+
emails: args.emails,
|
|
113
116
|
accountExtend: normalizeAccountExtend(provider, providerAccountId, accountExtend)
|
|
114
117
|
}, config, connectionPolicy?.provisioning.user ? {
|
|
115
118
|
existingUserId: existingScimIdentity?.userId,
|
package/dist/server/runtime.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { AuthProfile, SignInParams } from "./payloads.js";
|
|
|
4
4
|
import { HttpAuthContext, HttpAuthContextConfig, OptionalHttpAuthContext } from "./http.js";
|
|
5
5
|
import { createGroupConnectionDomain } from "./sso/domain.js";
|
|
6
6
|
import { GenericId } from "convex/values";
|
|
7
|
-
import * as
|
|
7
|
+
import * as convex_server119 from "convex/server";
|
|
8
8
|
import { GenericActionCtx, GenericDataModel, HttpRouter } from "convex/server";
|
|
9
9
|
|
|
10
10
|
//#region src/server/runtime.d.ts
|
|
@@ -45,26 +45,51 @@ declare function Auth(config_: ConvexAuthConfig): {
|
|
|
45
45
|
cursor?: string | null;
|
|
46
46
|
orderBy?: UserOrderBy;
|
|
47
47
|
order?: "asc" | "desc";
|
|
48
|
-
}) => Promise<
|
|
48
|
+
}) => Promise<{
|
|
49
|
+
items: Doc<"User">[];
|
|
50
|
+
nextCursor: string | null;
|
|
51
|
+
}>;
|
|
49
52
|
viewer: (ctx: ComponentReadCtx & {
|
|
50
|
-
auth:
|
|
53
|
+
auth: convex_server119.Auth;
|
|
51
54
|
}) => Promise<Doc<"User"> | null>;
|
|
55
|
+
email: {
|
|
56
|
+
list: (ctx: ComponentReadCtx & {
|
|
57
|
+
auth: convex_server119.Auth;
|
|
58
|
+
}, opts?: {
|
|
59
|
+
userId?: string;
|
|
60
|
+
}) => Promise<Doc<"UserEmail">[]>;
|
|
61
|
+
add: (ctx: ComponentCtx & {
|
|
62
|
+
auth: convex_server119.Auth;
|
|
63
|
+
}, email: string, opts?: {
|
|
64
|
+
userId?: string;
|
|
65
|
+
}) => Promise<{
|
|
66
|
+
email: string;
|
|
67
|
+
}>;
|
|
68
|
+
remove: (ctx: ComponentCtx & {
|
|
69
|
+
auth: convex_server119.Auth;
|
|
70
|
+
}, email: string, opts?: {
|
|
71
|
+
userId?: string;
|
|
72
|
+
}) => Promise<{
|
|
73
|
+
email: string;
|
|
74
|
+
}>;
|
|
75
|
+
primary: {
|
|
76
|
+
(ctx: ComponentReadCtx & {
|
|
77
|
+
auth: convex_server119.Auth;
|
|
78
|
+
}, opts?: {
|
|
79
|
+
userId?: string;
|
|
80
|
+
}): Promise<Doc<"UserEmail"> | null>;
|
|
81
|
+
(ctx: ComponentCtx & {
|
|
82
|
+
auth: convex_server119.Auth;
|
|
83
|
+
}, email: string, opts?: {
|
|
84
|
+
userId?: string;
|
|
85
|
+
}): Promise<{
|
|
86
|
+
email: string;
|
|
87
|
+
}>;
|
|
88
|
+
};
|
|
89
|
+
};
|
|
52
90
|
update: (ctx: ComponentCtx, userId: string, data: Record<string, unknown>) => Promise<{
|
|
53
91
|
userId: string;
|
|
54
92
|
}>;
|
|
55
|
-
setActiveGroup: (ctx: ComponentCtx, opts: {
|
|
56
|
-
userId: string;
|
|
57
|
-
groupId: string | null;
|
|
58
|
-
}) => Promise<{
|
|
59
|
-
userId: string;
|
|
60
|
-
groupId: null;
|
|
61
|
-
} | {
|
|
62
|
-
userId: string;
|
|
63
|
-
groupId: string;
|
|
64
|
-
}>;
|
|
65
|
-
getActiveGroup: (ctx: ComponentReadCtx, opts: {
|
|
66
|
-
userId: string;
|
|
67
|
-
}) => Promise<string | null>;
|
|
68
93
|
delete: (ctx: ComponentCtx, userId: string, opts?: {
|
|
69
94
|
cascade?: boolean;
|
|
70
95
|
}) => Promise<{
|
|
@@ -79,10 +104,10 @@ declare function Auth(config_: ConvexAuthConfig): {
|
|
|
79
104
|
userId: GenericId<"User">;
|
|
80
105
|
except: GenericId<"Session">[];
|
|
81
106
|
}>;
|
|
82
|
-
get: (ctx: ComponentReadCtx, sessionId: string) => Promise<
|
|
107
|
+
get: (ctx: ComponentReadCtx, sessionId: string) => Promise<Doc<"Session"> | null>;
|
|
83
108
|
list: (ctx: ComponentReadCtx, opts: {
|
|
84
109
|
userId: string;
|
|
85
|
-
}) => Promise<
|
|
110
|
+
}) => Promise<Doc<"Session">[]>;
|
|
86
111
|
};
|
|
87
112
|
account: {
|
|
88
113
|
create: <DataModel extends GenericDataModel>(ctx: GenericActionCtx<DataModel>, args: {
|
|
@@ -130,7 +155,7 @@ declare function Auth(config_: ConvexAuthConfig): {
|
|
|
130
155
|
}>;
|
|
131
156
|
listPasskeys: (ctx: ComponentReadCtx, opts: {
|
|
132
157
|
userId: string;
|
|
133
|
-
}) => Promise<
|
|
158
|
+
}) => Promise<Doc<"Passkey">[]>;
|
|
134
159
|
renamePasskey: (ctx: ComponentCtx, passkeyId: string, name: string) => Promise<{
|
|
135
160
|
passkeyId: string;
|
|
136
161
|
}>;
|
|
@@ -139,7 +164,7 @@ declare function Auth(config_: ConvexAuthConfig): {
|
|
|
139
164
|
}>;
|
|
140
165
|
listTotps: (ctx: ComponentReadCtx, opts: {
|
|
141
166
|
userId: string;
|
|
142
|
-
}) => Promise<
|
|
167
|
+
}) => Promise<Doc<"TotpFactor">[]>;
|
|
143
168
|
deleteTotp: (ctx: ComponentCtx, totpId: string) => Promise<{
|
|
144
169
|
totpId: string;
|
|
145
170
|
}>;
|
|
@@ -170,6 +195,17 @@ declare function Auth(config_: ConvexAuthConfig): {
|
|
|
170
195
|
get: {
|
|
171
196
|
(ctx: ComponentReadCtx, groupId: string): Promise<Doc<"Group"> | null>;
|
|
172
197
|
(ctx: ComponentReadCtx, groupIds: readonly string[]): Promise<Array<Doc<"Group"> | null>>;
|
|
198
|
+
(ctx: ComponentReadCtx, selector: {
|
|
199
|
+
slug: string;
|
|
200
|
+
}): Promise<Doc<"Group"> | null>;
|
|
201
|
+
(ctx: ComponentReadCtx, groupId: string, opts: {
|
|
202
|
+
tree: true;
|
|
203
|
+
}): Promise<{
|
|
204
|
+
current: Doc<"Group">;
|
|
205
|
+
parent: Doc<"Group"> | null;
|
|
206
|
+
children: Array<Doc<"Group">>;
|
|
207
|
+
ancestors: Array<Doc<"Group">>;
|
|
208
|
+
} | null>;
|
|
173
209
|
};
|
|
174
210
|
list: (ctx: ComponentReadCtx, opts?: {
|
|
175
211
|
where?: {
|
|
@@ -191,7 +227,10 @@ declare function Auth(config_: ConvexAuthConfig): {
|
|
|
191
227
|
cursor?: string | null;
|
|
192
228
|
orderBy?: "_creationTime" | "name" | "slug" | "type";
|
|
193
229
|
order?: "asc" | "desc";
|
|
194
|
-
}) => Promise<
|
|
230
|
+
}) => Promise<{
|
|
231
|
+
items: Doc<"Group">[];
|
|
232
|
+
nextCursor: string | null;
|
|
233
|
+
}>;
|
|
195
234
|
update: (ctx: ComponentCtx, groupId: string, data: Record<string, unknown>) => Promise<{
|
|
196
235
|
groupId: string;
|
|
197
236
|
}>;
|
|
@@ -201,13 +240,7 @@ declare function Auth(config_: ConvexAuthConfig): {
|
|
|
201
240
|
ancestors: (ctx: ComponentReadCtx, opts: {
|
|
202
241
|
groupId: string;
|
|
203
242
|
maxDepth?: number;
|
|
204
|
-
includeSelf
|
|
205
|
-
* Action called by the client to invalidate the current session.
|
|
206
|
-
*/?
|
|
207
|
-
/**
|
|
208
|
-
* Action called by the client to invalidate the current session.
|
|
209
|
-
*/
|
|
210
|
-
: boolean;
|
|
243
|
+
includeSelf?: boolean;
|
|
211
244
|
}) => Promise<{
|
|
212
245
|
ancestors: Array<Exclude<Doc<"Group"> | null, null>>;
|
|
213
246
|
cycleDetected: boolean;
|
|
@@ -224,8 +257,8 @@ declare function Auth(config_: ConvexAuthConfig): {
|
|
|
224
257
|
}) => Promise<{
|
|
225
258
|
memberId: string;
|
|
226
259
|
}>;
|
|
227
|
-
get: (ctx: ComponentReadCtx, memberId: string) => Promise<
|
|
228
|
-
list:
|
|
260
|
+
get: (ctx: ComponentReadCtx, memberId: string) => Promise<Doc<"GroupMember"> | null>;
|
|
261
|
+
list: <O extends {
|
|
229
262
|
where?: {
|
|
230
263
|
groupId?: string;
|
|
231
264
|
userId?: string;
|
|
@@ -236,7 +269,33 @@ declare function Auth(config_: ConvexAuthConfig): {
|
|
|
236
269
|
cursor?: string | null;
|
|
237
270
|
orderBy?: "_creationTime" | "status";
|
|
238
271
|
order?: "asc" | "desc";
|
|
239
|
-
|
|
272
|
+
withGroup?: true;
|
|
273
|
+
withGrants?: true;
|
|
274
|
+
} | undefined = undefined>(ctx: ComponentReadCtx, opts?: O) => Promise<{
|
|
275
|
+
items: ({
|
|
276
|
+
_id: GenericId<"GroupMember">;
|
|
277
|
+
_creationTime: number;
|
|
278
|
+
extend?: any;
|
|
279
|
+
role?: string | undefined;
|
|
280
|
+
roleIds?: string[] | undefined;
|
|
281
|
+
status?: string | undefined;
|
|
282
|
+
groupId: GenericId<"Group">;
|
|
283
|
+
userId: GenericId<"User">;
|
|
284
|
+
} & {
|
|
285
|
+
_id: GenericId<"GroupMember">;
|
|
286
|
+
_creationTime: number;
|
|
287
|
+
} & (NonNullable<O> extends infer T_2 ? T_2 extends NonNullable<O> ? T_2 extends {
|
|
288
|
+
withGroup: true;
|
|
289
|
+
} ? {
|
|
290
|
+
group: Doc<"Group"> | null;
|
|
291
|
+
} : unknown : never : never) & (NonNullable<O> extends infer T_3 ? T_3 extends NonNullable<O> ? T_3 extends {
|
|
292
|
+
withGrants: true;
|
|
293
|
+
} ? {
|
|
294
|
+
roleIds: string[];
|
|
295
|
+
grants: string[];
|
|
296
|
+
} : unknown : never : never))[];
|
|
297
|
+
nextCursor: string | null;
|
|
298
|
+
}>;
|
|
240
299
|
delete: (ctx: ComponentCtx, memberId: string) => Promise<{
|
|
241
300
|
memberId: string;
|
|
242
301
|
}>;
|
|
@@ -315,13 +374,19 @@ declare function Auth(config_: ConvexAuthConfig): {
|
|
|
315
374
|
inviteId: string;
|
|
316
375
|
token: string;
|
|
317
376
|
}>;
|
|
318
|
-
get: (ctx: ComponentReadCtx, inviteId: string) => Promise<
|
|
377
|
+
get: (ctx: ComponentReadCtx, inviteId: string) => Promise<Doc<"GroupInvite"> | null>;
|
|
319
378
|
token: {
|
|
320
|
-
get: (ctx: ComponentReadCtx, token: string) => Promise<
|
|
379
|
+
get: (ctx: ComponentReadCtx, token: string) => Promise<Doc<"GroupInvite"> | null>;
|
|
321
380
|
accept: (ctx: ComponentCtx, args: {
|
|
322
381
|
token: string;
|
|
323
382
|
acceptedByUserId: string;
|
|
324
|
-
}) => Promise<
|
|
383
|
+
}) => Promise<{
|
|
384
|
+
inviteId: string;
|
|
385
|
+
groupId: string | null;
|
|
386
|
+
memberId?: string;
|
|
387
|
+
inviteStatus: string;
|
|
388
|
+
membershipStatus: string;
|
|
389
|
+
}>;
|
|
325
390
|
};
|
|
326
391
|
list: (ctx: ComponentReadCtx, opts?: {
|
|
327
392
|
where?: {
|
|
@@ -337,7 +402,10 @@ declare function Auth(config_: ConvexAuthConfig): {
|
|
|
337
402
|
cursor?: string | null;
|
|
338
403
|
orderBy?: "_creationTime" | "status" | "email" | "expiresTime" | "acceptedTime";
|
|
339
404
|
order?: "asc" | "desc";
|
|
340
|
-
}) => Promise<
|
|
405
|
+
}) => Promise<{
|
|
406
|
+
items: Doc<"GroupInvite">[];
|
|
407
|
+
nextCursor: string | null;
|
|
408
|
+
}>;
|
|
341
409
|
accept: (ctx: ComponentCtx, inviteId: string, acceptedByUserId?: string) => Promise<{
|
|
342
410
|
inviteId: string;
|
|
343
411
|
acceptedByUserId: string | null;
|
|
@@ -377,7 +445,10 @@ declare function Auth(config_: ConvexAuthConfig): {
|
|
|
377
445
|
cursor?: string | null;
|
|
378
446
|
orderBy?: "_creationTime" | "name" | "lastUsedAt" | "expiresAt" | "revoked";
|
|
379
447
|
order?: "asc" | "desc";
|
|
380
|
-
}) => Promise<
|
|
448
|
+
}) => Promise<{
|
|
449
|
+
items: Doc<"ApiKey">[];
|
|
450
|
+
nextCursor: string | null;
|
|
451
|
+
}>;
|
|
381
452
|
get: (ctx: ComponentReadCtx, keyId: string) => Promise<KeyDoc | null>;
|
|
382
453
|
update: (ctx: ComponentCtx, keyId: string, data: {
|
|
383
454
|
name?: string;
|
|
@@ -403,6 +474,31 @@ declare function Auth(config_: ConvexAuthConfig): {
|
|
|
403
474
|
secret: string;
|
|
404
475
|
}>;
|
|
405
476
|
};
|
|
477
|
+
active: {
|
|
478
|
+
get: (ctx: ComponentReadCtx & {
|
|
479
|
+
auth: convex_server119.Auth;
|
|
480
|
+
}, opts?: {
|
|
481
|
+
userId?: string;
|
|
482
|
+
}) => Promise<{
|
|
483
|
+
groupId: string;
|
|
484
|
+
group: Doc<"Group"> | null;
|
|
485
|
+
membership: Doc<"GroupMember">;
|
|
486
|
+
} | null>;
|
|
487
|
+
set: (ctx: ComponentCtx & {
|
|
488
|
+
auth: convex_server119.Auth;
|
|
489
|
+
}, groupId: string, opts?: {
|
|
490
|
+
userId?: string;
|
|
491
|
+
}) => Promise<{
|
|
492
|
+
groupId: string;
|
|
493
|
+
}>;
|
|
494
|
+
clear: (ctx: ComponentCtx & {
|
|
495
|
+
auth: convex_server119.Auth;
|
|
496
|
+
}, opts?: {
|
|
497
|
+
userId?: string;
|
|
498
|
+
}) => Promise<{
|
|
499
|
+
groupId: null;
|
|
500
|
+
}>;
|
|
501
|
+
};
|
|
406
502
|
} & {
|
|
407
503
|
sso: ReturnType<typeof createGroupConnectionDomain>;
|
|
408
504
|
} & {
|
|
@@ -476,22 +572,22 @@ declare function Auth(config_: ConvexAuthConfig): {
|
|
|
476
572
|
context: {
|
|
477
573
|
<TResolve extends Record<string, unknown> = Record<string, never>, TCtx extends {
|
|
478
574
|
auth: {
|
|
479
|
-
getUserIdentity: () => Promise<
|
|
575
|
+
getUserIdentity: () => Promise<convex_server119.UserIdentity | null>;
|
|
480
576
|
};
|
|
481
577
|
} & ComponentReadCtx = {
|
|
482
578
|
auth: {
|
|
483
|
-
getUserIdentity: () => Promise<
|
|
579
|
+
getUserIdentity: () => Promise<convex_server119.UserIdentity | null>;
|
|
484
580
|
};
|
|
485
581
|
} & ComponentReadCtx>(ctx: TCtx, request: Request, config: HttpAuthContextConfig<TResolve, TCtx> & {
|
|
486
582
|
optional: true;
|
|
487
583
|
}): Promise<OptionalHttpAuthContext & TResolve>;
|
|
488
584
|
<TResolve extends Record<string, unknown> = Record<string, never>, TCtx extends {
|
|
489
585
|
auth: {
|
|
490
|
-
getUserIdentity: () => Promise<
|
|
586
|
+
getUserIdentity: () => Promise<convex_server119.UserIdentity | null>;
|
|
491
587
|
};
|
|
492
588
|
} & ComponentReadCtx = {
|
|
493
589
|
auth: {
|
|
494
|
-
getUserIdentity: () => Promise<
|
|
590
|
+
getUserIdentity: () => Promise<convex_server119.UserIdentity | null>;
|
|
495
591
|
};
|
|
496
592
|
} & ComponentReadCtx>(ctx: TCtx, request: Request, config?: HttpAuthContextConfig<TResolve, TCtx>): Promise<HttpAuthContext & TResolve>;
|
|
497
593
|
};
|
|
@@ -525,7 +621,7 @@ declare function Auth(config_: ConvexAuthConfig): {
|
|
|
525
621
|
action: string;
|
|
526
622
|
};
|
|
527
623
|
cors?: CorsConfig;
|
|
528
|
-
}) =>
|
|
624
|
+
}) => convex_server119.PublicHttpAction;
|
|
529
625
|
/**
|
|
530
626
|
* Register a Bearer-authenticated route **and** its OPTIONS preflight
|
|
531
627
|
* in a single call.
|
|
@@ -571,7 +667,7 @@ declare function Auth(config_: ConvexAuthConfig): {
|
|
|
571
667
|
*
|
|
572
668
|
* Also used for refreshing the session.
|
|
573
669
|
*/
|
|
574
|
-
signIn:
|
|
670
|
+
signIn: convex_server119.RegisteredAction<"public", {
|
|
575
671
|
provider?: string | undefined;
|
|
576
672
|
verifier?: string | undefined;
|
|
577
673
|
params?: Record<string, string | number | boolean | (string | number | boolean | null)[] | Record<string, string | number | boolean | (string | number | boolean | null)[] | null> | null> | undefined;
|
|
@@ -581,12 +677,12 @@ declare function Auth(config_: ConvexAuthConfig): {
|
|
|
581
677
|
/**
|
|
582
678
|
* Action called by the client to invalidate the current session.
|
|
583
679
|
*/
|
|
584
|
-
signOut:
|
|
680
|
+
signOut: convex_server119.RegisteredAction<"public", {}, Promise<void>>;
|
|
585
681
|
/**
|
|
586
682
|
* Internal mutation used by the library to read and write
|
|
587
683
|
* to the database during signin and signout.
|
|
588
684
|
*/
|
|
589
|
-
store:
|
|
685
|
+
store: convex_server119.RegisteredMutation<"internal", {
|
|
590
686
|
args: {
|
|
591
687
|
sessionId?: string | undefined;
|
|
592
688
|
type: "signIn";
|
|
@@ -609,9 +705,14 @@ declare function Auth(config_: ConvexAuthConfig): {
|
|
|
609
705
|
type: "verifier";
|
|
610
706
|
} | {
|
|
611
707
|
type: "verifierSignature";
|
|
612
|
-
verifier: string;
|
|
613
708
|
signature: string;
|
|
709
|
+
verifier: string;
|
|
614
710
|
} | {
|
|
711
|
+
emails?: {
|
|
712
|
+
primary?: boolean | undefined;
|
|
713
|
+
verified?: boolean | undefined;
|
|
714
|
+
email: string;
|
|
715
|
+
}[] | undefined;
|
|
615
716
|
accountExtend?: {
|
|
616
717
|
identity?: {
|
|
617
718
|
type?: string | undefined;
|
|
@@ -639,8 +740,8 @@ declare function Auth(config_: ConvexAuthConfig): {
|
|
|
639
740
|
phone?: string | undefined;
|
|
640
741
|
accountId?: string | undefined;
|
|
641
742
|
type: "createVerificationCode";
|
|
642
|
-
expirationTime: number;
|
|
643
743
|
provider: string;
|
|
744
|
+
expirationTime: number;
|
|
644
745
|
code: string;
|
|
645
746
|
allowExtraProviders: boolean;
|
|
646
747
|
} | {
|
package/dist/server/runtime.js
CHANGED
|
@@ -244,13 +244,14 @@ function Auth(config_) {
|
|
|
244
244
|
try {
|
|
245
245
|
const result = await handleOAuthCallback(providerId, provider, Object.fromEntries(params.entries()), cookies);
|
|
246
246
|
const oauthCookies = result.cookies;
|
|
247
|
-
const { id: profileId, ...profileData } = result.profile;
|
|
247
|
+
const { id: profileId, emails: profileEmails, ...profileData } = result.profile;
|
|
248
248
|
const { signature } = result;
|
|
249
249
|
const { redirectTo: stateRedirectTo } = decodeOAuthState(params.get("state") ?? "");
|
|
250
250
|
const redirUrl = setURLSearchParam(await redirectAbsoluteUrl(ctx, config, { redirectTo: stateRedirectTo ?? void 0 }), "code", await callUserOAuth(ctx, {
|
|
251
251
|
provider: providerId,
|
|
252
252
|
providerAccountId: profileId,
|
|
253
253
|
profile: profileData,
|
|
254
|
+
emails: profileEmails,
|
|
254
255
|
signature
|
|
255
256
|
}));
|
|
256
257
|
const redirHeaders = new Headers({ Location: redirUrl });
|
|
@@ -351,13 +352,14 @@ function Auth(config_) {
|
|
|
351
352
|
try {
|
|
352
353
|
const result = await handleOAuthCallback(providerId, provider, Object.fromEntries(params.entries()), cookies);
|
|
353
354
|
const oauthCookies = result.cookies;
|
|
354
|
-
const { id: profileId, ...profileData } = result.profile;
|
|
355
|
+
const { id: profileId, emails: profileEmails, ...profileData } = result.profile;
|
|
355
356
|
const { signature } = result;
|
|
356
357
|
const { redirectTo: stateRedirectTo } = decodeOAuthState(params.get("state") ?? "");
|
|
357
358
|
const redirUrl = setURLSearchParam(await redirectAbsoluteUrl(ctx, config, { redirectTo: stateRedirectTo ?? void 0 }), "code", await callUserOAuth(ctx, {
|
|
358
359
|
provider: providerId,
|
|
359
360
|
providerAccountId: profileId,
|
|
360
361
|
profile: profileData,
|
|
362
|
+
emails: profileEmails,
|
|
361
363
|
signature
|
|
362
364
|
}));
|
|
363
365
|
const redirHeaders = new Headers({ Location: redirUrl });
|
|
@@ -414,12 +416,12 @@ function Auth(config_) {
|
|
|
414
416
|
});
|
|
415
417
|
const http = Object.assign((options) => request.router(options), httpDelegate);
|
|
416
418
|
const accountUnlink = async (ctx, args) => {
|
|
417
|
-
const accountDoc = await ctx.runQuery(config.component.
|
|
419
|
+
const accountDoc = await ctx.runQuery(config.component.account.get, { id: args.accountId });
|
|
418
420
|
if (accountDoc === null) throw convexError({
|
|
419
421
|
code: "ACCOUNT_NOT_FOUND",
|
|
420
422
|
message: "Account not found."
|
|
421
423
|
});
|
|
422
|
-
await ctx.runMutation(config.component.
|
|
424
|
+
await ctx.runMutation(config.component.account.delete, { accountId: args.accountId });
|
|
423
425
|
const userId = accountDoc.userId;
|
|
424
426
|
const provider = accountDoc.provider;
|
|
425
427
|
await config.callbacks?.after?.(ctx, {
|
|
@@ -435,12 +437,12 @@ function Auth(config_) {
|
|
|
435
437
|
};
|
|
436
438
|
};
|
|
437
439
|
const passkeyDelete = async (ctx, args) => {
|
|
438
|
-
const passkeyDoc = await ctx.runQuery(config.component.
|
|
440
|
+
const passkeyDoc = await ctx.runQuery(config.component.factor.passkey.get, { id: args.passkeyId });
|
|
439
441
|
if (passkeyDoc === null) throw convexError({
|
|
440
442
|
code: "PASSKEY_NOT_FOUND",
|
|
441
443
|
message: "Passkey not found."
|
|
442
444
|
});
|
|
443
|
-
await ctx.runMutation(config.component.
|
|
445
|
+
await ctx.runMutation(config.component.factor.passkey.delete, { passkeyId: args.passkeyId });
|
|
444
446
|
const userId = passkeyDoc.userId;
|
|
445
447
|
await config.callbacks?.after?.(ctx, {
|
|
446
448
|
kind: "passkeyRemoved",
|
|
@@ -453,12 +455,12 @@ function Auth(config_) {
|
|
|
453
455
|
};
|
|
454
456
|
};
|
|
455
457
|
const totpDelete = async (ctx, args) => {
|
|
456
|
-
const totpDoc = await ctx.runQuery(config.component.
|
|
458
|
+
const totpDoc = await ctx.runQuery(config.component.factor.totp.get, { id: args.totpId });
|
|
457
459
|
if (totpDoc === null) throw convexError({
|
|
458
460
|
code: "TOTP_NOT_FOUND",
|
|
459
461
|
message: "TOTP factor not found."
|
|
460
462
|
});
|
|
461
|
-
await ctx.runMutation(config.component.
|
|
463
|
+
await ctx.runMutation(config.component.factor.totp.delete, { totpId: args.totpId });
|
|
462
464
|
const userId = totpDoc.userId;
|
|
463
465
|
await config.callbacks?.after?.(ctx, {
|
|
464
466
|
kind: "totpRemoved",
|
|
@@ -12,7 +12,7 @@ function createGroupService(deps) {
|
|
|
12
12
|
const connectionNotFoundError = "Connection not found.";
|
|
13
13
|
const getPolicyFromGroup = (group) => normalizeGroupConnectionPolicy(group.policy);
|
|
14
14
|
const getGroupConnectionSecret$1 = async (ctx, connectionId, kind) => {
|
|
15
|
-
return await getGroupConnectionSecret(ctx, config.component.
|
|
15
|
+
return await getGroupConnectionSecret(ctx, config.component.sso, {
|
|
16
16
|
connectionId,
|
|
17
17
|
kind
|
|
18
18
|
});
|
|
@@ -24,7 +24,7 @@ function createGroupService(deps) {
|
|
|
24
24
|
* merge, so doing them sequentially was costing 30–60ms per OIDC lookup.
|
|
25
25
|
*/
|
|
26
26
|
const resolveOidcConfigWithSecret = async (ctx, connectionId, preloadedConnection) => {
|
|
27
|
-
const [connection, secret] = await Promise.all([preloadedConnection !== void 0 ? Promise.resolve(preloadedConnection) : getGroupConnection(ctx, config.component.
|
|
27
|
+
const [connection, secret] = await Promise.all([preloadedConnection !== void 0 ? Promise.resolve(preloadedConnection) : getGroupConnection(ctx, config.component.sso, connectionId), getGroupConnectionSecret$1(ctx, connectionId, "oidc_client_secret")]);
|
|
28
28
|
if (!connection) throw convexError({
|
|
29
29
|
code: "INVALID_PARAMETERS",
|
|
30
30
|
message: connectionNotFoundError
|
|
@@ -42,7 +42,7 @@ function createGroupService(deps) {
|
|
|
42
42
|
};
|
|
43
43
|
};
|
|
44
44
|
const loadGroupPolicyOrThrow = async (ctx, groupId) => {
|
|
45
|
-
const group = await getGroup(ctx, config.component.
|
|
45
|
+
const group = await getGroup(ctx, config.component.group, groupId);
|
|
46
46
|
if (!group) throw convexError({
|
|
47
47
|
code: "INVALID_PARAMETERS",
|
|
48
48
|
message: "Group not found."
|
|
@@ -50,7 +50,7 @@ function createGroupService(deps) {
|
|
|
50
50
|
return getPolicyFromGroup(group);
|
|
51
51
|
};
|
|
52
52
|
const loadConnectionOrThrow = async (ctx, connectionId) => {
|
|
53
|
-
const connection = await getGroupConnection(ctx, config.component.
|
|
53
|
+
const connection = await getGroupConnection(ctx, config.component.sso, connectionId);
|
|
54
54
|
if (!connection) throw convexError({
|
|
55
55
|
code: "INVALID_PARAMETERS",
|
|
56
56
|
message: connectionNotFoundError
|
|
@@ -143,17 +143,17 @@ function createGroupService(deps) {
|
|
|
143
143
|
};
|
|
144
144
|
const recordGroupAuditEvent = async (ctx, data) => {
|
|
145
145
|
const { ok, ...rest } = data;
|
|
146
|
-
return await ctx.runMutation(config.component.
|
|
146
|
+
return await ctx.runMutation(config.component.sso.audit.create, {
|
|
147
147
|
...rest,
|
|
148
148
|
status: ok ? "success" : "failure",
|
|
149
149
|
occurredAt: Date.now()
|
|
150
150
|
});
|
|
151
151
|
};
|
|
152
152
|
const emitGroupWebhookDeliveries = async (ctx, data) => {
|
|
153
|
-
const endpoints = await listWebhookEndpoints(ctx, config.component.
|
|
153
|
+
const endpoints = await listWebhookEndpoints(ctx, config.component.sso, data.connectionId);
|
|
154
154
|
for (const endpoint of endpoints) {
|
|
155
155
|
if (endpoint.status !== "active" || !endpoint.subscriptions.includes(data.eventType)) continue;
|
|
156
|
-
await ctx.runMutation(config.component.
|
|
156
|
+
await ctx.runMutation(config.component.sso.webhook.delivery.create, {
|
|
157
157
|
connectionId: data.connectionId,
|
|
158
158
|
endpointId: endpoint._id,
|
|
159
159
|
auditEventId: data.auditEventId,
|
|
@@ -171,13 +171,13 @@ function createGroupService(deps) {
|
|
|
171
171
|
});
|
|
172
172
|
const token = authHeader.slice(7);
|
|
173
173
|
const parsedPath = parseScimPath(new URL(request.url).pathname);
|
|
174
|
-
const scimConfig = await getScimConfigByConnection(ctx, config.component.
|
|
174
|
+
const scimConfig = await getScimConfigByConnection(ctx, config.component.sso, parsedPath.connectionId);
|
|
175
175
|
const tokenHash = await sha256(token);
|
|
176
176
|
if (!scimConfig || scimConfig.status !== "active" || !scimConfig.tokenHash || !constantTimeEqualHex(tokenHash, scimConfig.tokenHash)) throw convexError({
|
|
177
177
|
code: "INVALID_API_KEY",
|
|
178
178
|
message: "Invalid SCIM token."
|
|
179
179
|
});
|
|
180
|
-
const connection = await getGroupConnection(ctx, config.component.
|
|
180
|
+
const connection = await getGroupConnection(ctx, config.component.sso, scimConfig.connectionId);
|
|
181
181
|
if (connection === null) throw convexError({
|
|
182
182
|
code: "INVALID_PARAMETERS",
|
|
183
183
|
message: connectionNotFoundError
|
|
@@ -448,7 +448,7 @@ declare function createGroupConnectionDomain<TDeps extends DomainDeps>(deps: TDe
|
|
|
448
448
|
loginHint?: string;
|
|
449
449
|
}) => Promise<{
|
|
450
450
|
connectionId: string;
|
|
451
|
-
protocol: "
|
|
451
|
+
protocol: "saml" | "oidc";
|
|
452
452
|
providerId: string;
|
|
453
453
|
signInPath: string;
|
|
454
454
|
callbackPath: string;
|