@seamless-auth/express 0.1.2 → 0.2.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/dist/index.js +374 -5
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -216,9 +216,9 @@ async function register(req, res, opts) {
|
|
|
216
216
|
setSessionCookie(
|
|
217
217
|
res,
|
|
218
218
|
{
|
|
219
|
-
name:
|
|
219
|
+
name: c.name,
|
|
220
220
|
payload: c.value,
|
|
221
|
-
domain: c.domain,
|
|
221
|
+
domain: c.domain ?? opts.cookieDomain,
|
|
222
222
|
ttlSeconds: c.ttl
|
|
223
223
|
},
|
|
224
224
|
cookieSigner
|
|
@@ -233,6 +233,7 @@ async function register(req, res, opts) {
|
|
|
233
233
|
|
|
234
234
|
// src/handlers/finishRegister.ts
|
|
235
235
|
import { finishRegisterHandler } from "@seamless-auth/core/handlers/finishRegister";
|
|
236
|
+
import { verifyCookieJwt } from "@seamless-auth/core";
|
|
236
237
|
async function finishRegister(req, res, opts) {
|
|
237
238
|
const cookieSigner = {
|
|
238
239
|
secret: opts.cookieSecret,
|
|
@@ -240,8 +241,24 @@ async function finishRegister(req, res, opts) {
|
|
|
240
241
|
sameSite: process.env.NODE_ENV === "production" ? "none" : "lax"
|
|
241
242
|
};
|
|
242
243
|
const authorization = buildServiceAuthorization(req, opts);
|
|
244
|
+
const bootstrapToken = req.cookies?.["seamless_bootstrap_token"];
|
|
245
|
+
const headers = {};
|
|
246
|
+
if (bootstrapToken) {
|
|
247
|
+
const payload = verifyCookieJwt(bootstrapToken, opts.cookieSecret);
|
|
248
|
+
if (!payload || !payload.sub) {
|
|
249
|
+
res.status(401).json({
|
|
250
|
+
error: "Invalid or expired session"
|
|
251
|
+
});
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
headers["cookie"] = `seamless_bootstrap_token=${payload.sub}`;
|
|
255
|
+
}
|
|
243
256
|
const result = await finishRegisterHandler(
|
|
244
|
-
{
|
|
257
|
+
{
|
|
258
|
+
body: req.body,
|
|
259
|
+
authorization,
|
|
260
|
+
headers
|
|
261
|
+
},
|
|
245
262
|
{
|
|
246
263
|
authServerUrl: opts.authServerUrl,
|
|
247
264
|
cookieDomain: opts.cookieDomain,
|
|
@@ -346,10 +363,272 @@ async function pollMagicLinkConfirmation(req, res, opts) {
|
|
|
346
363
|
res.status(result.status).json(result.body).end();
|
|
347
364
|
}
|
|
348
365
|
|
|
366
|
+
// src/handlers/admin.ts
|
|
367
|
+
import {
|
|
368
|
+
getUsersHandler,
|
|
369
|
+
createUserHandler,
|
|
370
|
+
deleteUserHandler,
|
|
371
|
+
updateUserHandler,
|
|
372
|
+
getUserDetailHandler,
|
|
373
|
+
getUserAnomaliesHandler,
|
|
374
|
+
getAuthEventsHandler,
|
|
375
|
+
getCredentialCountHandler,
|
|
376
|
+
listAllSessionsHandler,
|
|
377
|
+
listUserSessionsHandler,
|
|
378
|
+
revokeAllUserSessionsHandler
|
|
379
|
+
} from "@seamless-auth/core/handlers/admin";
|
|
380
|
+
function handle(res, result) {
|
|
381
|
+
if (result.error) {
|
|
382
|
+
return res.status(result.status).json({ error: result.error });
|
|
383
|
+
}
|
|
384
|
+
return res.status(result.status).json(result.body);
|
|
385
|
+
}
|
|
386
|
+
var getUsers = async (req, res, opts) => handle(
|
|
387
|
+
res,
|
|
388
|
+
await getUsersHandler({
|
|
389
|
+
authServerUrl: opts.authServerUrl,
|
|
390
|
+
authorization: buildServiceAuthorization(req, opts)
|
|
391
|
+
})
|
|
392
|
+
);
|
|
393
|
+
var createUser = async (req, res, opts) => handle(
|
|
394
|
+
res,
|
|
395
|
+
await createUserHandler({
|
|
396
|
+
authServerUrl: opts.authServerUrl,
|
|
397
|
+
authorization: buildServiceAuthorization(req, opts),
|
|
398
|
+
body: req.body
|
|
399
|
+
})
|
|
400
|
+
);
|
|
401
|
+
var deleteUser = async (req, res, opts) => handle(
|
|
402
|
+
res,
|
|
403
|
+
await deleteUserHandler({
|
|
404
|
+
authServerUrl: opts.authServerUrl,
|
|
405
|
+
authorization: buildServiceAuthorization(req, opts)
|
|
406
|
+
})
|
|
407
|
+
);
|
|
408
|
+
var updateUser = async (req, res, opts) => handle(
|
|
409
|
+
res,
|
|
410
|
+
await updateUserHandler(req.params.userId, {
|
|
411
|
+
authServerUrl: opts.authServerUrl,
|
|
412
|
+
authorization: buildServiceAuthorization(req, opts),
|
|
413
|
+
body: req.body
|
|
414
|
+
})
|
|
415
|
+
);
|
|
416
|
+
var getUserDetail = async (req, res, opts) => handle(
|
|
417
|
+
res,
|
|
418
|
+
await getUserDetailHandler(req.params.userId, {
|
|
419
|
+
authServerUrl: opts.authServerUrl,
|
|
420
|
+
authorization: buildServiceAuthorization(req, opts)
|
|
421
|
+
})
|
|
422
|
+
);
|
|
423
|
+
var getUserAnomalies = async (req, res, opts) => handle(
|
|
424
|
+
res,
|
|
425
|
+
await getUserAnomaliesHandler(req.params.userId, {
|
|
426
|
+
authServerUrl: opts.authServerUrl,
|
|
427
|
+
authorization: buildServiceAuthorization(req, opts)
|
|
428
|
+
})
|
|
429
|
+
);
|
|
430
|
+
var getAuthEvents = async (req, res, opts) => handle(
|
|
431
|
+
res,
|
|
432
|
+
await getAuthEventsHandler({
|
|
433
|
+
authServerUrl: opts.authServerUrl,
|
|
434
|
+
authorization: buildServiceAuthorization(req, opts),
|
|
435
|
+
query: req.query
|
|
436
|
+
})
|
|
437
|
+
);
|
|
438
|
+
var getCredentialCount = async (req, res, opts) => handle(
|
|
439
|
+
res,
|
|
440
|
+
await getCredentialCountHandler({
|
|
441
|
+
authServerUrl: opts.authServerUrl,
|
|
442
|
+
authorization: buildServiceAuthorization(req, opts)
|
|
443
|
+
})
|
|
444
|
+
);
|
|
445
|
+
var listAllSessions = async (req, res, opts) => handle(
|
|
446
|
+
res,
|
|
447
|
+
await listAllSessionsHandler({
|
|
448
|
+
authServerUrl: opts.authServerUrl,
|
|
449
|
+
authorization: buildServiceAuthorization(req, opts),
|
|
450
|
+
query: req.query
|
|
451
|
+
})
|
|
452
|
+
);
|
|
453
|
+
var listUserSessions = async (req, res, opts) => handle(
|
|
454
|
+
res,
|
|
455
|
+
await listUserSessionsHandler(req.params.userId, {
|
|
456
|
+
authServerUrl: opts.authServerUrl,
|
|
457
|
+
authorization: buildServiceAuthorization(req, opts)
|
|
458
|
+
})
|
|
459
|
+
);
|
|
460
|
+
var revokeAllUserSessions = async (req, res, opts) => handle(
|
|
461
|
+
res,
|
|
462
|
+
await revokeAllUserSessionsHandler(req.params.userId, {
|
|
463
|
+
authServerUrl: opts.authServerUrl,
|
|
464
|
+
authorization: buildServiceAuthorization(req, opts)
|
|
465
|
+
})
|
|
466
|
+
);
|
|
467
|
+
|
|
349
468
|
// src/createServer.ts
|
|
350
469
|
import {
|
|
351
470
|
authFetch
|
|
352
471
|
} from "@seamless-auth/core";
|
|
472
|
+
|
|
473
|
+
// src/handlers/bootstrapAdmininvite.ts
|
|
474
|
+
import { bootstrapAdminInviteHandler } from "@seamless-auth/core/handlers/bootstrapAdminInvite";
|
|
475
|
+
async function bootstrapAdminInvite(req, res, opts) {
|
|
476
|
+
const result = await bootstrapAdminInviteHandler({
|
|
477
|
+
authServerUrl: opts.authServerUrl,
|
|
478
|
+
email: req.body.email,
|
|
479
|
+
authorization: req.headers["authorization"]
|
|
480
|
+
});
|
|
481
|
+
if (result.error) {
|
|
482
|
+
return res.status(result.status).json({ error: result.error });
|
|
483
|
+
}
|
|
484
|
+
res.status(result.status).json(result.body);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// src/handlers/systemConfig.ts
|
|
488
|
+
import {
|
|
489
|
+
getAvailableRolesHandler,
|
|
490
|
+
getSystemConfigAdminHandler,
|
|
491
|
+
updateSystemConfigHandler
|
|
492
|
+
} from "@seamless-auth/core/handlers/systemConfig";
|
|
493
|
+
async function getAvailableRoles(req, res, opts) {
|
|
494
|
+
const authorization = buildServiceAuthorization(req, opts);
|
|
495
|
+
const result = await getAvailableRolesHandler({
|
|
496
|
+
authServerUrl: opts.authServerUrl,
|
|
497
|
+
authorization
|
|
498
|
+
});
|
|
499
|
+
if (result.error) {
|
|
500
|
+
return res.status(result.status).json({ error: result.error });
|
|
501
|
+
}
|
|
502
|
+
res.status(result.status).json(result.body);
|
|
503
|
+
}
|
|
504
|
+
async function getSystemConfigAdmin(req, res, opts) {
|
|
505
|
+
const authorization = buildServiceAuthorization(req, opts);
|
|
506
|
+
const result = await getSystemConfigAdminHandler({
|
|
507
|
+
authServerUrl: opts.authServerUrl,
|
|
508
|
+
authorization
|
|
509
|
+
});
|
|
510
|
+
if (result.error) {
|
|
511
|
+
return res.status(result.status).json({ error: result.error });
|
|
512
|
+
}
|
|
513
|
+
res.status(result.status).json(result.body);
|
|
514
|
+
}
|
|
515
|
+
async function updateSystemConfig(req, res, opts) {
|
|
516
|
+
const authorization = buildServiceAuthorization(req, opts);
|
|
517
|
+
const result = await updateSystemConfigHandler({
|
|
518
|
+
authServerUrl: opts.authServerUrl,
|
|
519
|
+
authorization,
|
|
520
|
+
payload: req.body
|
|
521
|
+
});
|
|
522
|
+
if (result.error) {
|
|
523
|
+
return res.status(result.status).json({ error: result.error });
|
|
524
|
+
}
|
|
525
|
+
res.status(result.status).json(result.body);
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
// src/handlers/internalMetrics.ts
|
|
529
|
+
import {
|
|
530
|
+
getAuthEventSummaryHandler,
|
|
531
|
+
getAuthEventTimeseriesHandler,
|
|
532
|
+
getLoginStatsHandler,
|
|
533
|
+
getSecurityAnomaliesHandler,
|
|
534
|
+
getDashboardMetricsHandler,
|
|
535
|
+
getGroupedEventSummaryHandler
|
|
536
|
+
} from "@seamless-auth/core/handlers/internalMetrics";
|
|
537
|
+
function handle2(res, result) {
|
|
538
|
+
if (result.error) {
|
|
539
|
+
return res.status(result.status).json({ error: result.error });
|
|
540
|
+
}
|
|
541
|
+
return res.status(result.status).json(result.body);
|
|
542
|
+
}
|
|
543
|
+
async function getAuthEventSummary(req, res, opts) {
|
|
544
|
+
const authorization = buildServiceAuthorization(req, opts);
|
|
545
|
+
const result = await getAuthEventSummaryHandler({
|
|
546
|
+
authServerUrl: opts.authServerUrl,
|
|
547
|
+
authorization,
|
|
548
|
+
query: req.query
|
|
549
|
+
});
|
|
550
|
+
return handle2(res, result);
|
|
551
|
+
}
|
|
552
|
+
async function getAuthEventTimeseries(req, res, opts) {
|
|
553
|
+
const authorization = buildServiceAuthorization(req, opts);
|
|
554
|
+
const result = await getAuthEventTimeseriesHandler({
|
|
555
|
+
authServerUrl: opts.authServerUrl,
|
|
556
|
+
authorization,
|
|
557
|
+
query: req.query
|
|
558
|
+
});
|
|
559
|
+
return handle2(res, result);
|
|
560
|
+
}
|
|
561
|
+
async function getLoginStats(req, res, opts) {
|
|
562
|
+
const authorization = buildServiceAuthorization(req, opts);
|
|
563
|
+
const result = await getLoginStatsHandler({
|
|
564
|
+
authServerUrl: opts.authServerUrl,
|
|
565
|
+
authorization
|
|
566
|
+
});
|
|
567
|
+
return handle2(res, result);
|
|
568
|
+
}
|
|
569
|
+
async function getSecurityAnomalies(req, res, opts) {
|
|
570
|
+
const authorization = buildServiceAuthorization(req, opts);
|
|
571
|
+
const result = await getSecurityAnomaliesHandler({
|
|
572
|
+
authServerUrl: opts.authServerUrl,
|
|
573
|
+
authorization
|
|
574
|
+
});
|
|
575
|
+
return handle2(res, result);
|
|
576
|
+
}
|
|
577
|
+
async function getDashboardMetrics(req, res, opts) {
|
|
578
|
+
const authorization = buildServiceAuthorization(req, opts);
|
|
579
|
+
const result = await getDashboardMetricsHandler({
|
|
580
|
+
authServerUrl: opts.authServerUrl,
|
|
581
|
+
authorization
|
|
582
|
+
});
|
|
583
|
+
return handle2(res, result);
|
|
584
|
+
}
|
|
585
|
+
async function getGroupedEventSummary(req, res, opts) {
|
|
586
|
+
const authorization = buildServiceAuthorization(req, opts);
|
|
587
|
+
const result = await getGroupedEventSummaryHandler({
|
|
588
|
+
authServerUrl: opts.authServerUrl,
|
|
589
|
+
authorization
|
|
590
|
+
});
|
|
591
|
+
return handle2(res, result);
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
// src/handlers/sessions.ts
|
|
595
|
+
import {
|
|
596
|
+
listSessionsHandler,
|
|
597
|
+
revokeSessionHandler,
|
|
598
|
+
revokeAllSessionsHandler
|
|
599
|
+
} from "@seamless-auth/core/handlers/sessions";
|
|
600
|
+
function handle3(res, result) {
|
|
601
|
+
if (result.error) {
|
|
602
|
+
return res.status(result.status).json({ error: result.error });
|
|
603
|
+
}
|
|
604
|
+
return res.status(result.status).json(result.body);
|
|
605
|
+
}
|
|
606
|
+
async function listSessions(req, res, opts) {
|
|
607
|
+
const authorization = buildServiceAuthorization(req, opts);
|
|
608
|
+
const result = await listSessionsHandler({
|
|
609
|
+
authServerUrl: opts.authServerUrl,
|
|
610
|
+
authorization
|
|
611
|
+
});
|
|
612
|
+
return handle3(res, result);
|
|
613
|
+
}
|
|
614
|
+
async function revokeSession(req, res, opts) {
|
|
615
|
+
const authorization = buildServiceAuthorization(req, opts);
|
|
616
|
+
const result = await revokeSessionHandler(req.params.id, {
|
|
617
|
+
authServerUrl: opts.authServerUrl,
|
|
618
|
+
authorization
|
|
619
|
+
});
|
|
620
|
+
return handle3(res, result);
|
|
621
|
+
}
|
|
622
|
+
async function revokeAllSessions(req, res, opts) {
|
|
623
|
+
const authorization = buildServiceAuthorization(req, opts);
|
|
624
|
+
const result = await revokeAllSessionsHandler({
|
|
625
|
+
authServerUrl: opts.authServerUrl,
|
|
626
|
+
authorization
|
|
627
|
+
});
|
|
628
|
+
return handle3(res, result);
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
// src/createServer.ts
|
|
353
632
|
function createSeamlessAuthServer(opts) {
|
|
354
633
|
const r = express.Router();
|
|
355
634
|
r.use(express.json());
|
|
@@ -473,11 +752,101 @@ function createSeamlessAuthServer(opts) {
|
|
|
473
752
|
"/magic-link/check",
|
|
474
753
|
(req, res) => pollMagicLinkConfirmation(req, res, resolvedOpts)
|
|
475
754
|
);
|
|
755
|
+
r.post(
|
|
756
|
+
"/internal/bootstrap/admin-invite",
|
|
757
|
+
(req, res) => bootstrapAdminInvite(req, res, resolvedOpts)
|
|
758
|
+
);
|
|
759
|
+
r.get(
|
|
760
|
+
"/system-config/roles",
|
|
761
|
+
(req, res) => getAvailableRoles(req, res, resolvedOpts)
|
|
762
|
+
);
|
|
763
|
+
r.get(
|
|
764
|
+
"/system-config/admin",
|
|
765
|
+
(req, res) => getSystemConfigAdmin(req, res, resolvedOpts)
|
|
766
|
+
);
|
|
767
|
+
r.patch(
|
|
768
|
+
"/system-config/admin",
|
|
769
|
+
(req, res) => updateSystemConfig(req, res, resolvedOpts)
|
|
770
|
+
);
|
|
771
|
+
r.get(
|
|
772
|
+
"/internal/auth-events/summary",
|
|
773
|
+
(req, res) => getAuthEventSummary(req, res, resolvedOpts)
|
|
774
|
+
);
|
|
775
|
+
r.get(
|
|
776
|
+
"/internal/auth-events/timeseries",
|
|
777
|
+
(req, res) => getAuthEventTimeseries(req, res, resolvedOpts)
|
|
778
|
+
);
|
|
779
|
+
r.get(
|
|
780
|
+
"/internal/auth-events/login-stats",
|
|
781
|
+
(req, res) => getLoginStats(req, res, resolvedOpts)
|
|
782
|
+
);
|
|
783
|
+
r.get(
|
|
784
|
+
"/internal/security/anomalies",
|
|
785
|
+
(req, res) => getSecurityAnomalies(req, res, resolvedOpts)
|
|
786
|
+
);
|
|
787
|
+
r.get(
|
|
788
|
+
"/internal/metrics/dashboard",
|
|
789
|
+
(req, res) => getDashboardMetrics(req, res, resolvedOpts)
|
|
790
|
+
);
|
|
791
|
+
r.get(
|
|
792
|
+
"/internal/auth-events/grouped",
|
|
793
|
+
(req, res) => getGroupedEventSummary(req, res, resolvedOpts)
|
|
794
|
+
);
|
|
795
|
+
r.get("/admin/users", (req, res) => getUsers(req, res, resolvedOpts));
|
|
796
|
+
r.post(
|
|
797
|
+
"/admin/users",
|
|
798
|
+
(req, res) => createUser(req, res, resolvedOpts)
|
|
799
|
+
);
|
|
800
|
+
r.delete(
|
|
801
|
+
"/admin/users",
|
|
802
|
+
(req, res) => deleteUser(req, res, resolvedOpts)
|
|
803
|
+
);
|
|
804
|
+
r.patch(
|
|
805
|
+
"/admin/users/:userId",
|
|
806
|
+
(req, res) => updateUser(req, res, resolvedOpts)
|
|
807
|
+
);
|
|
808
|
+
r.get(
|
|
809
|
+
"/admin/users/:userId",
|
|
810
|
+
(req, res) => getUserDetail(req, res, resolvedOpts)
|
|
811
|
+
);
|
|
812
|
+
r.get(
|
|
813
|
+
"/admin/users/:userId/anomalies",
|
|
814
|
+
(req, res) => getUserAnomalies(req, res, resolvedOpts)
|
|
815
|
+
);
|
|
816
|
+
r.get(
|
|
817
|
+
"/admin/auth-events",
|
|
818
|
+
(req, res) => getAuthEvents(req, res, resolvedOpts)
|
|
819
|
+
);
|
|
820
|
+
r.get(
|
|
821
|
+
"/admin/credential-count",
|
|
822
|
+
(req, res) => getCredentialCount(req, res, resolvedOpts)
|
|
823
|
+
);
|
|
824
|
+
r.get(
|
|
825
|
+
"/admin/sessions",
|
|
826
|
+
(req, res) => listAllSessions(req, res, resolvedOpts)
|
|
827
|
+
);
|
|
828
|
+
r.get(
|
|
829
|
+
"/admin/sessions/:userId",
|
|
830
|
+
(req, res) => listUserSessions(req, res, resolvedOpts)
|
|
831
|
+
);
|
|
832
|
+
r.delete(
|
|
833
|
+
"/admin/sessions/:userId/revoke-all",
|
|
834
|
+
(req, res) => revokeAllUserSessions(req, res, resolvedOpts)
|
|
835
|
+
);
|
|
836
|
+
r.get("/sessions", (req, res) => listSessions(req, res, resolvedOpts));
|
|
837
|
+
r.delete(
|
|
838
|
+
"/sessions/:id",
|
|
839
|
+
(req, res) => revokeSession(req, res, resolvedOpts)
|
|
840
|
+
);
|
|
841
|
+
r.delete(
|
|
842
|
+
"/sessions",
|
|
843
|
+
(req, res) => revokeAllSessions(req, res, resolvedOpts)
|
|
844
|
+
);
|
|
476
845
|
return r;
|
|
477
846
|
}
|
|
478
847
|
|
|
479
848
|
// src/middleware/requireAuth.ts
|
|
480
|
-
import { verifyCookieJwt } from "@seamless-auth/core";
|
|
849
|
+
import { verifyCookieJwt as verifyCookieJwt2 } from "@seamless-auth/core";
|
|
481
850
|
function requireAuth(opts) {
|
|
482
851
|
const { cookieName = "seamless-access", cookieSecret } = opts;
|
|
483
852
|
if (!cookieSecret) {
|
|
@@ -495,7 +864,7 @@ function requireAuth(opts) {
|
|
|
495
864
|
});
|
|
496
865
|
return;
|
|
497
866
|
}
|
|
498
|
-
const payload =
|
|
867
|
+
const payload = verifyCookieJwt2(token, cookieSecret);
|
|
499
868
|
if (!payload || !payload.sub) {
|
|
500
869
|
res.status(401).json({
|
|
501
870
|
error: "Invalid or expired session"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seamless-auth/express",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Express adapter for Seamless Auth passwordless authentication",
|
|
5
5
|
"license": "AGPL-3.0-only",
|
|
6
6
|
"type": "module",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"express": ">=4.18.0"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@seamless-auth/core": "^0.
|
|
40
|
+
"@seamless-auth/core": "^0.3.0",
|
|
41
41
|
"cookie-parser": "^1.4.6",
|
|
42
42
|
"jsonwebtoken": "^9.0.3"
|
|
43
43
|
},
|