@robelest/convex-auth 0.0.4-preview.30 → 0.0.4-preview.32

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.
Files changed (104) hide show
  1. package/dist/bin.js +125 -36
  2. package/dist/browser/index.d.ts +3 -13
  3. package/dist/browser/index.js +47 -12
  4. package/dist/browser/navigation.js +1 -1
  5. package/dist/browser/passkey.js +7 -7
  6. package/dist/browser/runtime.js +13 -15
  7. package/dist/client/core/types.d.ts +179 -63
  8. package/dist/client/core/types.js +6 -0
  9. package/dist/client/factors/totp.js +1 -1
  10. package/dist/client/index.d.ts +5 -4
  11. package/dist/client/index.js +115 -56
  12. package/dist/client/runtime/mutex.js +3 -2
  13. package/dist/component/_generated/component.d.ts +40 -0
  14. package/dist/component/http.js +9 -0
  15. package/dist/component/index.d.ts +1 -1
  16. package/dist/component/model.d.ts +27 -27
  17. package/dist/component/model.js +2 -1
  18. package/dist/component/modules.js +1 -0
  19. package/dist/component/public/factors/passkeys.js +31 -1
  20. package/dist/component/public/identity/codes.js +1 -1
  21. package/dist/component/public/identity/tokens.js +2 -1
  22. package/dist/component/public/identity/verifiers.js +15 -5
  23. package/dist/component/public.js +2 -2
  24. package/dist/component/schema.d.ts +287 -285
  25. package/dist/component/schema.js +2 -1
  26. package/dist/core/index.d.ts +8 -3
  27. package/dist/core/index.js +7 -2
  28. package/dist/expo/index.d.ts +21 -0
  29. package/dist/expo/index.js +148 -0
  30. package/dist/expo/passkey.js +174 -0
  31. package/dist/providers/apple.d.ts +1 -1
  32. package/dist/providers/apple.js +6 -8
  33. package/dist/providers/custom.d.ts +1 -1
  34. package/dist/providers/custom.js +4 -7
  35. package/dist/providers/github.d.ts +1 -1
  36. package/dist/providers/github.js +5 -8
  37. package/dist/providers/google.d.ts +1 -1
  38. package/dist/providers/google.js +5 -8
  39. package/dist/providers/microsoft.d.ts +1 -1
  40. package/dist/providers/microsoft.js +5 -9
  41. package/dist/providers/password.d.ts +18 -37
  42. package/dist/providers/password.js +170 -115
  43. package/dist/providers/redirect.d.ts +1 -0
  44. package/dist/providers/redirect.js +20 -0
  45. package/dist/server/auth.d.ts +6 -7
  46. package/dist/server/auth.js +3 -2
  47. package/dist/server/{ctxCache.js → cache/context.js} +2 -2
  48. package/dist/server/{componentContext.d.ts → component/context.d.ts} +2 -2
  49. package/dist/server/context.js +3 -10
  50. package/dist/server/contract.d.ts +2 -87
  51. package/dist/server/contract.js +1 -1
  52. package/dist/server/cookies.js +25 -1
  53. package/dist/server/core.js +1 -1
  54. package/dist/server/errors.js +24 -1
  55. package/dist/server/{auth-context.d.ts → facade.d.ts} +3 -45
  56. package/dist/server/{auth-context.js → facade.js} +11 -12
  57. package/dist/server/http.d.ts +7 -7
  58. package/dist/server/http.js +47 -7
  59. package/dist/server/{convexIdentity.d.ts → identity/convex.d.ts} +3 -3
  60. package/dist/server/index.d.ts +5 -3
  61. package/dist/server/index.js +3 -2
  62. package/dist/server/mounts.d.ts +171 -18
  63. package/dist/server/mutations/code.js +7 -1
  64. package/dist/server/mutations/{credentialsSignIn.js → credentials/signin.js} +10 -10
  65. package/dist/server/mutations/index.js +1 -1
  66. package/dist/server/mutations/invalidate.js +11 -1
  67. package/dist/server/mutations/oauth.js +25 -27
  68. package/dist/server/mutations/signin.js +6 -0
  69. package/dist/server/mutations/signout.js +5 -0
  70. package/dist/server/mutations/store.js +1 -1
  71. package/dist/server/oauth/factory.js +11 -3
  72. package/dist/server/passkey.js +126 -110
  73. package/dist/server/prefetch.js +8 -1
  74. package/dist/server/redirects.js +11 -3
  75. package/dist/server/refresh.js +6 -1
  76. package/dist/server/runtime.d.ts +68 -37
  77. package/dist/server/runtime.js +318 -36
  78. package/dist/server/services/group.js +4 -0
  79. package/dist/server/sessions.js +1 -0
  80. package/dist/server/signin.js +8 -6
  81. package/dist/server/sso/domain.d.ts +159 -16
  82. package/dist/server/sso/domain.js +1 -1
  83. package/dist/server/sso/http.js +144 -60
  84. package/dist/server/sso/oidc.js +28 -12
  85. package/dist/server/sso/policy.js +30 -14
  86. package/dist/server/sso/provision.js +1 -1
  87. package/dist/server/sso/saml.js +18 -9
  88. package/dist/server/sso/scim.js +12 -4
  89. package/dist/server/sso/shared.js +5 -5
  90. package/dist/server/telemetry.js +3 -0
  91. package/dist/server/tokens.js +10 -2
  92. package/dist/server/totp.js +127 -100
  93. package/dist/server/types.d.ts +224 -151
  94. package/dist/server/url.js +1 -1
  95. package/dist/server/users.js +93 -53
  96. package/dist/server/wellknown.d.ts +75 -0
  97. package/dist/server/wellknown.js +198 -0
  98. package/dist/shared/errors.js +0 -1
  99. package/package.json +36 -4
  100. package/dist/server/oauth/index.js +0 -12
  101. package/dist/server/utils/dispatch.js +0 -36
  102. package/dist/shared/authResults.d.ts +0 -16
  103. /package/dist/server/{componentContext.js → component/context.js} +0 -0
  104. /package/dist/server/{convexIdentity.js → identity/convex.js} +0 -0
@@ -1,5 +1,4 @@
1
- import { AuthAuthorizationConfig, GroupConnectionDeprovisionMode, GroupConnectionPolicy } from "./types.js";
2
- import { AuditEventRecord, ConnectionDomainRecord, GroupConnectionDomainLookupRecord, GroupConnectionListResult, GroupConnectionRecord, ScimConfigRecord } from "./contract.js";
1
+ import { AuthAuthorizationConfig, GroupConnectionPolicy } from "./types.js";
3
2
  import { AuthApi } from "./auth.js";
4
3
  import * as convex_server6 from "convex/server";
5
4
 
@@ -227,10 +226,41 @@ declare function sso<TAuthorization extends AuthAuthorizationConfig | undefined
227
226
  }>>;
228
227
  get: convex_server6.RegisteredQuery<"public", {
229
228
  connectionId: string;
230
- }, Promise<GroupConnectionRecord | null>>;
229
+ }, Promise<{
230
+ _id: string;
231
+ _creationTime: number;
232
+ groupId: string;
233
+ slug?: string;
234
+ name?: string;
235
+ protocol: "oidc" | "saml";
236
+ status: "draft" | "active" | "disabled";
237
+ config?: unknown;
238
+ extend?: unknown;
239
+ } | null>>;
231
240
  getByDomain: convex_server6.RegisteredQuery<"public", {
232
241
  domain: string;
233
- }, Promise<GroupConnectionDomainLookupRecord | null>>;
242
+ }, Promise<{
243
+ connection: {
244
+ _id: string;
245
+ _creationTime: number;
246
+ groupId: string;
247
+ slug?: string;
248
+ name?: string;
249
+ protocol: "oidc" | "saml";
250
+ status: "draft" | "active" | "disabled";
251
+ config?: unknown;
252
+ extend?: unknown;
253
+ } | null;
254
+ domain: {
255
+ _id: string;
256
+ _creationTime: number;
257
+ connectionId: string;
258
+ groupId: string;
259
+ domain: string;
260
+ isPrimary: boolean;
261
+ verifiedAt?: number;
262
+ } | null;
263
+ } | null>>;
234
264
  list: convex_server6.RegisteredQuery<"public", {
235
265
  limit?: number | undefined;
236
266
  where?: {
@@ -241,7 +271,20 @@ declare function sso<TAuthorization extends AuthAuthorizationConfig | undefined
241
271
  cursor?: string | null | undefined;
242
272
  orderBy?: string | undefined;
243
273
  order?: "asc" | "desc" | undefined;
244
- }, Promise<GroupConnectionListResult>>;
274
+ }, Promise<{
275
+ items: {
276
+ _id: string;
277
+ _creationTime: number;
278
+ groupId: string;
279
+ slug?: string;
280
+ name?: string;
281
+ protocol: "oidc" | "saml";
282
+ status: "draft" | "active" | "disabled";
283
+ config?: unknown;
284
+ extend?: unknown;
285
+ }[];
286
+ nextCursor: string | null;
287
+ }>>;
245
288
  update: convex_server6.RegisteredMutation<"public", {
246
289
  connectionId: string;
247
290
  data: {
@@ -280,14 +323,22 @@ declare function sso<TAuthorization extends AuthAuthorizationConfig | undefined
280
323
  configured: boolean;
281
324
  ready: boolean;
282
325
  basePath: string | null;
283
- deprovisionMode: GroupConnectionDeprovisionMode;
326
+ deprovisionMode: "soft" | "hard";
284
327
  };
285
328
  };
286
329
  }>>;
287
330
  domain: {
288
331
  list: convex_server6.RegisteredQuery<"public", {
289
332
  connectionId: string;
290
- }, Promise<ConnectionDomainRecord[]>>;
333
+ }, Promise<{
334
+ _id: string;
335
+ _creationTime: number;
336
+ connectionId: string;
337
+ groupId: string;
338
+ domain: string;
339
+ isPrimary: boolean;
340
+ verifiedAt?: number;
341
+ }[]>>;
291
342
  status: convex_server6.RegisteredQuery<"public", {
292
343
  connectionId: string;
293
344
  }, Promise<{
@@ -610,7 +661,22 @@ declare function sso<TAuthorization extends AuthAuthorizationConfig | undefined
610
661
  groupId?: string | undefined;
611
662
  connectionId?: string | undefined;
612
663
  limit?: number | undefined;
613
- }, Promise<AuditEventRecord[]>>;
664
+ }, Promise<{
665
+ _id: string;
666
+ _creationTime: number;
667
+ connectionId?: string;
668
+ groupId: string;
669
+ eventType: string;
670
+ actorType: string;
671
+ actorId?: string;
672
+ subjectType: string;
673
+ subjectId?: string;
674
+ status: string;
675
+ occurredAt: number;
676
+ requestId?: string;
677
+ ip?: string;
678
+ metadata?: Record<string, unknown>;
679
+ }[]>>;
614
680
  };
615
681
  webhook: {
616
682
  delivery: {
@@ -769,7 +835,17 @@ declare function scim<TAuthorization extends AuthAuthorizationConfig | undefined
769
835
  connectionId: string;
770
836
  configured: boolean;
771
837
  ready: boolean;
772
- config: ScimConfigRecord | null;
838
+ config: {
839
+ _id: string;
840
+ _creationTime: number;
841
+ connectionId: string;
842
+ groupId: string;
843
+ status: string;
844
+ basePath: string;
845
+ tokenHash: string;
846
+ lastRotatedAt?: number;
847
+ extend?: unknown;
848
+ } | null;
773
849
  checks: {
774
850
  name: string;
775
851
  ok: boolean;
@@ -806,7 +882,7 @@ declare function scim<TAuthorization extends AuthAuthorizationConfig | undefined
806
882
  ok: boolean;
807
883
  connectionId: string;
808
884
  basePath: string;
809
- deprovisionMode: GroupConnectionDeprovisionMode;
885
+ deprovisionMode: "soft" | "hard";
810
886
  capabilities: {
811
887
  users: boolean;
812
888
  groups: boolean;
@@ -876,10 +952,41 @@ declare function createAuthGroupSso<TAuthorization extends AuthAuthorizationConf
876
952
  }>>;
877
953
  getConnection: convex_server6.RegisteredQuery<"public", {
878
954
  connectionId: string;
879
- }, Promise<GroupConnectionRecord | null>>;
955
+ }, Promise<{
956
+ _id: string;
957
+ _creationTime: number;
958
+ groupId: string;
959
+ slug?: string;
960
+ name?: string;
961
+ protocol: "oidc" | "saml";
962
+ status: "draft" | "active" | "disabled";
963
+ config?: unknown;
964
+ extend?: unknown;
965
+ } | null>>;
880
966
  getConnectionByDomain: convex_server6.RegisteredQuery<"public", {
881
967
  domain: string;
882
- }, Promise<GroupConnectionDomainLookupRecord | null>>;
968
+ }, Promise<{
969
+ connection: {
970
+ _id: string;
971
+ _creationTime: number;
972
+ groupId: string;
973
+ slug?: string;
974
+ name?: string;
975
+ protocol: "oidc" | "saml";
976
+ status: "draft" | "active" | "disabled";
977
+ config?: unknown;
978
+ extend?: unknown;
979
+ } | null;
980
+ domain: {
981
+ _id: string;
982
+ _creationTime: number;
983
+ connectionId: string;
984
+ groupId: string;
985
+ domain: string;
986
+ isPrimary: boolean;
987
+ verifiedAt?: number;
988
+ } | null;
989
+ } | null>>;
883
990
  listConnections: convex_server6.RegisteredQuery<"public", {
884
991
  limit?: number | undefined;
885
992
  where?: {
@@ -890,7 +997,20 @@ declare function createAuthGroupSso<TAuthorization extends AuthAuthorizationConf
890
997
  cursor?: string | null | undefined;
891
998
  orderBy?: string | undefined;
892
999
  order?: "asc" | "desc" | undefined;
893
- }, Promise<GroupConnectionListResult>>;
1000
+ }, Promise<{
1001
+ items: {
1002
+ _id: string;
1003
+ _creationTime: number;
1004
+ groupId: string;
1005
+ slug?: string;
1006
+ name?: string;
1007
+ protocol: "oidc" | "saml";
1008
+ status: "draft" | "active" | "disabled";
1009
+ config?: unknown;
1010
+ extend?: unknown;
1011
+ }[];
1012
+ nextCursor: string | null;
1013
+ }>>;
894
1014
  updateConnection: convex_server6.RegisteredMutation<"public", {
895
1015
  connectionId: string;
896
1016
  data: {
@@ -929,13 +1049,21 @@ declare function createAuthGroupSso<TAuthorization extends AuthAuthorizationConf
929
1049
  configured: boolean;
930
1050
  ready: boolean;
931
1051
  basePath: string | null;
932
- deprovisionMode: GroupConnectionDeprovisionMode;
1052
+ deprovisionMode: "soft" | "hard";
933
1053
  };
934
1054
  };
935
1055
  }>>;
936
1056
  listDomains: convex_server6.RegisteredQuery<"public", {
937
1057
  connectionId: string;
938
- }, Promise<ConnectionDomainRecord[]>>;
1058
+ }, Promise<{
1059
+ _id: string;
1060
+ _creationTime: number;
1061
+ connectionId: string;
1062
+ groupId: string;
1063
+ domain: string;
1064
+ isPrimary: boolean;
1065
+ verifiedAt?: number;
1066
+ }[]>>;
939
1067
  getDomainStatus: convex_server6.RegisteredQuery<"public", {
940
1068
  connectionId: string;
941
1069
  }, Promise<{
@@ -1247,7 +1375,22 @@ declare function createAuthGroupSso<TAuthorization extends AuthAuthorizationConf
1247
1375
  groupId?: string | undefined;
1248
1376
  connectionId?: string | undefined;
1249
1377
  limit?: number | undefined;
1250
- }, Promise<AuditEventRecord[]>>;
1378
+ }, Promise<{
1379
+ _id: string;
1380
+ _creationTime: number;
1381
+ connectionId?: string;
1382
+ groupId: string;
1383
+ eventType: string;
1384
+ actorType: string;
1385
+ actorId?: string;
1386
+ subjectType: string;
1387
+ subjectId?: string;
1388
+ status: string;
1389
+ occurredAt: number;
1390
+ requestId?: string;
1391
+ ip?: string;
1392
+ metadata?: Record<string, unknown>;
1393
+ }[]>>;
1251
1394
  createWebhookEndpoint: convex_server6.RegisteredMutation<"public", {
1252
1395
  createdByUserId?: string | undefined;
1253
1396
  secret: string;
@@ -1341,7 +1484,17 @@ declare function createAuthGroupSso<TAuthorization extends AuthAuthorizationConf
1341
1484
  connectionId: string;
1342
1485
  configured: boolean;
1343
1486
  ready: boolean;
1344
- config: ScimConfigRecord | null;
1487
+ config: {
1488
+ _id: string;
1489
+ _creationTime: number;
1490
+ connectionId: string;
1491
+ groupId: string;
1492
+ status: string;
1493
+ basePath: string;
1494
+ tokenHash: string;
1495
+ lastRotatedAt?: number;
1496
+ extend?: unknown;
1497
+ } | null;
1345
1498
  checks: {
1346
1499
  name: string;
1347
1500
  ok: boolean;
@@ -1378,7 +1531,7 @@ declare function createAuthGroupSso<TAuthorization extends AuthAuthorizationConf
1378
1531
  ok: boolean;
1379
1532
  connectionId: string;
1380
1533
  basePath: string;
1381
- deprovisionMode: GroupConnectionDeprovisionMode;
1534
+ deprovisionMode: "soft" | "hard";
1382
1535
  capabilities: {
1383
1536
  users: boolean;
1384
1537
  groups: boolean;
@@ -54,10 +54,16 @@ async function generateUniqueVerificationCode(ctx, accountId, provider, code, ex
54
54
  const db = authDb(ctx, config);
55
55
  const existingCode = await db.verificationCodes.getByAccountId(accountId);
56
56
  if (existingCode !== null) await db.verificationCodes.delete(existingCode._id);
57
+ const hashedCode = await sha256(code);
58
+ const conflictingCode = await db.verificationCodes.getByCode(hashedCode);
59
+ if (conflictingCode !== null && conflictingCode.accountId !== accountId) throw new ConvexError({
60
+ code: "VERIFICATION_CODE_COLLISION",
61
+ message: "Generated verification code conflicts with another pending sign-in."
62
+ });
57
63
  await db.verificationCodes.create({
58
64
  accountId,
59
65
  provider,
60
- code: await sha256(code),
66
+ code: hashedCode,
61
67
  expirationTime,
62
68
  emailVerified: email,
63
69
  phoneVerified: phone
@@ -1,14 +1,14 @@
1
- import { LOG_LEVELS } from "../../shared/log.js";
2
- import { verify } from "../crypto.js";
3
- import { authDb } from "../db.js";
4
- import { log, maybeRedact } from "../log.js";
5
- import { AUTH_STORE_REF } from "./store/refs.js";
6
- import { withSpan } from "../utils/span.js";
7
- import { issueSession } from "../sessions.js";
8
- import { getSignInRateLimitState, isStateRateLimited, recordFailedSignIn, resetSignInRateLimit } from "../limits.js";
1
+ import { LOG_LEVELS } from "../../../shared/log.js";
2
+ import { verify } from "../../crypto.js";
3
+ import { authDb } from "../../db.js";
4
+ import { log, maybeRedact } from "../../log.js";
5
+ import { AUTH_STORE_REF } from "../store/refs.js";
6
+ import { withSpan } from "../../utils/span.js";
7
+ import { issueSession } from "../../sessions.js";
8
+ import { getSignInRateLimitState, isStateRateLimited, recordFailedSignIn, resetSignInRateLimit } from "../../limits.js";
9
9
  import { v } from "convex/values";
10
10
 
11
- //#region src/server/mutations/credentialsSignIn.ts
11
+ //#region src/server/mutations/credentials/signin.ts
12
12
  const credentialsSignInArgs = v.object({
13
13
  provider: v.string(),
14
14
  account: v.object({
@@ -111,4 +111,4 @@ const callCredentialsSignIn = async (ctx, args) => {
111
111
 
112
112
  //#endregion
113
113
  export { callCredentialsSignIn, credentialsSignInArgs, credentialsSignInImpl };
114
- //# sourceMappingURL=credentialsSignIn.js.map
114
+ //# sourceMappingURL=signin.js.map
@@ -1,6 +1,6 @@
1
1
  import { callModifyAccount } from "./account.js";
2
2
  import { callCreateVerificationCode } from "./code.js";
3
- import { callCredentialsSignIn } from "./credentialsSignIn.js";
3
+ import { callCredentialsSignIn } from "./credentials/signin.js";
4
4
  import { callInvalidateSessions } from "./invalidate.js";
5
5
  import { callUserOAuth } from "./oauth.js";
6
6
  import { callRefreshSession } from "./refresh.js";
@@ -22,7 +22,17 @@ async function invalidateSessionsImpl(ctx, args, config) {
22
22
  const exceptSet = new Set(except ?? []);
23
23
  const typedUserId = userId;
24
24
  const sessions = await authDb(ctx, config).sessions.listByUser(typedUserId);
25
- await Promise.all(sessions.map((session) => exceptSet.has(session._id) ? Promise.resolve() : deleteSession(ctx, session, config)));
25
+ const deleted = [];
26
+ await Promise.all(sessions.map(async (session) => {
27
+ if (exceptSet.has(session._id)) return;
28
+ await deleteSession(ctx, session, config);
29
+ deleted.push(session._id);
30
+ }));
31
+ if (deleted.length > 0) await config.callbacks?.after?.(ctx, {
32
+ kind: "sessionsInvalidated",
33
+ userId: typedUserId,
34
+ sessionIds: deleted
35
+ });
26
36
  }
27
37
 
28
38
  //#endregion
@@ -43,6 +43,30 @@ function normalizeAccountExtend(provider, providerAccountId, accountExtend) {
43
43
  }
44
44
  };
45
45
  }
46
+ async function jitProvisionMembership(ctx, config, connectionPolicy, connection, userId, profile) {
47
+ if (connectionPolicy?.provisioning.jit.mode !== "createUserAndMembership") return;
48
+ const groupId = connection?.groupId;
49
+ if (!groupId) return;
50
+ const provisionedRoleIds = resolveProvisionedRoleIds({
51
+ policy: connectionPolicy,
52
+ groups: Array.isArray(profile.groups) ? profile.groups : void 0,
53
+ roles: Array.isArray(profile.roles) ? profile.roles : void 0
54
+ });
55
+ const existingMembership = await ctx.runQuery(config.component.public.memberGetByGroupAndUser, {
56
+ userId,
57
+ groupId
58
+ });
59
+ if (existingMembership === null) await ctx.runMutation(config.component.public.memberAdd, {
60
+ groupId,
61
+ userId,
62
+ roleIds: provisionedRoleIds,
63
+ status: "active"
64
+ });
65
+ else if (provisionedRoleIds.length > 0) await ctx.runMutation(config.component.public.memberUpdate, {
66
+ memberId: existingMembership._id,
67
+ data: { roleIds: provisionedRoleIds }
68
+ });
69
+ }
46
70
  async function userOAuthImpl(ctx, args, getProviderOrThrow, config) {
47
71
  log("DEBUG", "userOAuthImpl args:", args);
48
72
  const { profile, provider, providerAccountId, signature, accountExtend } = args;
@@ -92,36 +116,10 @@ async function userOAuthImpl(ctx, args, getProviderOrThrow, config) {
92
116
  provisioningUser: connectionPolicy.provisioning.user,
93
117
  source: "login"
94
118
  } : existingScimIdentity?.userId ? { existingUserId: existingScimIdentity.userId } : void 0);
95
- if (connectionId !== null && connectionPolicy?.provisioning.jit.mode === "createUserAndMembership") {
96
- const userId = (await db.accounts.getById(accountId))?.userId;
97
- if (userId) {
98
- const groupId = connection?.groupId;
99
- if (groupId) {
100
- const provisionedRoleIds = resolveProvisionedRoleIds({
101
- policy: connectionPolicy,
102
- groups: Array.isArray(typedProfile.groups) ? typedProfile.groups : void 0,
103
- roles: Array.isArray(typedProfile.roles) ? typedProfile.roles : void 0
104
- });
105
- const existingMembership = await ctx.runQuery(config.component.public.memberGetByGroupAndUser, {
106
- userId,
107
- groupId
108
- });
109
- if (existingMembership === null) await ctx.runMutation(config.component.public.memberAdd, {
110
- groupId,
111
- userId,
112
- roleIds: provisionedRoleIds,
113
- status: "active"
114
- });
115
- else if (provisionedRoleIds.length > 0) await ctx.runMutation(config.component.public.memberUpdate, {
116
- memberId: existingMembership._id,
117
- data: { roleIds: provisionedRoleIds }
118
- });
119
- }
120
- }
121
- }
122
119
  if (connectionId !== null) {
123
120
  const userId = (await db.accounts.getById(accountId))?.userId;
124
121
  if (userId) {
122
+ await jitProvisionMembership(ctx, config, connectionPolicy, connection, userId, typedProfile);
125
123
  if (config.sso?.hooks?.afterProvision) await config.sso.hooks.afterProvision({
126
124
  protocol: connectionProtocol ?? "oidc",
127
125
  connectionId,
@@ -33,6 +33,12 @@ async function signInImpl(ctx, args, config) {
33
33
  sessionId: issuance.sessionId
34
34
  })
35
35
  });
36
+ await config.callbacks?.after?.(ctx, {
37
+ kind: "signedIn",
38
+ userId: issuance.userId,
39
+ sessionId: issuance.sessionId,
40
+ provider: "session"
41
+ });
36
42
  return issuance;
37
43
  });
38
44
  }
@@ -26,6 +26,11 @@ async function signOutImpl(ctx, config) {
26
26
  sessionId: session._id
27
27
  })
28
28
  });
29
+ await config.callbacks?.after?.(ctx, {
30
+ kind: "signedOut",
31
+ userId: session.userId,
32
+ sessionId: session._id
33
+ });
29
34
  return {
30
35
  userId: session.userId,
31
36
  sessionId: session._id
@@ -2,7 +2,7 @@ import { LOG_LEVELS } from "../../shared/log.js";
2
2
  import { log } from "../log.js";
3
3
  import { modifyAccountArgs, modifyAccountImpl } from "./account.js";
4
4
  import { createVerificationCodeArgs, createVerificationCodeImpl } from "./code.js";
5
- import { credentialsSignInArgs, credentialsSignInImpl } from "./credentialsSignIn.js";
5
+ import { credentialsSignInArgs, credentialsSignInImpl } from "./credentials/signin.js";
6
6
  import { invalidateSessionsArgs, invalidateSessionsImpl } from "./invalidate.js";
7
7
  import { userOAuthArgs, userOAuthImpl } from "./oauth.js";
8
8
  import { refreshSessionArgs } from "./refresh.js";
@@ -13,19 +13,27 @@ function normalizeTokens(tokens) {
13
13
  };
14
14
  }
15
15
  function createArcticOAuthClient(provider, options) {
16
- const pkce = options?.pkce ?? (provider.createAuthorizationURL.length >= 3 ? "required" : "never");
16
+ const getProvider = () => typeof provider === "function" ? provider() : provider;
17
+ const pkce = options?.pkce ?? (getProvider().createAuthorizationURL.length >= 3 ? "required" : "never");
17
18
  return {
18
19
  pkce,
19
20
  createAuthorizationURL({ state, codeVerifier, scopes, nonce }) {
20
- const url = pkce === "required" ? provider.createAuthorizationURL(state, codeVerifier, scopes) : provider.createAuthorizationURL(state, scopes);
21
+ const provider$1 = getProvider();
22
+ const url = pkce !== "never" ? provider$1.createAuthorizationURL(state, codeVerifier, scopes) : provider$1.createAuthorizationURL(state, scopes);
21
23
  if (nonce !== void 0) url.searchParams.set("nonce", nonce);
22
24
  return url;
23
25
  },
24
26
  async validateAuthorizationCode({ code, codeVerifier }) {
25
- return normalizeTokens(pkce === "required" ? await provider.validateAuthorizationCode(code, codeVerifier) : await provider.validateAuthorizationCode(code));
27
+ const provider$1 = getProvider();
28
+ return normalizeTokens(pkce !== "never" ? await provider$1.validateAuthorizationCode(code, codeVerifier) : await provider$1.validateAuthorizationCode(code));
26
29
  }
27
30
  };
28
31
  }
32
+ /**
33
+ * Materialize a validated OAuth provider definition for internal auth runtime use.
34
+ *
35
+ * @internal
36
+ */
29
37
  function createOAuthProvider(config) {
30
38
  if (!config.provider || typeof config.provider.createAuthorizationURL !== "function" || typeof config.provider.validateAuthorizationCode !== "function") throw new Error(`OAuth provider "${config.id}" must expose createAuthorizationURL() and validateAuthorizationCode().`);
31
39
  return {