@checkstack/auth-backend 0.2.2 → 0.4.0
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/CHANGELOG.md +37 -0
- package/package.json +1 -1
- package/src/index.ts +43 -86
- package/src/router.test.ts +680 -30
- package/src/router.ts +406 -127
package/src/router.ts
CHANGED
|
@@ -31,6 +31,11 @@ import {
|
|
|
31
31
|
PLATFORM_REGISTRATION_CONFIG_ID,
|
|
32
32
|
} from "./platform-registration-config";
|
|
33
33
|
|
|
34
|
+
export const ADMIN_ROLE_ID = "admin";
|
|
35
|
+
export const USERS_ROLE_ID = "users";
|
|
36
|
+
export const ANONYMOUS_ROLE_ID = "anonymous";
|
|
37
|
+
export const APPLICATIONS_ROLE_ID = "applications";
|
|
38
|
+
|
|
34
39
|
/**
|
|
35
40
|
* Creates the auth router using contract-based implementation.
|
|
36
41
|
*
|
|
@@ -52,12 +57,12 @@ const os = implement(authContract)
|
|
|
52
57
|
*/
|
|
53
58
|
async function getStrategyEnabled(
|
|
54
59
|
strategyId: string,
|
|
55
|
-
configService: ConfigService
|
|
60
|
+
configService: ConfigService,
|
|
56
61
|
): Promise<boolean> {
|
|
57
62
|
const metaConfig = await configService.get(
|
|
58
63
|
`${strategyId}.meta`,
|
|
59
64
|
strategyMetaConfigV1,
|
|
60
|
-
STRATEGY_META_CONFIG_VERSION
|
|
65
|
+
STRATEGY_META_CONFIG_VERSION,
|
|
61
66
|
);
|
|
62
67
|
|
|
63
68
|
// Default: credential=true (fresh installs), others=false (require explicit config)
|
|
@@ -70,13 +75,13 @@ async function getStrategyEnabled(
|
|
|
70
75
|
async function setStrategyEnabled(
|
|
71
76
|
strategyId: string,
|
|
72
77
|
enabled: boolean,
|
|
73
|
-
configService: ConfigService
|
|
78
|
+
configService: ConfigService,
|
|
74
79
|
): Promise<void> {
|
|
75
80
|
await configService.set(
|
|
76
81
|
`${strategyId}.meta`,
|
|
77
82
|
strategyMetaConfigV1,
|
|
78
83
|
STRATEGY_META_CONFIG_VERSION,
|
|
79
|
-
{ enabled }
|
|
84
|
+
{ enabled },
|
|
80
85
|
);
|
|
81
86
|
}
|
|
82
87
|
|
|
@@ -87,12 +92,12 @@ async function setStrategyEnabled(
|
|
|
87
92
|
* @returns true if registration is allowed, false otherwise
|
|
88
93
|
*/
|
|
89
94
|
async function isRegistrationAllowed(
|
|
90
|
-
configService: ConfigService
|
|
95
|
+
configService: ConfigService,
|
|
91
96
|
): Promise<boolean> {
|
|
92
97
|
const config = await configService.get(
|
|
93
98
|
PLATFORM_REGISTRATION_CONFIG_ID,
|
|
94
99
|
platformRegistrationConfigV1,
|
|
95
|
-
PLATFORM_REGISTRATION_CONFIG_VERSION
|
|
100
|
+
PLATFORM_REGISTRATION_CONFIG_VERSION,
|
|
96
101
|
);
|
|
97
102
|
return config?.allowRegistration ?? true;
|
|
98
103
|
}
|
|
@@ -124,7 +129,7 @@ export const createAuthRouter = (
|
|
|
124
129
|
isDefault?: boolean;
|
|
125
130
|
isPublic?: boolean;
|
|
126
131
|
}[];
|
|
127
|
-
}
|
|
132
|
+
},
|
|
128
133
|
) => {
|
|
129
134
|
// Public endpoint for enabled strategies (no authentication required)
|
|
130
135
|
const getEnabledStrategies = os.getEnabledStrategies.handler(async () => {
|
|
@@ -148,7 +153,7 @@ export const createAuthRouter = (
|
|
|
148
153
|
icon: strategy.icon,
|
|
149
154
|
requiresManualRegistration: strategy.requiresManualRegistration,
|
|
150
155
|
};
|
|
151
|
-
})
|
|
156
|
+
}),
|
|
152
157
|
);
|
|
153
158
|
|
|
154
159
|
// Filter to only return enabled strategies
|
|
@@ -173,8 +178,8 @@ export const createAuthRouter = (
|
|
|
173
178
|
.where(
|
|
174
179
|
inArray(
|
|
175
180
|
schema.userRole.userId,
|
|
176
|
-
users.map((u) => u.id)
|
|
177
|
-
)
|
|
181
|
+
users.map((u) => u.id),
|
|
182
|
+
),
|
|
178
183
|
);
|
|
179
184
|
|
|
180
185
|
return users.map((u) => ({
|
|
@@ -186,9 +191,15 @@ export const createAuthRouter = (
|
|
|
186
191
|
});
|
|
187
192
|
|
|
188
193
|
const deleteUser = os.deleteUser.handler(async ({ input: id, context }) => {
|
|
189
|
-
if
|
|
194
|
+
// Check if user has admin role - prevent deletion to avoid lockout
|
|
195
|
+
const userRoles = await internalDb
|
|
196
|
+
.select({ roleId: schema.userRole.roleId })
|
|
197
|
+
.from(schema.userRole)
|
|
198
|
+
.where(eq(schema.userRole.userId, id));
|
|
199
|
+
|
|
200
|
+
if (userRoles.some((ur) => ur.roleId === ADMIN_ROLE_ID)) {
|
|
190
201
|
throw new ORPCError("FORBIDDEN", {
|
|
191
|
-
message: "Cannot delete
|
|
202
|
+
message: "Cannot delete users with the admin role",
|
|
192
203
|
});
|
|
193
204
|
}
|
|
194
205
|
|
|
@@ -227,7 +238,7 @@ export const createAuthRouter = (
|
|
|
227
238
|
.map((rp) => rp.accessRuleId),
|
|
228
239
|
isSystem: role.isSystem || false,
|
|
229
240
|
// Anonymous role cannot be assigned to users - it's for unauthenticated access
|
|
230
|
-
isAssignable: role.id !==
|
|
241
|
+
isAssignable: role.id !== ANONYMOUS_ROLE_ID,
|
|
231
242
|
}));
|
|
232
243
|
});
|
|
233
244
|
|
|
@@ -244,12 +255,12 @@ export const createAuthRouter = (
|
|
|
244
255
|
|
|
245
256
|
// Get active access rules to filter input
|
|
246
257
|
const activeAccessRules = new Set(
|
|
247
|
-
accessRuleRegistry.getAccessRules().map((p) => p.id)
|
|
258
|
+
accessRuleRegistry.getAccessRules().map((p) => p.id),
|
|
248
259
|
);
|
|
249
260
|
|
|
250
261
|
// Filter to only include active access rules
|
|
251
262
|
const validAccessRules = inputAccessRules.filter((p) =>
|
|
252
|
-
activeAccessRules.has(p)
|
|
263
|
+
activeAccessRules.has(p),
|
|
253
264
|
);
|
|
254
265
|
|
|
255
266
|
await internalDb.transaction(async (tx) => {
|
|
@@ -267,7 +278,7 @@ export const createAuthRouter = (
|
|
|
267
278
|
validAccessRules.map((accessRuleId) => ({
|
|
268
279
|
roleId: id,
|
|
269
280
|
accessRuleId,
|
|
270
|
-
}))
|
|
281
|
+
})),
|
|
271
282
|
);
|
|
272
283
|
}
|
|
273
284
|
});
|
|
@@ -292,8 +303,8 @@ export const createAuthRouter = (
|
|
|
292
303
|
});
|
|
293
304
|
}
|
|
294
305
|
|
|
295
|
-
const isUsersRole = id ===
|
|
296
|
-
const isAdminRole = id ===
|
|
306
|
+
const isUsersRole = id === USERS_ROLE_ID;
|
|
307
|
+
const isAdminRole = id === ADMIN_ROLE_ID;
|
|
297
308
|
|
|
298
309
|
// System roles can have name/description edited, but not deleted
|
|
299
310
|
// Admin role: access rules cannot be changed (wildcard access)
|
|
@@ -302,12 +313,12 @@ export const createAuthRouter = (
|
|
|
302
313
|
|
|
303
314
|
// Get active access rules to filter input
|
|
304
315
|
const activeAccessRules = new Set(
|
|
305
|
-
accessRuleRegistry.getAccessRules().map((p) => p.id)
|
|
316
|
+
accessRuleRegistry.getAccessRules().map((p) => p.id),
|
|
306
317
|
);
|
|
307
318
|
|
|
308
319
|
// Filter to only include active access rules
|
|
309
320
|
const validAccessRules = inputAccessRules.filter((p) =>
|
|
310
|
-
activeAccessRules.has(p)
|
|
321
|
+
activeAccessRules.has(p),
|
|
311
322
|
);
|
|
312
323
|
|
|
313
324
|
// Track disabled authenticated default access rules for "users" role
|
|
@@ -319,7 +330,7 @@ export const createAuthRouter = (
|
|
|
319
330
|
|
|
320
331
|
// Find authenticated default access rules that are being removed
|
|
321
332
|
const removedDefaults = defaultPermIds.filter(
|
|
322
|
-
(defId) => !validAccessRules.includes(defId)
|
|
333
|
+
(defId) => !validAccessRules.includes(defId),
|
|
323
334
|
);
|
|
324
335
|
|
|
325
336
|
// Insert into disabled_default_access_rule table
|
|
@@ -335,7 +346,7 @@ export const createAuthRouter = (
|
|
|
335
346
|
|
|
336
347
|
// Remove from disabled table if being re-added
|
|
337
348
|
const readdedDefaults = validAccessRules.filter((p) =>
|
|
338
|
-
defaultPermIds.includes(p)
|
|
349
|
+
defaultPermIds.includes(p),
|
|
339
350
|
);
|
|
340
351
|
for (const permId of readdedDefaults) {
|
|
341
352
|
await internalDb
|
|
@@ -345,7 +356,7 @@ export const createAuthRouter = (
|
|
|
345
356
|
}
|
|
346
357
|
|
|
347
358
|
// Track disabled public default access rules for "anonymous" role
|
|
348
|
-
const isAnonymousRole = id ===
|
|
359
|
+
const isAnonymousRole = id === ANONYMOUS_ROLE_ID;
|
|
349
360
|
if (isAnonymousRole) {
|
|
350
361
|
const allPerms = accessRuleRegistry.getAccessRules();
|
|
351
362
|
const publicDefaultPermIds = allPerms
|
|
@@ -354,7 +365,7 @@ export const createAuthRouter = (
|
|
|
354
365
|
|
|
355
366
|
// Find public default access rules that are being removed
|
|
356
367
|
const removedPublicDefaults = publicDefaultPermIds.filter(
|
|
357
|
-
(defId) => !validAccessRules.includes(defId)
|
|
368
|
+
(defId) => !validAccessRules.includes(defId),
|
|
358
369
|
);
|
|
359
370
|
|
|
360
371
|
// Insert into disabled_public_default_access_rule table
|
|
@@ -370,13 +381,13 @@ export const createAuthRouter = (
|
|
|
370
381
|
|
|
371
382
|
// Remove from disabled table if being re-added
|
|
372
383
|
const readdedPublicDefaults = validAccessRules.filter((p) =>
|
|
373
|
-
publicDefaultPermIds.includes(p)
|
|
384
|
+
publicDefaultPermIds.includes(p),
|
|
374
385
|
);
|
|
375
386
|
for (const permId of readdedPublicDefaults) {
|
|
376
387
|
await internalDb
|
|
377
388
|
.delete(schema.disabledPublicDefaultAccessRule)
|
|
378
389
|
.where(
|
|
379
|
-
eq(schema.disabledPublicDefaultAccessRule.accessRuleId, permId)
|
|
390
|
+
eq(schema.disabledPublicDefaultAccessRule.accessRuleId, permId),
|
|
380
391
|
);
|
|
381
392
|
}
|
|
382
393
|
}
|
|
@@ -406,7 +417,7 @@ export const createAuthRouter = (
|
|
|
406
417
|
validAccessRules.map((accessRuleId) => ({
|
|
407
418
|
roleId: id,
|
|
408
419
|
accessRuleId,
|
|
409
|
-
}))
|
|
420
|
+
})),
|
|
410
421
|
);
|
|
411
422
|
}
|
|
412
423
|
});
|
|
@@ -468,7 +479,7 @@ export const createAuthRouter = (
|
|
|
468
479
|
}
|
|
469
480
|
|
|
470
481
|
// Prevent assignment of the "anonymous" role - it's reserved for unauthenticated users
|
|
471
|
-
if (roles.includes(
|
|
482
|
+
if (roles.includes(ANONYMOUS_ROLE_ID)) {
|
|
472
483
|
throw new ORPCError("BAD_REQUEST", {
|
|
473
484
|
message: "The 'anonymous' role cannot be assigned to users",
|
|
474
485
|
});
|
|
@@ -483,11 +494,11 @@ export const createAuthRouter = (
|
|
|
483
494
|
roles.map((roleId) => ({
|
|
484
495
|
userId,
|
|
485
496
|
roleId,
|
|
486
|
-
}))
|
|
497
|
+
})),
|
|
487
498
|
);
|
|
488
499
|
}
|
|
489
500
|
});
|
|
490
|
-
}
|
|
501
|
+
},
|
|
491
502
|
);
|
|
492
503
|
|
|
493
504
|
const getStrategies = os.getStrategies.handler(async () => {
|
|
@@ -500,7 +511,7 @@ export const createAuthRouter = (
|
|
|
500
511
|
strategy.id,
|
|
501
512
|
strategy.configSchema,
|
|
502
513
|
strategy.configVersion,
|
|
503
|
-
strategy.migrations
|
|
514
|
+
strategy.migrations,
|
|
504
515
|
);
|
|
505
516
|
|
|
506
517
|
// Convert Zod schema to JSON Schema with automatic secret metadata
|
|
@@ -520,7 +531,7 @@ export const createAuthRouter = (
|
|
|
520
531
|
config,
|
|
521
532
|
adminInstructions: strategy.adminInstructions,
|
|
522
533
|
};
|
|
523
|
-
})
|
|
534
|
+
}),
|
|
524
535
|
);
|
|
525
536
|
});
|
|
526
537
|
|
|
@@ -541,7 +552,7 @@ export const createAuthRouter = (
|
|
|
541
552
|
strategy.configSchema,
|
|
542
553
|
strategy.configVersion,
|
|
543
554
|
config, // Just the config, no enabled mixed in
|
|
544
|
-
strategy.migrations
|
|
555
|
+
strategy.migrations,
|
|
545
556
|
);
|
|
546
557
|
}
|
|
547
558
|
|
|
@@ -574,12 +585,208 @@ export const createAuthRouter = (
|
|
|
574
585
|
PLATFORM_REGISTRATION_CONFIG_ID,
|
|
575
586
|
platformRegistrationConfigV1,
|
|
576
587
|
PLATFORM_REGISTRATION_CONFIG_VERSION,
|
|
577
|
-
{ allowRegistration: input.allowRegistration }
|
|
588
|
+
{ allowRegistration: input.allowRegistration },
|
|
578
589
|
);
|
|
579
590
|
// Trigger auth reload to apply new settings
|
|
580
591
|
await reloadAuthFn();
|
|
581
592
|
return { success: true };
|
|
582
|
-
}
|
|
593
|
+
},
|
|
594
|
+
);
|
|
595
|
+
|
|
596
|
+
// ==========================================================================
|
|
597
|
+
// ONBOARDING ENDPOINTS
|
|
598
|
+
// ==========================================================================
|
|
599
|
+
|
|
600
|
+
const getOnboardingStatus = os.getOnboardingStatus.handler(async () => {
|
|
601
|
+
// Check if any users exist in the database
|
|
602
|
+
const users = await internalDb
|
|
603
|
+
.select({ id: schema.user.id })
|
|
604
|
+
.from(schema.user)
|
|
605
|
+
.limit(1);
|
|
606
|
+
return { needsOnboarding: users.length === 0 };
|
|
607
|
+
});
|
|
608
|
+
|
|
609
|
+
const completeOnboarding = os.completeOnboarding.handler(
|
|
610
|
+
async ({ input }) => {
|
|
611
|
+
const { name, email, password } = input;
|
|
612
|
+
|
|
613
|
+
// Security check: only allow if no users exist
|
|
614
|
+
const existingUsers = await internalDb
|
|
615
|
+
.select({ id: schema.user.id })
|
|
616
|
+
.from(schema.user)
|
|
617
|
+
.limit(1);
|
|
618
|
+
|
|
619
|
+
if (existingUsers.length > 0) {
|
|
620
|
+
throw new ORPCError("FORBIDDEN", {
|
|
621
|
+
message: "Onboarding has already been completed.",
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
// Validate password against platform's password schema
|
|
626
|
+
const passwordValidation = passwordSchema.safeParse(password);
|
|
627
|
+
if (!passwordValidation.success) {
|
|
628
|
+
throw new ORPCError("BAD_REQUEST", {
|
|
629
|
+
message: passwordValidation.error.issues
|
|
630
|
+
.map((issue) => issue.message)
|
|
631
|
+
.join(", "),
|
|
632
|
+
});
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
// Create the first admin user
|
|
636
|
+
const userId = crypto.randomUUID();
|
|
637
|
+
const accountId = crypto.randomUUID();
|
|
638
|
+
const hashedPassword = await hashPassword(password);
|
|
639
|
+
const now = new Date();
|
|
640
|
+
|
|
641
|
+
await internalDb.transaction(async (tx) => {
|
|
642
|
+
// Create user
|
|
643
|
+
await tx.insert(schema.user).values({
|
|
644
|
+
id: userId,
|
|
645
|
+
email,
|
|
646
|
+
name,
|
|
647
|
+
emailVerified: true,
|
|
648
|
+
createdAt: now,
|
|
649
|
+
updatedAt: now,
|
|
650
|
+
});
|
|
651
|
+
|
|
652
|
+
// Create credential account
|
|
653
|
+
await tx.insert(schema.account).values({
|
|
654
|
+
id: accountId,
|
|
655
|
+
accountId: email,
|
|
656
|
+
providerId: "credential",
|
|
657
|
+
userId,
|
|
658
|
+
password: hashedPassword,
|
|
659
|
+
createdAt: now,
|
|
660
|
+
updatedAt: now,
|
|
661
|
+
});
|
|
662
|
+
|
|
663
|
+
// Assign admin role
|
|
664
|
+
await tx.insert(schema.userRole).values({
|
|
665
|
+
userId,
|
|
666
|
+
roleId: ADMIN_ROLE_ID,
|
|
667
|
+
});
|
|
668
|
+
});
|
|
669
|
+
|
|
670
|
+
return { success: true };
|
|
671
|
+
},
|
|
672
|
+
);
|
|
673
|
+
|
|
674
|
+
// ==========================================================================
|
|
675
|
+
// USER PROFILE ENDPOINTS
|
|
676
|
+
// ==========================================================================
|
|
677
|
+
|
|
678
|
+
const getCurrentUserProfile = os.getCurrentUserProfile.handler(
|
|
679
|
+
async ({ context }) => {
|
|
680
|
+
const user = context.user;
|
|
681
|
+
if (!isRealUser(user)) {
|
|
682
|
+
throw new ORPCError("UNAUTHORIZED", {
|
|
683
|
+
message: "Not authenticated",
|
|
684
|
+
});
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
// Get user data
|
|
688
|
+
const users = await internalDb
|
|
689
|
+
.select()
|
|
690
|
+
.from(schema.user)
|
|
691
|
+
.where(eq(schema.user.id, user.id))
|
|
692
|
+
.limit(1);
|
|
693
|
+
|
|
694
|
+
if (users.length === 0) {
|
|
695
|
+
throw new ORPCError("NOT_FOUND", {
|
|
696
|
+
message: "User not found",
|
|
697
|
+
});
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
// Check if user has a credential account
|
|
701
|
+
const accounts = await internalDb
|
|
702
|
+
.select()
|
|
703
|
+
.from(schema.account)
|
|
704
|
+
.where(
|
|
705
|
+
and(
|
|
706
|
+
eq(schema.account.userId, user.id),
|
|
707
|
+
eq(schema.account.providerId, "credential"),
|
|
708
|
+
),
|
|
709
|
+
)
|
|
710
|
+
.limit(1);
|
|
711
|
+
|
|
712
|
+
return {
|
|
713
|
+
id: users[0].id,
|
|
714
|
+
name: users[0].name,
|
|
715
|
+
email: users[0].email,
|
|
716
|
+
hasCredentialAccount: accounts.length > 0,
|
|
717
|
+
};
|
|
718
|
+
},
|
|
719
|
+
);
|
|
720
|
+
|
|
721
|
+
const updateCurrentUser = os.updateCurrentUser.handler(
|
|
722
|
+
async ({ input, context }) => {
|
|
723
|
+
const user = context.user;
|
|
724
|
+
if (!isRealUser(user)) {
|
|
725
|
+
throw new ORPCError("UNAUTHORIZED", {
|
|
726
|
+
message: "Not authenticated",
|
|
727
|
+
});
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
const { name, email } = input;
|
|
731
|
+
|
|
732
|
+
// If email is being updated, check if user has a credential account
|
|
733
|
+
if (email !== undefined) {
|
|
734
|
+
const accounts = await internalDb
|
|
735
|
+
.select()
|
|
736
|
+
.from(schema.account)
|
|
737
|
+
.where(
|
|
738
|
+
and(
|
|
739
|
+
eq(schema.account.userId, user.id),
|
|
740
|
+
eq(schema.account.providerId, "credential"),
|
|
741
|
+
),
|
|
742
|
+
)
|
|
743
|
+
.limit(1);
|
|
744
|
+
|
|
745
|
+
if (accounts.length === 0) {
|
|
746
|
+
throw new ORPCError("FORBIDDEN", {
|
|
747
|
+
message: "Email can only be updated for credential-based accounts.",
|
|
748
|
+
});
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
// Check email uniqueness
|
|
752
|
+
const existingUsers = await internalDb
|
|
753
|
+
.select({ id: schema.user.id })
|
|
754
|
+
.from(schema.user)
|
|
755
|
+
.where(eq(schema.user.email, email))
|
|
756
|
+
.limit(1);
|
|
757
|
+
|
|
758
|
+
if (existingUsers.length > 0 && existingUsers[0].id !== user.id) {
|
|
759
|
+
throw new ORPCError("CONFLICT", {
|
|
760
|
+
message: "A user with this email already exists.",
|
|
761
|
+
});
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
// Build update object
|
|
766
|
+
const updates: { name?: string; email?: string; updatedAt: Date } = {
|
|
767
|
+
updatedAt: new Date(),
|
|
768
|
+
};
|
|
769
|
+
if (name !== undefined) updates.name = name;
|
|
770
|
+
if (email !== undefined) updates.email = email;
|
|
771
|
+
|
|
772
|
+
await internalDb
|
|
773
|
+
.update(schema.user)
|
|
774
|
+
.set(updates)
|
|
775
|
+
.where(eq(schema.user.id, user.id));
|
|
776
|
+
|
|
777
|
+
// If email was updated, also update the credential account's accountId
|
|
778
|
+
if (email !== undefined) {
|
|
779
|
+
await internalDb
|
|
780
|
+
.update(schema.account)
|
|
781
|
+
.set({ accountId: email, updatedAt: new Date() })
|
|
782
|
+
.where(
|
|
783
|
+
and(
|
|
784
|
+
eq(schema.account.userId, user.id),
|
|
785
|
+
eq(schema.account.providerId, "credential"),
|
|
786
|
+
),
|
|
787
|
+
);
|
|
788
|
+
}
|
|
789
|
+
},
|
|
583
790
|
);
|
|
584
791
|
|
|
585
792
|
const getAnonymousAccessRules = os.getAnonymousAccessRules.handler(
|
|
@@ -587,9 +794,9 @@ export const createAuthRouter = (
|
|
|
587
794
|
const rolePerms = await internalDb
|
|
588
795
|
.select()
|
|
589
796
|
.from(schema.roleAccessRule)
|
|
590
|
-
.where(eq(schema.roleAccessRule.roleId,
|
|
797
|
+
.where(eq(schema.roleAccessRule.roleId, ANONYMOUS_ROLE_ID));
|
|
591
798
|
return rolePerms.map((rp) => rp.accessRuleId);
|
|
592
|
-
}
|
|
799
|
+
},
|
|
593
800
|
);
|
|
594
801
|
|
|
595
802
|
const filterUsersByAccessRule = os.filterUsersByAccessRule.handler(
|
|
@@ -605,18 +812,18 @@ export const createAuthRouter = (
|
|
|
605
812
|
.from(schema.userRole)
|
|
606
813
|
.innerJoin(
|
|
607
814
|
schema.roleAccessRule,
|
|
608
|
-
eq(schema.userRole.roleId, schema.roleAccessRule.roleId)
|
|
815
|
+
eq(schema.userRole.roleId, schema.roleAccessRule.roleId),
|
|
609
816
|
)
|
|
610
817
|
.where(
|
|
611
818
|
and(
|
|
612
819
|
inArray(schema.userRole.userId, userIds),
|
|
613
|
-
eq(schema.roleAccessRule.accessRuleId, accessRule)
|
|
614
|
-
)
|
|
820
|
+
eq(schema.roleAccessRule.accessRuleId, accessRule),
|
|
821
|
+
),
|
|
615
822
|
)
|
|
616
823
|
.groupBy(schema.userRole.userId);
|
|
617
824
|
|
|
618
825
|
return usersWithAccess.map((row) => row.userId);
|
|
619
|
-
}
|
|
826
|
+
},
|
|
620
827
|
);
|
|
621
828
|
|
|
622
829
|
// ==========================================================================
|
|
@@ -649,8 +856,16 @@ export const createAuthRouter = (
|
|
|
649
856
|
|
|
650
857
|
const upsertExternalUser = os.upsertExternalUser.handler(
|
|
651
858
|
async ({ input, context }) => {
|
|
652
|
-
const {
|
|
653
|
-
|
|
859
|
+
const {
|
|
860
|
+
email,
|
|
861
|
+
name,
|
|
862
|
+
providerId,
|
|
863
|
+
accountId,
|
|
864
|
+
password,
|
|
865
|
+
autoUpdateUser,
|
|
866
|
+
syncRoles,
|
|
867
|
+
managedRoleIds,
|
|
868
|
+
} = input;
|
|
654
869
|
|
|
655
870
|
// Check if user exists
|
|
656
871
|
const existingUsers = await internalDb
|
|
@@ -659,9 +874,12 @@ export const createAuthRouter = (
|
|
|
659
874
|
.where(eq(schema.user.email, email))
|
|
660
875
|
.limit(1);
|
|
661
876
|
|
|
877
|
+
let userId: string;
|
|
878
|
+
let created = false;
|
|
879
|
+
|
|
662
880
|
if (existingUsers.length > 0) {
|
|
663
881
|
// User exists - update if autoUpdateUser is enabled
|
|
664
|
-
|
|
882
|
+
userId = existingUsers[0].id;
|
|
665
883
|
|
|
666
884
|
if (autoUpdateUser) {
|
|
667
885
|
await internalDb
|
|
@@ -669,50 +887,107 @@ export const createAuthRouter = (
|
|
|
669
887
|
.set({ name, updatedAt: new Date() })
|
|
670
888
|
.where(eq(schema.user.id, userId));
|
|
671
889
|
}
|
|
890
|
+
} else {
|
|
891
|
+
// Check if registration is allowed before creating new user
|
|
892
|
+
const registrationAllowed = await isRegistrationAllowed(configService);
|
|
893
|
+
if (!registrationAllowed) {
|
|
894
|
+
throw new ORPCError("FORBIDDEN", {
|
|
895
|
+
message:
|
|
896
|
+
"Registration is disabled. Please contact an administrator.",
|
|
897
|
+
});
|
|
898
|
+
}
|
|
672
899
|
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
900
|
+
// Create new user and account in a transaction
|
|
901
|
+
userId = crypto.randomUUID();
|
|
902
|
+
const accountEntryId = crypto.randomUUID();
|
|
903
|
+
const now = new Date();
|
|
904
|
+
|
|
905
|
+
await internalDb.transaction(async (tx) => {
|
|
906
|
+
// Create user
|
|
907
|
+
await tx.insert(schema.user).values({
|
|
908
|
+
id: userId,
|
|
909
|
+
email,
|
|
910
|
+
name,
|
|
911
|
+
emailVerified: false,
|
|
912
|
+
createdAt: now,
|
|
913
|
+
updatedAt: now,
|
|
914
|
+
});
|
|
915
|
+
|
|
916
|
+
// Create account
|
|
917
|
+
await tx.insert(schema.account).values({
|
|
918
|
+
id: accountEntryId,
|
|
919
|
+
accountId,
|
|
920
|
+
providerId,
|
|
921
|
+
userId,
|
|
922
|
+
password,
|
|
923
|
+
createdAt: now,
|
|
924
|
+
updatedAt: now,
|
|
925
|
+
});
|
|
681
926
|
});
|
|
682
|
-
}
|
|
683
927
|
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
const now = new Date();
|
|
928
|
+
context.logger.info(`Created new user from ${providerId}: ${email}`);
|
|
929
|
+
created = true;
|
|
930
|
+
}
|
|
688
931
|
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
932
|
+
// Handle role sync if syncRoles is provided
|
|
933
|
+
// Uses managedRoleIds to determine which roles are controlled by directory
|
|
934
|
+
if (syncRoles) {
|
|
935
|
+
const syncRoleSet = new Set(syncRoles);
|
|
936
|
+
|
|
937
|
+
// Validate which sync roles actually exist in the database
|
|
938
|
+
const validSyncRoles =
|
|
939
|
+
syncRoles.length > 0
|
|
940
|
+
? await internalDb
|
|
941
|
+
.select({ id: schema.role.id })
|
|
942
|
+
.from(schema.role)
|
|
943
|
+
.where(inArray(schema.role.id, syncRoles))
|
|
944
|
+
: [];
|
|
945
|
+
const validSyncRoleIds = new Set(validSyncRoles.map((r) => r.id));
|
|
946
|
+
|
|
947
|
+
// Get current user roles
|
|
948
|
+
const currentRoles = await internalDb
|
|
949
|
+
.select({ roleId: schema.userRole.roleId })
|
|
950
|
+
.from(schema.userRole)
|
|
951
|
+
.where(eq(schema.userRole.userId, userId));
|
|
952
|
+
const currentRoleIds = new Set(currentRoles.map((r) => r.roleId));
|
|
699
953
|
|
|
700
|
-
//
|
|
701
|
-
|
|
702
|
-
id
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
954
|
+
// Add new roles that user should have
|
|
955
|
+
const rolesToAdd = [...validSyncRoleIds].filter(
|
|
956
|
+
(id) => !currentRoleIds.has(id),
|
|
957
|
+
);
|
|
958
|
+
if (rolesToAdd.length > 0) {
|
|
959
|
+
await internalDb
|
|
960
|
+
.insert(schema.userRole)
|
|
961
|
+
.values(rolesToAdd.map((roleId) => ({ userId, roleId })));
|
|
962
|
+
context.logger.info(
|
|
963
|
+
`Added ${rolesToAdd.length} roles for external user: ${email}`,
|
|
964
|
+
);
|
|
965
|
+
}
|
|
711
966
|
|
|
712
|
-
|
|
967
|
+
// Remove roles that are managed but user no longer has in directory
|
|
968
|
+
if (managedRoleIds && managedRoleIds.length > 0) {
|
|
969
|
+
// Roles to remove: currently has + is managed + NOT in sync roles
|
|
970
|
+
const rolesToRemove = [...currentRoleIds].filter(
|
|
971
|
+
(id) => managedRoleIds.includes(id) && !syncRoleSet.has(id),
|
|
972
|
+
);
|
|
973
|
+
if (rolesToRemove.length > 0) {
|
|
974
|
+
await internalDb
|
|
975
|
+
.delete(schema.userRole)
|
|
976
|
+
.where(
|
|
977
|
+
and(
|
|
978
|
+
eq(schema.userRole.userId, userId),
|
|
979
|
+
inArray(schema.userRole.roleId, rolesToRemove),
|
|
980
|
+
),
|
|
981
|
+
);
|
|
982
|
+
context.logger.info(
|
|
983
|
+
`Removed ${rolesToRemove.length} managed roles for external user: ${email}`,
|
|
984
|
+
);
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
}
|
|
713
988
|
|
|
714
|
-
return { userId, created
|
|
715
|
-
}
|
|
989
|
+
return { userId, created };
|
|
990
|
+
},
|
|
716
991
|
);
|
|
717
992
|
|
|
718
993
|
const createSession = os.createSession.handler(async ({ input }) => {
|
|
@@ -753,7 +1028,7 @@ export const createAuthRouter = (
|
|
|
753
1028
|
// Check if credential strategy is enabled
|
|
754
1029
|
const credentialEnabled = await getStrategyEnabled(
|
|
755
1030
|
"credential",
|
|
756
|
-
configService
|
|
1031
|
+
configService,
|
|
757
1032
|
);
|
|
758
1033
|
if (!credentialEnabled) {
|
|
759
1034
|
throw new ORPCError("BAD_REQUEST", {
|
|
@@ -806,16 +1081,16 @@ export const createAuthRouter = (
|
|
|
806
1081
|
// Assign "users" role to new user
|
|
807
1082
|
await tx.insert(schema.userRole).values({
|
|
808
1083
|
userId,
|
|
809
|
-
roleId:
|
|
1084
|
+
roleId: USERS_ROLE_ID,
|
|
810
1085
|
});
|
|
811
1086
|
});
|
|
812
1087
|
|
|
813
1088
|
context.logger.info(
|
|
814
|
-
`[auth-backend] Admin created credential user: ${email}
|
|
1089
|
+
`[auth-backend] Admin created credential user: ${email}`,
|
|
815
1090
|
);
|
|
816
1091
|
|
|
817
1092
|
return { userId };
|
|
818
|
-
}
|
|
1093
|
+
},
|
|
819
1094
|
);
|
|
820
1095
|
|
|
821
1096
|
// ==========================================================================
|
|
@@ -833,8 +1108,8 @@ export const createAuthRouter = (
|
|
|
833
1108
|
.where(
|
|
834
1109
|
inArray(
|
|
835
1110
|
schema.applicationRole.applicationId,
|
|
836
|
-
apps.map((a) => a.id)
|
|
837
|
-
)
|
|
1111
|
+
apps.map((a) => a.id),
|
|
1112
|
+
),
|
|
838
1113
|
);
|
|
839
1114
|
|
|
840
1115
|
return apps.map((app) => ({
|
|
@@ -868,7 +1143,7 @@ export const createAuthRouter = (
|
|
|
868
1143
|
const now = new Date();
|
|
869
1144
|
|
|
870
1145
|
// Default role for all applications
|
|
871
|
-
const defaultRole =
|
|
1146
|
+
const defaultRole = APPLICATIONS_ROLE_ID;
|
|
872
1147
|
|
|
873
1148
|
await internalDb.transaction(async (tx) => {
|
|
874
1149
|
// Create application
|
|
@@ -890,7 +1165,7 @@ export const createAuthRouter = (
|
|
|
890
1165
|
});
|
|
891
1166
|
|
|
892
1167
|
context.logger.info(
|
|
893
|
-
`[auth-backend] Created application: ${name} (${id})
|
|
1168
|
+
`[auth-backend] Created application: ${name} (${id})`,
|
|
894
1169
|
);
|
|
895
1170
|
|
|
896
1171
|
return {
|
|
@@ -904,7 +1179,7 @@ export const createAuthRouter = (
|
|
|
904
1179
|
},
|
|
905
1180
|
secret: `ck_${id}_${secret}`, // Full secret - only shown once!
|
|
906
1181
|
};
|
|
907
|
-
}
|
|
1182
|
+
},
|
|
908
1183
|
);
|
|
909
1184
|
|
|
910
1185
|
const updateApplication = os.updateApplication.handler(async ({ input }) => {
|
|
@@ -953,7 +1228,7 @@ export const createAuthRouter = (
|
|
|
953
1228
|
roles.map((roleId) => ({
|
|
954
1229
|
applicationId: id,
|
|
955
1230
|
roleId,
|
|
956
|
-
}))
|
|
1231
|
+
})),
|
|
957
1232
|
);
|
|
958
1233
|
}
|
|
959
1234
|
}
|
|
@@ -982,7 +1257,7 @@ export const createAuthRouter = (
|
|
|
982
1257
|
.where(eq(schema.application.id, id));
|
|
983
1258
|
|
|
984
1259
|
context.logger.info(`[auth-backend] Deleted application: ${id}`);
|
|
985
|
-
}
|
|
1260
|
+
},
|
|
986
1261
|
);
|
|
987
1262
|
|
|
988
1263
|
const regenerateApplicationSecret = os.regenerateApplicationSecret.handler(
|
|
@@ -1009,11 +1284,11 @@ export const createAuthRouter = (
|
|
|
1009
1284
|
.where(eq(schema.application.id, id));
|
|
1010
1285
|
|
|
1011
1286
|
context.logger.info(
|
|
1012
|
-
`[auth-backend] Regenerated secret for application: ${id}
|
|
1287
|
+
`[auth-backend] Regenerated secret for application: ${id}`,
|
|
1013
1288
|
);
|
|
1014
1289
|
|
|
1015
1290
|
return { secret: `ck_${id}_${secret}` };
|
|
1016
|
-
}
|
|
1291
|
+
},
|
|
1017
1292
|
);
|
|
1018
1293
|
|
|
1019
1294
|
// ==========================================================================
|
|
@@ -1158,10 +1433,10 @@ export const createAuthRouter = (
|
|
|
1158
1433
|
.where(
|
|
1159
1434
|
and(
|
|
1160
1435
|
eq(schema.userTeam.userId, input.userId),
|
|
1161
|
-
eq(schema.userTeam.teamId, input.teamId)
|
|
1162
|
-
)
|
|
1436
|
+
eq(schema.userTeam.teamId, input.teamId),
|
|
1437
|
+
),
|
|
1163
1438
|
);
|
|
1164
|
-
}
|
|
1439
|
+
},
|
|
1165
1440
|
);
|
|
1166
1441
|
|
|
1167
1442
|
const addTeamManager = os.addTeamManager.handler(async ({ input }) => {
|
|
@@ -1177,8 +1452,8 @@ export const createAuthRouter = (
|
|
|
1177
1452
|
.where(
|
|
1178
1453
|
and(
|
|
1179
1454
|
eq(schema.teamManager.userId, input.userId),
|
|
1180
|
-
eq(schema.teamManager.teamId, input.teamId)
|
|
1181
|
-
)
|
|
1455
|
+
eq(schema.teamManager.teamId, input.teamId),
|
|
1456
|
+
),
|
|
1182
1457
|
);
|
|
1183
1458
|
});
|
|
1184
1459
|
|
|
@@ -1189,13 +1464,13 @@ export const createAuthRouter = (
|
|
|
1189
1464
|
.from(schema.resourceTeamAccess)
|
|
1190
1465
|
.innerJoin(
|
|
1191
1466
|
schema.team,
|
|
1192
|
-
eq(schema.resourceTeamAccess.teamId, schema.team.id)
|
|
1467
|
+
eq(schema.resourceTeamAccess.teamId, schema.team.id),
|
|
1193
1468
|
)
|
|
1194
1469
|
.where(
|
|
1195
1470
|
and(
|
|
1196
1471
|
eq(schema.resourceTeamAccess.resourceType, input.resourceType),
|
|
1197
|
-
eq(schema.resourceTeamAccess.resourceId, input.resourceId)
|
|
1198
|
-
)
|
|
1472
|
+
eq(schema.resourceTeamAccess.resourceId, input.resourceId),
|
|
1473
|
+
),
|
|
1199
1474
|
);
|
|
1200
1475
|
return rows.map((r) => ({
|
|
1201
1476
|
teamId: r.resource_team_access.teamId,
|
|
@@ -1203,7 +1478,7 @@ export const createAuthRouter = (
|
|
|
1203
1478
|
canRead: r.resource_team_access.canRead,
|
|
1204
1479
|
canManage: r.resource_team_access.canManage,
|
|
1205
1480
|
}));
|
|
1206
|
-
}
|
|
1481
|
+
},
|
|
1207
1482
|
);
|
|
1208
1483
|
|
|
1209
1484
|
const setResourceTeamAccess = os.setResourceTeamAccess.handler(
|
|
@@ -1229,7 +1504,7 @@ export const createAuthRouter = (
|
|
|
1229
1504
|
canManage: canManage ?? false,
|
|
1230
1505
|
},
|
|
1231
1506
|
});
|
|
1232
|
-
}
|
|
1507
|
+
},
|
|
1233
1508
|
);
|
|
1234
1509
|
|
|
1235
1510
|
const removeResourceTeamAccess = os.removeResourceTeamAccess.handler(
|
|
@@ -1240,10 +1515,10 @@ export const createAuthRouter = (
|
|
|
1240
1515
|
and(
|
|
1241
1516
|
eq(schema.resourceTeamAccess.resourceType, input.resourceType),
|
|
1242
1517
|
eq(schema.resourceTeamAccess.resourceId, input.resourceId),
|
|
1243
|
-
eq(schema.resourceTeamAccess.teamId, input.teamId)
|
|
1244
|
-
)
|
|
1518
|
+
eq(schema.resourceTeamAccess.teamId, input.teamId),
|
|
1519
|
+
),
|
|
1245
1520
|
);
|
|
1246
|
-
}
|
|
1521
|
+
},
|
|
1247
1522
|
);
|
|
1248
1523
|
|
|
1249
1524
|
// Resource-level access settings
|
|
@@ -1255,12 +1530,12 @@ export const createAuthRouter = (
|
|
|
1255
1530
|
.where(
|
|
1256
1531
|
and(
|
|
1257
1532
|
eq(schema.resourceAccessSettings.resourceType, input.resourceType),
|
|
1258
|
-
eq(schema.resourceAccessSettings.resourceId, input.resourceId)
|
|
1259
|
-
)
|
|
1533
|
+
eq(schema.resourceAccessSettings.resourceId, input.resourceId),
|
|
1534
|
+
),
|
|
1260
1535
|
)
|
|
1261
1536
|
.limit(1);
|
|
1262
1537
|
return { teamOnly: rows[0]?.teamOnly ?? false };
|
|
1263
|
-
}
|
|
1538
|
+
},
|
|
1264
1539
|
);
|
|
1265
1540
|
|
|
1266
1541
|
const setResourceAccessSettings = os.setResourceAccessSettings.handler(
|
|
@@ -1276,7 +1551,7 @@ export const createAuthRouter = (
|
|
|
1276
1551
|
],
|
|
1277
1552
|
set: { teamOnly },
|
|
1278
1553
|
});
|
|
1279
|
-
}
|
|
1554
|
+
},
|
|
1280
1555
|
);
|
|
1281
1556
|
|
|
1282
1557
|
// S2S Endpoints for middleware
|
|
@@ -1297,8 +1572,8 @@ export const createAuthRouter = (
|
|
|
1297
1572
|
.where(
|
|
1298
1573
|
and(
|
|
1299
1574
|
eq(schema.resourceTeamAccess.resourceType, resourceType),
|
|
1300
|
-
eq(schema.resourceTeamAccess.resourceId, resourceId)
|
|
1301
|
-
)
|
|
1575
|
+
eq(schema.resourceTeamAccess.resourceId, resourceId),
|
|
1576
|
+
),
|
|
1302
1577
|
);
|
|
1303
1578
|
|
|
1304
1579
|
// No grants = global access applies
|
|
@@ -1311,8 +1586,8 @@ export const createAuthRouter = (
|
|
|
1311
1586
|
.where(
|
|
1312
1587
|
and(
|
|
1313
1588
|
eq(schema.resourceAccessSettings.resourceType, resourceType),
|
|
1314
|
-
eq(schema.resourceAccessSettings.resourceId, resourceId)
|
|
1315
|
-
)
|
|
1589
|
+
eq(schema.resourceAccessSettings.resourceId, resourceId),
|
|
1590
|
+
),
|
|
1316
1591
|
)
|
|
1317
1592
|
.limit(1);
|
|
1318
1593
|
const isTeamOnly = settingsRows[0]?.teamOnly ?? false;
|
|
@@ -1339,10 +1614,10 @@ export const createAuthRouter = (
|
|
|
1339
1614
|
|
|
1340
1615
|
const field = action === "manage" ? "canManage" : "canRead";
|
|
1341
1616
|
const hasAccess = grants.some(
|
|
1342
|
-
(g) => userTeamIds.has(g.teamId) && g[field]
|
|
1617
|
+
(g) => userTeamIds.has(g.teamId) && g[field],
|
|
1343
1618
|
);
|
|
1344
1619
|
return { hasAccess };
|
|
1345
|
-
}
|
|
1620
|
+
},
|
|
1346
1621
|
);
|
|
1347
1622
|
|
|
1348
1623
|
const getAccessibleResourceIds = os.getAccessibleResourceIds.handler(
|
|
@@ -1364,8 +1639,8 @@ export const createAuthRouter = (
|
|
|
1364
1639
|
.where(
|
|
1365
1640
|
and(
|
|
1366
1641
|
eq(schema.resourceTeamAccess.resourceType, resourceType),
|
|
1367
|
-
inArray(schema.resourceTeamAccess.resourceId, resourceIds)
|
|
1368
|
-
)
|
|
1642
|
+
inArray(schema.resourceTeamAccess.resourceId, resourceIds),
|
|
1643
|
+
),
|
|
1369
1644
|
);
|
|
1370
1645
|
|
|
1371
1646
|
// Get resource-level settings for teamOnly
|
|
@@ -1375,11 +1650,11 @@ export const createAuthRouter = (
|
|
|
1375
1650
|
.where(
|
|
1376
1651
|
and(
|
|
1377
1652
|
eq(schema.resourceAccessSettings.resourceType, resourceType),
|
|
1378
|
-
inArray(schema.resourceAccessSettings.resourceId, resourceIds)
|
|
1379
|
-
)
|
|
1653
|
+
inArray(schema.resourceAccessSettings.resourceId, resourceIds),
|
|
1654
|
+
),
|
|
1380
1655
|
);
|
|
1381
1656
|
const teamOnlyByResource = new Map(
|
|
1382
|
-
settingsRows.map((s) => [s.resourceId, s.teamOnly])
|
|
1657
|
+
settingsRows.map((s) => [s.resourceId, s.teamOnly]),
|
|
1383
1658
|
);
|
|
1384
1659
|
|
|
1385
1660
|
// Get user's teams
|
|
@@ -1414,10 +1689,10 @@ export const createAuthRouter = (
|
|
|
1414
1689
|
const isTeamOnly = teamOnlyByResource.get(id) ?? false;
|
|
1415
1690
|
if (!isTeamOnly && hasGlobalAccess) return true;
|
|
1416
1691
|
return resourceGrants.some(
|
|
1417
|
-
(g) => userTeamIds.has(g.teamId) && g[field]
|
|
1692
|
+
(g) => userTeamIds.has(g.teamId) && g[field],
|
|
1418
1693
|
);
|
|
1419
1694
|
});
|
|
1420
|
-
}
|
|
1695
|
+
},
|
|
1421
1696
|
);
|
|
1422
1697
|
|
|
1423
1698
|
const deleteResourceGrants = os.deleteResourceGrants.handler(
|
|
@@ -1427,10 +1702,10 @@ export const createAuthRouter = (
|
|
|
1427
1702
|
.where(
|
|
1428
1703
|
and(
|
|
1429
1704
|
eq(schema.resourceTeamAccess.resourceType, input.resourceType),
|
|
1430
|
-
eq(schema.resourceTeamAccess.resourceId, input.resourceId)
|
|
1431
|
-
)
|
|
1705
|
+
eq(schema.resourceTeamAccess.resourceId, input.resourceId),
|
|
1706
|
+
),
|
|
1432
1707
|
);
|
|
1433
|
-
}
|
|
1708
|
+
},
|
|
1434
1709
|
);
|
|
1435
1710
|
|
|
1436
1711
|
return os.router({
|
|
@@ -1450,6 +1725,10 @@ export const createAuthRouter = (
|
|
|
1450
1725
|
getRegistrationSchema,
|
|
1451
1726
|
getRegistrationStatus,
|
|
1452
1727
|
setRegistrationStatus,
|
|
1728
|
+
getOnboardingStatus,
|
|
1729
|
+
completeOnboarding,
|
|
1730
|
+
getCurrentUserProfile,
|
|
1731
|
+
updateCurrentUser,
|
|
1453
1732
|
getAnonymousAccessRules,
|
|
1454
1733
|
getUserById,
|
|
1455
1734
|
filterUsersByAccessRule,
|