@seamless-auth/express 0.1.2 → 0.3.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.
Files changed (51) hide show
  1. package/README.md +18 -0
  2. package/dist/createServer.d.ts +78 -0
  3. package/dist/createServer.d.ts.map +1 -0
  4. package/dist/getSeamlessUser.d.ts +4 -0
  5. package/dist/getSeamlessUser.d.ts.map +1 -0
  6. package/dist/handlers/admin.d.ts +14 -0
  7. package/dist/handlers/admin.d.ts.map +1 -0
  8. package/dist/handlers/bootstrapAdmininvite.d.ts +4 -0
  9. package/dist/handlers/bootstrapAdmininvite.d.ts.map +1 -0
  10. package/dist/handlers/finishLogin.d.ts +6 -0
  11. package/dist/handlers/finishLogin.d.ts.map +1 -0
  12. package/dist/handlers/finishRegister.d.ts +6 -0
  13. package/dist/handlers/finishRegister.d.ts.map +1 -0
  14. package/dist/handlers/internalMetrics.d.ts +9 -0
  15. package/dist/handlers/internalMetrics.d.ts.map +1 -0
  16. package/dist/handlers/login.d.ts +4 -0
  17. package/dist/handlers/login.d.ts.map +1 -0
  18. package/dist/handlers/logout.d.ts +4 -0
  19. package/dist/handlers/logout.d.ts.map +1 -0
  20. package/dist/handlers/me.d.ts +6 -0
  21. package/dist/handlers/me.d.ts.map +1 -0
  22. package/dist/handlers/pollMagicLinkConfirmation.d.ts +6 -0
  23. package/dist/handlers/pollMagicLinkConfirmation.d.ts.map +1 -0
  24. package/dist/handlers/register.d.ts +4 -0
  25. package/dist/handlers/register.d.ts.map +1 -0
  26. package/dist/handlers/requestMagicLink.d.ts +7 -0
  27. package/dist/handlers/requestMagicLink.d.ts.map +1 -0
  28. package/dist/handlers/requestOtp.d.ts +7 -0
  29. package/dist/handlers/requestOtp.d.ts.map +1 -0
  30. package/dist/handlers/sessions.d.ts +6 -0
  31. package/dist/handlers/sessions.d.ts.map +1 -0
  32. package/dist/handlers/systemConfig.d.ts +6 -0
  33. package/dist/handlers/systemConfig.d.ts.map +1 -0
  34. package/dist/index.d.ts +9 -197
  35. package/dist/index.d.ts.map +1 -0
  36. package/dist/index.js +621 -12
  37. package/dist/internal/buildAuthorization.d.ts +6 -0
  38. package/dist/internal/buildAuthorization.d.ts.map +1 -0
  39. package/dist/internal/cookie.d.ts +17 -0
  40. package/dist/internal/cookie.d.ts.map +1 -0
  41. package/dist/internal/deliverAuthMessage.d.ts +6 -0
  42. package/dist/internal/deliverAuthMessage.d.ts.map +1 -0
  43. package/dist/messaging.d.ts +98 -0
  44. package/dist/messaging.d.ts.map +1 -0
  45. package/dist/middleware/ensureCookies.d.ts +16 -0
  46. package/dist/middleware/ensureCookies.d.ts.map +1 -0
  47. package/dist/middleware/requireAuth.d.ts +69 -0
  48. package/dist/middleware/requireAuth.d.ts.map +1 -0
  49. package/dist/middleware/requireRole.d.ts +36 -0
  50. package/dist/middleware/requireRole.d.ts.map +1 -0
  51. package/package.json +7 -5
package/dist/index.js CHANGED
@@ -139,11 +139,12 @@ import { finishLoginHandler } from "@seamless-auth/core/handlers/finishLogin";
139
139
  // src/internal/buildAuthorization.ts
140
140
  import { createServiceToken } from "@seamless-auth/core";
141
141
  function buildServiceAuthorization(req, opts) {
142
- if (!req.cookiePayload?.sub && !req.user.sub) {
142
+ const subject = req.cookiePayload?.sub || req.user?.sub;
143
+ if (!subject) {
143
144
  return void 0;
144
145
  }
145
146
  const token = createServiceToken({
146
- subject: req.cookiePayload?.sub || req.user.sub,
147
+ subject,
147
148
  issuer: opts.issuer,
148
149
  audience: opts.audience,
149
150
  serviceSecret: opts.serviceSecret,
@@ -194,6 +195,174 @@ async function finishLogin(req, res, opts) {
194
195
 
195
196
  // src/handlers/register.ts
196
197
  import { registerHandler } from "@seamless-auth/core/handlers/register";
198
+
199
+ // src/internal/deliverAuthMessage.ts
200
+ function applyEmailOverride(override, input, defaults, appName) {
201
+ return override ? override(input, defaults, { appName }) : defaults;
202
+ }
203
+ function applySmsOverride(override, input, defaults, appName) {
204
+ return override ? override(input, defaults, { appName }) : defaults;
205
+ }
206
+ function buildOtpEmailMessage(input, messaging) {
207
+ const appName = messaging.defaults?.appName ?? "Seamless Auth";
208
+ return applyEmailOverride(
209
+ messaging.overrides?.otpEmail,
210
+ {
211
+ to: input.to,
212
+ token: input.token,
213
+ from: messaging.defaults?.emailFrom,
214
+ subject: `${appName} - Verify your email`
215
+ },
216
+ {
217
+ to: input.to,
218
+ from: messaging.defaults?.emailFrom,
219
+ subject: `${appName} - Verify your email`,
220
+ text: `Verify your account with ${appName}.
221
+
222
+ Your verification code is: ${input.token}
223
+
224
+ If you did not request this code, you can safely ignore this message.`,
225
+ html: `<div><h1>Verify your account with ${appName}</h1><p>Please use the verification code below:</p><p><strong>${input.token}</strong></p><p>If you did not request this code, you can safely ignore this message.</p></div>`
226
+ },
227
+ appName
228
+ );
229
+ }
230
+ function buildOtpSmsMessage(input, messaging) {
231
+ const appName = messaging.defaults?.appName ?? "Seamless Auth";
232
+ return applySmsOverride(
233
+ messaging.overrides?.otpSms,
234
+ {
235
+ to: input.to,
236
+ token: input.token,
237
+ from: messaging.defaults?.smsFrom
238
+ },
239
+ {
240
+ to: input.to,
241
+ from: messaging.defaults?.smsFrom,
242
+ body: `Your ${appName} verification code is: ${input.token}. No one will ever ask you for this code. Do not share it.`
243
+ },
244
+ appName
245
+ );
246
+ }
247
+ function buildMagicLinkMessage(input, messaging) {
248
+ const appName = messaging.defaults?.appName ?? "Seamless Auth";
249
+ return applyEmailOverride(
250
+ messaging.overrides?.magicLinkEmail,
251
+ {
252
+ to: input.to,
253
+ magicLinkUrl: input.magicLinkUrl,
254
+ token: input.token,
255
+ from: messaging.defaults?.emailFrom,
256
+ subject: `${appName} - Your sign-in link`
257
+ },
258
+ {
259
+ to: input.to,
260
+ from: messaging.defaults?.emailFrom,
261
+ subject: `${appName} - Your sign-in link`,
262
+ text: `Use the link below to sign in to ${appName}:
263
+
264
+ ${input.magicLinkUrl}
265
+
266
+ If you did not request this email, you can safely ignore it.`,
267
+ html: `<div><h1>Sign in to ${appName}</h1><p>Use the link below to complete sign-in:</p><p><a href="${input.magicLinkUrl}">${input.magicLinkUrl}</a></p><p>If you did not request this email, you can safely ignore it.</p></div>`
268
+ },
269
+ appName
270
+ );
271
+ }
272
+ function buildBootstrapInviteMessage(input, messaging) {
273
+ const appName = messaging.defaults?.appName ?? "Seamless Auth";
274
+ return applyEmailOverride(
275
+ messaging.overrides?.bootstrapInviteEmail,
276
+ {
277
+ to: input.to,
278
+ inviteUrl: input.inviteUrl,
279
+ token: input.token,
280
+ from: messaging.defaults?.emailFrom,
281
+ subject: `${appName} - Bootstrap invite`
282
+ },
283
+ {
284
+ to: input.to,
285
+ from: messaging.defaults?.emailFrom,
286
+ subject: `${appName} - Bootstrap invite`,
287
+ text: `You have been invited to bootstrap ${appName}.
288
+
289
+ Use the link below to continue:
290
+ ${input.inviteUrl}`,
291
+ html: `<div><h1>Bootstrap invite for ${appName}</h1><p>Use the link below to continue:</p><p><a href="${input.inviteUrl}">${input.inviteUrl}</a></p></div>`
292
+ },
293
+ appName
294
+ );
295
+ }
296
+ async function deliverAuthMessage(messaging, delivery) {
297
+ if (!messaging || !delivery) {
298
+ return;
299
+ }
300
+ switch (delivery.kind) {
301
+ case "otp_email":
302
+ if (messaging.handlers?.sendOtpEmail) {
303
+ await messaging.handlers.sendOtpEmail({
304
+ to: delivery.to,
305
+ token: delivery.token,
306
+ from: messaging.defaults?.emailFrom
307
+ });
308
+ return;
309
+ }
310
+ if (!messaging.email) {
311
+ throw new Error("Missing email transport for OTP email delivery.");
312
+ }
313
+ await messaging.email.send(buildOtpEmailMessage(delivery, messaging));
314
+ return;
315
+ case "otp_sms":
316
+ if (messaging.handlers?.sendOtpSms) {
317
+ await messaging.handlers.sendOtpSms({
318
+ to: delivery.to,
319
+ token: delivery.token,
320
+ from: messaging.defaults?.smsFrom
321
+ });
322
+ return;
323
+ }
324
+ if (!messaging.sms) {
325
+ throw new Error("Missing SMS transport for OTP SMS delivery.");
326
+ }
327
+ await messaging.sms.send(buildOtpSmsMessage(delivery, messaging));
328
+ return;
329
+ case "magic_link_email":
330
+ if (messaging.handlers?.sendMagicLinkEmail) {
331
+ await messaging.handlers.sendMagicLinkEmail({
332
+ to: delivery.to,
333
+ token: delivery.token,
334
+ magicLinkUrl: delivery.magicLinkUrl,
335
+ from: messaging.defaults?.emailFrom
336
+ });
337
+ return;
338
+ }
339
+ if (!messaging.email) {
340
+ throw new Error("Missing email transport for magic link delivery.");
341
+ }
342
+ await messaging.email.send(buildMagicLinkMessage(delivery, messaging));
343
+ return;
344
+ case "bootstrap_invite_email":
345
+ if (messaging.handlers?.sendBootstrapInviteEmail) {
346
+ await messaging.handlers.sendBootstrapInviteEmail({
347
+ to: delivery.to,
348
+ inviteUrl: delivery.inviteUrl,
349
+ from: messaging.defaults?.emailFrom
350
+ });
351
+ return;
352
+ }
353
+ if (!messaging.email) {
354
+ throw new Error("Missing email transport for bootstrap invite delivery.");
355
+ }
356
+ await messaging.email.send(buildBootstrapInviteMessage(delivery, messaging));
357
+ return;
358
+ }
359
+ }
360
+ function stripDelivery(body) {
361
+ const { delivery: _delivery, ...rest } = body;
362
+ return rest;
363
+ }
364
+
365
+ // src/handlers/register.ts
197
366
  async function register(req, res, opts) {
198
367
  const cookieSigner = {
199
368
  secret: opts.cookieSecret,
@@ -205,7 +374,8 @@ async function register(req, res, opts) {
205
374
  {
206
375
  authServerUrl: opts.authServerUrl,
207
376
  cookieDomain: opts.cookieDomain,
208
- registrationCookieName: opts.registrationCookieName
377
+ registrationCookieName: opts.registrationCookieName,
378
+ externalDelivery: Boolean(opts.messaging)
209
379
  }
210
380
  );
211
381
  if (!cookieSigner.secret) {
@@ -216,9 +386,9 @@ async function register(req, res, opts) {
216
386
  setSessionCookie(
217
387
  res,
218
388
  {
219
- name: opts.registrationCookieName || "seamless-auth-registraion",
389
+ name: c.name,
220
390
  payload: c.value,
221
- domain: c.domain,
391
+ domain: c.domain ?? opts.cookieDomain,
222
392
  ttlSeconds: c.ttl
223
393
  },
224
394
  cookieSigner
@@ -228,11 +398,45 @@ async function register(req, res, opts) {
228
398
  if (result.error) {
229
399
  return res.status(result.status).json(result.error);
230
400
  }
401
+ if (result.body && typeof result.body === "object" && "delivery" in result.body) {
402
+ await deliverAuthMessage(
403
+ opts.messaging,
404
+ result.body.delivery
405
+ );
406
+ return res.status(result.status).json(stripDelivery(result.body)).end();
407
+ }
231
408
  res.status(result.status).json(result.body).end();
232
409
  }
233
410
 
411
+ // src/handlers/requestOtp.ts
412
+ import { requestOtpHandler } from "@seamless-auth/core/handlers/requestOtpHandler";
413
+ async function requestOtp(req, res, opts, kind) {
414
+ const result = await requestOtpHandler(
415
+ {
416
+ kind,
417
+ authorization: buildServiceAuthorization(req, opts)
418
+ },
419
+ {
420
+ authServerUrl: opts.authServerUrl,
421
+ externalDelivery: Boolean(opts.messaging)
422
+ }
423
+ );
424
+ if (result.error) {
425
+ return res.status(result.status).json(result.error);
426
+ }
427
+ if (result.body && typeof result.body === "object" && "delivery" in result.body) {
428
+ await deliverAuthMessage(
429
+ opts.messaging,
430
+ result.body.delivery
431
+ );
432
+ return res.status(result.status).json(stripDelivery(result.body));
433
+ }
434
+ return res.status(result.status).json(result.body);
435
+ }
436
+
234
437
  // src/handlers/finishRegister.ts
235
438
  import { finishRegisterHandler } from "@seamless-auth/core/handlers/finishRegister";
439
+ import { verifyCookieJwt } from "@seamless-auth/core";
236
440
  async function finishRegister(req, res, opts) {
237
441
  const cookieSigner = {
238
442
  secret: opts.cookieSecret,
@@ -240,8 +444,24 @@ async function finishRegister(req, res, opts) {
240
444
  sameSite: process.env.NODE_ENV === "production" ? "none" : "lax"
241
445
  };
242
446
  const authorization = buildServiceAuthorization(req, opts);
447
+ const bootstrapToken = req.cookies?.["seamless_bootstrap_token"];
448
+ const headers = {};
449
+ if (bootstrapToken) {
450
+ const payload = verifyCookieJwt(bootstrapToken, opts.cookieSecret);
451
+ if (!payload || !payload.sub) {
452
+ res.status(401).json({
453
+ error: "Invalid or expired session"
454
+ });
455
+ return;
456
+ }
457
+ headers["cookie"] = `seamless_bootstrap_token=${payload.sub}`;
458
+ }
243
459
  const result = await finishRegisterHandler(
244
- { body: req.body, authorization },
460
+ {
461
+ body: req.body,
462
+ authorization,
463
+ headers
464
+ },
245
465
  {
246
466
  authServerUrl: opts.authServerUrl,
247
467
  cookieDomain: opts.cookieDomain,
@@ -346,10 +566,305 @@ async function pollMagicLinkConfirmation(req, res, opts) {
346
566
  res.status(result.status).json(result.body).end();
347
567
  }
348
568
 
569
+ // src/handlers/requestMagicLink.ts
570
+ import { requestMagicLinkHandler } from "@seamless-auth/core/handlers/requestMagicLinkHandler";
571
+ async function requestMagicLink(req, res, opts) {
572
+ const result = await requestMagicLinkHandler(
573
+ {
574
+ authorization: buildServiceAuthorization(req, opts)
575
+ },
576
+ {
577
+ authServerUrl: opts.authServerUrl,
578
+ externalDelivery: Boolean(opts.messaging)
579
+ }
580
+ );
581
+ if (result.error) {
582
+ return res.status(result.status).json(result.error);
583
+ }
584
+ if (result.body && typeof result.body === "object" && "delivery" in result.body) {
585
+ await deliverAuthMessage(
586
+ opts.messaging,
587
+ result.body.delivery
588
+ );
589
+ return res.status(result.status).json(stripDelivery(result.body));
590
+ }
591
+ return res.status(result.status).json(result.body);
592
+ }
593
+
594
+ // src/handlers/admin.ts
595
+ import {
596
+ getUsersHandler,
597
+ createUserHandler,
598
+ deleteUserHandler,
599
+ updateUserHandler,
600
+ getUserDetailHandler,
601
+ getUserAnomaliesHandler,
602
+ getAuthEventsHandler,
603
+ getCredentialCountHandler,
604
+ listAllSessionsHandler,
605
+ listUserSessionsHandler,
606
+ revokeAllUserSessionsHandler
607
+ } from "@seamless-auth/core/handlers/admin";
608
+ function handle(res, result) {
609
+ if (result.error) {
610
+ return res.status(result.status).json({ error: result.error });
611
+ }
612
+ return res.status(result.status).json(result.body);
613
+ }
614
+ var getUsers = async (req, res, opts) => handle(
615
+ res,
616
+ await getUsersHandler({
617
+ authServerUrl: opts.authServerUrl,
618
+ authorization: buildServiceAuthorization(req, opts)
619
+ })
620
+ );
621
+ var createUser = async (req, res, opts) => handle(
622
+ res,
623
+ await createUserHandler({
624
+ authServerUrl: opts.authServerUrl,
625
+ authorization: buildServiceAuthorization(req, opts),
626
+ body: req.body
627
+ })
628
+ );
629
+ var deleteUser = async (req, res, opts) => handle(
630
+ res,
631
+ await deleteUserHandler({
632
+ authServerUrl: opts.authServerUrl,
633
+ authorization: buildServiceAuthorization(req, opts)
634
+ })
635
+ );
636
+ var updateUser = async (req, res, opts) => handle(
637
+ res,
638
+ await updateUserHandler(req.params.userId, {
639
+ authServerUrl: opts.authServerUrl,
640
+ authorization: buildServiceAuthorization(req, opts),
641
+ body: req.body
642
+ })
643
+ );
644
+ var getUserDetail = async (req, res, opts) => handle(
645
+ res,
646
+ await getUserDetailHandler(req.params.userId, {
647
+ authServerUrl: opts.authServerUrl,
648
+ authorization: buildServiceAuthorization(req, opts)
649
+ })
650
+ );
651
+ var getUserAnomalies = async (req, res, opts) => handle(
652
+ res,
653
+ await getUserAnomaliesHandler(req.params.userId, {
654
+ authServerUrl: opts.authServerUrl,
655
+ authorization: buildServiceAuthorization(req, opts)
656
+ })
657
+ );
658
+ var getAuthEvents = async (req, res, opts) => handle(
659
+ res,
660
+ await getAuthEventsHandler({
661
+ authServerUrl: opts.authServerUrl,
662
+ authorization: buildServiceAuthorization(req, opts),
663
+ query: req.query
664
+ })
665
+ );
666
+ var getCredentialCount = async (req, res, opts) => handle(
667
+ res,
668
+ await getCredentialCountHandler({
669
+ authServerUrl: opts.authServerUrl,
670
+ authorization: buildServiceAuthorization(req, opts)
671
+ })
672
+ );
673
+ var listAllSessions = async (req, res, opts) => handle(
674
+ res,
675
+ await listAllSessionsHandler({
676
+ authServerUrl: opts.authServerUrl,
677
+ authorization: buildServiceAuthorization(req, opts),
678
+ query: req.query
679
+ })
680
+ );
681
+ var listUserSessions = async (req, res, opts) => handle(
682
+ res,
683
+ await listUserSessionsHandler(req.params.userId, {
684
+ authServerUrl: opts.authServerUrl,
685
+ authorization: buildServiceAuthorization(req, opts)
686
+ })
687
+ );
688
+ var revokeAllUserSessions = async (req, res, opts) => handle(
689
+ res,
690
+ await revokeAllUserSessionsHandler(req.params.userId, {
691
+ authServerUrl: opts.authServerUrl,
692
+ authorization: buildServiceAuthorization(req, opts)
693
+ })
694
+ );
695
+
349
696
  // src/createServer.ts
350
697
  import {
351
698
  authFetch
352
699
  } from "@seamless-auth/core";
700
+
701
+ // src/handlers/bootstrapAdmininvite.ts
702
+ import { bootstrapAdminInviteHandler } from "@seamless-auth/core/handlers/bootstrapAdminInvite";
703
+ async function bootstrapAdminInvite(req, res, opts) {
704
+ const result = await bootstrapAdminInviteHandler({
705
+ authServerUrl: opts.authServerUrl,
706
+ email: req.body.email,
707
+ authorization: req.headers["authorization"],
708
+ externalDelivery: Boolean(opts.messaging)
709
+ });
710
+ if (result.error) {
711
+ return res.status(result.status).json({ error: result.error });
712
+ }
713
+ if (result.body && typeof result.body === "object" && "delivery" in result.body) {
714
+ await deliverAuthMessage(
715
+ opts.messaging,
716
+ result.body.delivery
717
+ );
718
+ return res.status(result.status).json(stripDelivery(result.body));
719
+ }
720
+ res.status(result.status).json(result.body);
721
+ }
722
+
723
+ // src/handlers/systemConfig.ts
724
+ import {
725
+ getAvailableRolesHandler,
726
+ getSystemConfigAdminHandler,
727
+ updateSystemConfigHandler
728
+ } from "@seamless-auth/core/handlers/systemConfig";
729
+ async function getAvailableRoles(req, res, opts) {
730
+ const authorization = buildServiceAuthorization(req, opts);
731
+ const result = await getAvailableRolesHandler({
732
+ authServerUrl: opts.authServerUrl,
733
+ authorization
734
+ });
735
+ if (result.error) {
736
+ return res.status(result.status).json({ error: result.error });
737
+ }
738
+ res.status(result.status).json(result.body);
739
+ }
740
+ async function getSystemConfigAdmin(req, res, opts) {
741
+ const authorization = buildServiceAuthorization(req, opts);
742
+ const result = await getSystemConfigAdminHandler({
743
+ authServerUrl: opts.authServerUrl,
744
+ authorization
745
+ });
746
+ if (result.error) {
747
+ return res.status(result.status).json({ error: result.error });
748
+ }
749
+ res.status(result.status).json(result.body);
750
+ }
751
+ async function updateSystemConfig(req, res, opts) {
752
+ const authorization = buildServiceAuthorization(req, opts);
753
+ const result = await updateSystemConfigHandler({
754
+ authServerUrl: opts.authServerUrl,
755
+ authorization,
756
+ payload: req.body
757
+ });
758
+ if (result.error) {
759
+ return res.status(result.status).json({ error: result.error });
760
+ }
761
+ res.status(result.status).json(result.body);
762
+ }
763
+
764
+ // src/handlers/internalMetrics.ts
765
+ import {
766
+ getAuthEventSummaryHandler,
767
+ getAuthEventTimeseriesHandler,
768
+ getLoginStatsHandler,
769
+ getSecurityAnomaliesHandler,
770
+ getDashboardMetricsHandler,
771
+ getGroupedEventSummaryHandler
772
+ } from "@seamless-auth/core/handlers/internalMetrics";
773
+ function handle2(res, result) {
774
+ if (result.error) {
775
+ return res.status(result.status).json({ error: result.error });
776
+ }
777
+ return res.status(result.status).json(result.body);
778
+ }
779
+ async function getAuthEventSummary(req, res, opts) {
780
+ const authorization = buildServiceAuthorization(req, opts);
781
+ const result = await getAuthEventSummaryHandler({
782
+ authServerUrl: opts.authServerUrl,
783
+ authorization,
784
+ query: req.query
785
+ });
786
+ return handle2(res, result);
787
+ }
788
+ async function getAuthEventTimeseries(req, res, opts) {
789
+ const authorization = buildServiceAuthorization(req, opts);
790
+ const result = await getAuthEventTimeseriesHandler({
791
+ authServerUrl: opts.authServerUrl,
792
+ authorization,
793
+ query: req.query
794
+ });
795
+ return handle2(res, result);
796
+ }
797
+ async function getLoginStats(req, res, opts) {
798
+ const authorization = buildServiceAuthorization(req, opts);
799
+ const result = await getLoginStatsHandler({
800
+ authServerUrl: opts.authServerUrl,
801
+ authorization
802
+ });
803
+ return handle2(res, result);
804
+ }
805
+ async function getSecurityAnomalies(req, res, opts) {
806
+ const authorization = buildServiceAuthorization(req, opts);
807
+ const result = await getSecurityAnomaliesHandler({
808
+ authServerUrl: opts.authServerUrl,
809
+ authorization
810
+ });
811
+ return handle2(res, result);
812
+ }
813
+ async function getDashboardMetrics(req, res, opts) {
814
+ const authorization = buildServiceAuthorization(req, opts);
815
+ const result = await getDashboardMetricsHandler({
816
+ authServerUrl: opts.authServerUrl,
817
+ authorization
818
+ });
819
+ return handle2(res, result);
820
+ }
821
+ async function getGroupedEventSummary(req, res, opts) {
822
+ const authorization = buildServiceAuthorization(req, opts);
823
+ const result = await getGroupedEventSummaryHandler({
824
+ authServerUrl: opts.authServerUrl,
825
+ authorization
826
+ });
827
+ return handle2(res, result);
828
+ }
829
+
830
+ // src/handlers/sessions.ts
831
+ import {
832
+ listSessionsHandler,
833
+ revokeSessionHandler,
834
+ revokeAllSessionsHandler
835
+ } from "@seamless-auth/core/handlers/sessions";
836
+ function handle3(res, result) {
837
+ if (result.error) {
838
+ return res.status(result.status).json({ error: result.error });
839
+ }
840
+ return res.status(result.status).json(result.body);
841
+ }
842
+ async function listSessions(req, res, opts) {
843
+ const authorization = buildServiceAuthorization(req, opts);
844
+ const result = await listSessionsHandler({
845
+ authServerUrl: opts.authServerUrl,
846
+ authorization
847
+ });
848
+ return handle3(res, result);
849
+ }
850
+ async function revokeSession(req, res, opts) {
851
+ const authorization = buildServiceAuthorization(req, opts);
852
+ const result = await revokeSessionHandler(req.params.id, {
853
+ authServerUrl: opts.authServerUrl,
854
+ authorization
855
+ });
856
+ return handle3(res, result);
857
+ }
858
+ async function revokeAllSessions(req, res, opts) {
859
+ const authorization = buildServiceAuthorization(req, opts);
860
+ const result = await revokeAllSessionsHandler({
861
+ authServerUrl: opts.authServerUrl,
862
+ authorization
863
+ });
864
+ return handle3(res, result);
865
+ }
866
+
867
+ // src/createServer.ts
353
868
  function createSeamlessAuthServer(opts) {
354
869
  const r = express.Router();
355
870
  r.use(express.json());
@@ -365,7 +880,8 @@ function createSeamlessAuthServer(opts) {
365
880
  accessCookieName: opts.accessCookieName ?? "seamless-access",
366
881
  registrationCookieName: opts.registrationCookieName ?? "seamless-ephemeral",
367
882
  refreshCookieName: opts.refreshCookieName ?? "seamless-refresh",
368
- preAuthCookieName: opts.preAuthCookieName ?? "seamless-ephemeral"
883
+ preAuthCookieName: opts.preAuthCookieName ?? "seamless-ephemeral",
884
+ messaging: opts.messaging
369
885
  };
370
886
  const proxyWithIdentity = (path, identity, method = "POST") => async (req, res) => {
371
887
  if (!req.cookiePayload?.sub) {
@@ -438,11 +954,11 @@ function createSeamlessAuthServer(opts) {
438
954
  );
439
955
  r.get(
440
956
  "/otp/generate-phone-otp",
441
- proxyWithIdentity("otp/generate-phone-otp", "preAuth", "GET")
957
+ (req, res) => requestOtp(req, res, resolvedOpts, "phone")
442
958
  );
443
959
  r.get(
444
960
  "/otp/generate-email-otp",
445
- proxyWithIdentity("otp/generate-email-otp", "preAuth", "GET")
961
+ (req, res) => requestOtp(req, res, resolvedOpts, "email")
446
962
  );
447
963
  r.post("/login", (req, res) => login(req, res, resolvedOpts));
448
964
  r.post(
@@ -460,7 +976,10 @@ function createSeamlessAuthServer(opts) {
460
976
  "/users/credentials",
461
977
  proxyWithIdentity("users/credentials", "access")
462
978
  );
463
- r.get("/magic-link", proxyWithIdentity("magic-link", "preAuth", "GET"));
979
+ r.get(
980
+ "/magic-link",
981
+ (req, res) => requestMagicLink(req, res, resolvedOpts)
982
+ );
464
983
  r.get("/magic-link/verify/:token", async (req, res) => {
465
984
  const upstream = await authFetch(
466
985
  `${resolvedOpts.authServerUrl}/magic-link/verify/${req.params.token}`,
@@ -473,11 +992,101 @@ function createSeamlessAuthServer(opts) {
473
992
  "/magic-link/check",
474
993
  (req, res) => pollMagicLinkConfirmation(req, res, resolvedOpts)
475
994
  );
995
+ r.post(
996
+ "/internal/bootstrap/admin-invite",
997
+ (req, res) => bootstrapAdminInvite(req, res, resolvedOpts)
998
+ );
999
+ r.get(
1000
+ "/system-config/roles",
1001
+ (req, res) => getAvailableRoles(req, res, resolvedOpts)
1002
+ );
1003
+ r.get(
1004
+ "/system-config/admin",
1005
+ (req, res) => getSystemConfigAdmin(req, res, resolvedOpts)
1006
+ );
1007
+ r.patch(
1008
+ "/system-config/admin",
1009
+ (req, res) => updateSystemConfig(req, res, resolvedOpts)
1010
+ );
1011
+ r.get(
1012
+ "/internal/auth-events/summary",
1013
+ (req, res) => getAuthEventSummary(req, res, resolvedOpts)
1014
+ );
1015
+ r.get(
1016
+ "/internal/auth-events/timeseries",
1017
+ (req, res) => getAuthEventTimeseries(req, res, resolvedOpts)
1018
+ );
1019
+ r.get(
1020
+ "/internal/auth-events/login-stats",
1021
+ (req, res) => getLoginStats(req, res, resolvedOpts)
1022
+ );
1023
+ r.get(
1024
+ "/internal/security/anomalies",
1025
+ (req, res) => getSecurityAnomalies(req, res, resolvedOpts)
1026
+ );
1027
+ r.get(
1028
+ "/internal/metrics/dashboard",
1029
+ (req, res) => getDashboardMetrics(req, res, resolvedOpts)
1030
+ );
1031
+ r.get(
1032
+ "/internal/auth-events/grouped",
1033
+ (req, res) => getGroupedEventSummary(req, res, resolvedOpts)
1034
+ );
1035
+ r.get("/admin/users", (req, res) => getUsers(req, res, resolvedOpts));
1036
+ r.post(
1037
+ "/admin/users",
1038
+ (req, res) => createUser(req, res, resolvedOpts)
1039
+ );
1040
+ r.delete(
1041
+ "/admin/users",
1042
+ (req, res) => deleteUser(req, res, resolvedOpts)
1043
+ );
1044
+ r.patch(
1045
+ "/admin/users/:userId",
1046
+ (req, res) => updateUser(req, res, resolvedOpts)
1047
+ );
1048
+ r.get(
1049
+ "/admin/users/:userId",
1050
+ (req, res) => getUserDetail(req, res, resolvedOpts)
1051
+ );
1052
+ r.get(
1053
+ "/admin/users/:userId/anomalies",
1054
+ (req, res) => getUserAnomalies(req, res, resolvedOpts)
1055
+ );
1056
+ r.get(
1057
+ "/admin/auth-events",
1058
+ (req, res) => getAuthEvents(req, res, resolvedOpts)
1059
+ );
1060
+ r.get(
1061
+ "/admin/credential-count",
1062
+ (req, res) => getCredentialCount(req, res, resolvedOpts)
1063
+ );
1064
+ r.get(
1065
+ "/admin/sessions",
1066
+ (req, res) => listAllSessions(req, res, resolvedOpts)
1067
+ );
1068
+ r.get(
1069
+ "/admin/sessions/:userId",
1070
+ (req, res) => listUserSessions(req, res, resolvedOpts)
1071
+ );
1072
+ r.delete(
1073
+ "/admin/sessions/:userId/revoke-all",
1074
+ (req, res) => revokeAllUserSessions(req, res, resolvedOpts)
1075
+ );
1076
+ r.get("/sessions", (req, res) => listSessions(req, res, resolvedOpts));
1077
+ r.delete(
1078
+ "/sessions/:id",
1079
+ (req, res) => revokeSession(req, res, resolvedOpts)
1080
+ );
1081
+ r.delete(
1082
+ "/sessions",
1083
+ (req, res) => revokeAllSessions(req, res, resolvedOpts)
1084
+ );
476
1085
  return r;
477
1086
  }
478
1087
 
479
1088
  // src/middleware/requireAuth.ts
480
- import { verifyCookieJwt } from "@seamless-auth/core";
1089
+ import { verifyCookieJwt as verifyCookieJwt2 } from "@seamless-auth/core";
481
1090
  function requireAuth(opts) {
482
1091
  const { cookieName = "seamless-access", cookieSecret } = opts;
483
1092
  if (!cookieSecret) {
@@ -495,7 +1104,7 @@ function requireAuth(opts) {
495
1104
  });
496
1105
  return;
497
1106
  }
498
- const payload = verifyCookieJwt(token, cookieSecret);
1107
+ const payload = verifyCookieJwt2(token, cookieSecret);
499
1108
  if (!payload || !payload.sub) {
500
1109
  res.status(401).json({
501
1110
  error: "Invalid or expired session"