create-authenik8-app 2.4.5 → 2.4.7

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 (87) hide show
  1. package/dist/src/bin/index.d.ts +3 -0
  2. package/dist/src/bin/index.d.ts.map +1 -0
  3. package/dist/src/bin/index.js +275 -0
  4. package/dist/src/bin/index.js.map +1 -0
  5. package/dist/src/lib/constants.d.ts +4 -0
  6. package/dist/src/lib/constants.d.ts.map +1 -0
  7. package/dist/src/lib/constants.js +25 -0
  8. package/dist/src/lib/constants.js.map +1 -0
  9. package/dist/src/lib/process.d.ts +7 -0
  10. package/dist/src/lib/process.d.ts.map +1 -0
  11. package/dist/src/lib/process.js +60 -0
  12. package/dist/src/lib/process.js.map +1 -0
  13. package/dist/src/lib/state.d.ts +8 -0
  14. package/dist/src/lib/state.d.ts.map +1 -0
  15. package/dist/src/lib/state.js +31 -0
  16. package/dist/src/lib/state.js.map +1 -0
  17. package/dist/src/lib/types.d.ts +19 -0
  18. package/dist/src/lib/types.d.ts.map +1 -0
  19. package/dist/src/lib/types.js +2 -0
  20. package/dist/src/lib/types.js.map +1 -0
  21. package/dist/src/lib/ui.d.ts +7 -0
  22. package/dist/src/lib/ui.d.ts.map +1 -0
  23. package/dist/src/lib/ui.js +124 -0
  24. package/dist/src/lib/ui.js.map +1 -0
  25. package/dist/src/steps/configurePrisma.d.ts +3 -0
  26. package/dist/src/steps/configurePrisma.d.ts.map +1 -0
  27. package/dist/src/steps/configurePrisma.js +62 -0
  28. package/dist/src/steps/configurePrisma.js.map +1 -0
  29. package/dist/src/steps/createProject.d.ts +5 -0
  30. package/dist/src/steps/createProject.d.ts.map +1 -0
  31. package/dist/src/steps/createProject.js +202 -0
  32. package/dist/src/steps/createProject.js.map +1 -0
  33. package/dist/src/steps/finalSetup.d.ts +7 -0
  34. package/dist/src/steps/finalSetup.d.ts.map +1 -0
  35. package/dist/src/steps/finalSetup.js +110 -0
  36. package/dist/src/steps/finalSetup.js.map +1 -0
  37. package/dist/src/steps/installAuth.d.ts +3 -0
  38. package/dist/src/steps/installAuth.d.ts.map +1 -0
  39. package/dist/src/steps/installAuth.js +16 -0
  40. package/dist/src/steps/installAuth.js.map +1 -0
  41. package/dist/src/steps/installDeps.d.ts +5 -0
  42. package/dist/src/steps/installDeps.d.ts.map +1 -0
  43. package/dist/src/steps/installDeps.js +99 -0
  44. package/dist/src/steps/installDeps.js.map +1 -0
  45. package/dist/src/steps/prompts.d.ts +3 -0
  46. package/dist/src/steps/prompts.d.ts.map +1 -0
  47. package/dist/src/steps/prompts.js +93 -0
  48. package/dist/src/steps/prompts.js.map +1 -0
  49. package/dist/src/tests/templated-routes.test.d.ts +2 -0
  50. package/dist/src/tests/templated-routes.test.d.ts.map +1 -0
  51. package/dist/src/tests/templated-routes.test.js +325 -0
  52. package/dist/src/tests/templated-routes.test.js.map +1 -0
  53. package/dist/src/utils/hash.d.ts +4 -0
  54. package/dist/src/utils/hash.d.ts.map +1 -0
  55. package/dist/src/utils/hash.js +17 -0
  56. package/dist/src/utils/hash.js.map +1 -0
  57. package/dist/src/utils/output.d.ts +3 -0
  58. package/dist/src/utils/output.d.ts.map +1 -0
  59. package/dist/src/utils/output.js +81 -0
  60. package/dist/src/utils/output.js.map +1 -0
  61. package/dist/templates/THREAT_MODEL.md +138 -0
  62. package/dist/templates/express-auth/src/controllers/protected.controller.d.ts +8 -0
  63. package/dist/templates/express-auth/src/controllers/protected.controller.d.ts.map +1 -0
  64. package/dist/templates/express-auth/src/controllers/protected.controller.js +50 -0
  65. package/dist/templates/express-auth/src/controllers/protected.controller.js.map +1 -0
  66. package/dist/templates/express-auth/src/routes/protected.routes.d.ts +2 -0
  67. package/dist/templates/express-auth/src/routes/protected.routes.d.ts.map +1 -0
  68. package/dist/templates/express-auth/src/routes/protected.routes.js +16 -0
  69. package/dist/templates/express-auth/src/routes/protected.routes.js.map +1 -0
  70. package/dist/templates/express-auth/src/utils/security.d.ts +8 -0
  71. package/dist/templates/express-auth/src/utils/security.d.ts.map +1 -0
  72. package/dist/templates/express-auth/src/utils/security.js +55 -0
  73. package/dist/templates/express-auth/src/utils/security.js.map +1 -0
  74. package/dist/templates/express-base/controllers/base.controller.d.ts +12 -0
  75. package/dist/templates/express-base/controllers/base.controller.d.ts.map +1 -0
  76. package/dist/templates/express-base/controllers/base.controller.js +77 -0
  77. package/dist/templates/express-base/controllers/base.controller.js.map +1 -0
  78. package/dist/templates/express-base/routes/base.routes.d.ts +2 -0
  79. package/dist/templates/express-base/routes/base.routes.d.ts.map +1 -0
  80. package/dist/templates/express-base/routes/base.routes.js +20 -0
  81. package/dist/templates/express-base/routes/base.routes.js.map +1 -0
  82. package/dist/templates/express-base/utils/security.d.ts +5 -0
  83. package/dist/templates/express-base/utils/security.d.ts.map +1 -0
  84. package/dist/templates/express-base/utils/security.js +40 -0
  85. package/dist/templates/express-base/utils/security.js.map +1 -0
  86. package/dist/templates/package.json +27 -0
  87. package/package.json +7 -6
@@ -0,0 +1,138 @@
1
+ # Authenik8 Generated App Threat Model
2
+
3
+ This document describes what a generated Authenik8 app is designed to help with, what it does not solve for you, and what you must configure before production use.
4
+
5
+ ## System Boundary
6
+
7
+ A generated app includes:
8
+
9
+ - Express API routes.
10
+ - JWT access tokens.
11
+ - Redis-backed refresh-token rotation.
12
+ - Prisma database schema.
13
+ - Optional Google/GitHub OAuth.
14
+ - Authenik8 security middleware: Helmet, rate limiting, and optional IP whitelist.
15
+ - Optional PM2 production process config.
16
+
17
+ External systems are outside the generated app boundary:
18
+
19
+ - Browser or mobile frontend.
20
+ - OAuth provider dashboards.
21
+ - Redis hosting.
22
+ - SQL database hosting.
23
+ - TLS termination and reverse proxy.
24
+ - Secret management.
25
+ - Email delivery, MFA, and password reset flows unless you add them.
26
+
27
+ ## Assets Protected
28
+
29
+ - Access tokens.
30
+ - Refresh tokens.
31
+ - OAuth authorization state.
32
+ - OAuth identity records.
33
+ - User IDs, emails, roles, and provider links.
34
+ - Redis-backed session state.
35
+ - Admin-only routes.
36
+
37
+ ## Trust Assumptions
38
+
39
+ - `JWT_SECRET` and `REFRESH_SECRET` are long, random, private values.
40
+ - Redis is private to the app and not exposed to the public internet.
41
+ - Database credentials are private.
42
+ - OAuth callback URLs match provider dashboard settings exactly.
43
+ - Production traffic uses HTTPS.
44
+ - Reverse proxy headers are trusted only when you control the proxy.
45
+ - Developers validate and authorize their own business-domain routes.
46
+
47
+ ## Threats Addressed
48
+
49
+ ### Refresh-token replay
50
+
51
+ Refresh tokens are stateful. The currently valid refresh token is stored in Redis under `refresh:<userId>`. When a refresh succeeds, Authenik8-core rotates the refresh token and replaces the Redis value. Reusing an old refresh token fails.
52
+
53
+ ### Concurrent refresh abuse
54
+
55
+ Refresh requests acquire a Redis lock under `lock:<userId>`. Two simultaneous refresh attempts for the same user should not both rotate successfully.
56
+
57
+ ### Stateless JWT logout limitations
58
+
59
+ Access-token sessions are persisted in Redis under `sessions:<userId>`. Admin helpers can list sessions and revoke one or all sessions for a user.
60
+
61
+ ### Basic request flooding
62
+
63
+ `auth.rateLimit` uses Redis-backed rate limiting. Generated apps apply it globally by default.
64
+
65
+ ### Common HTTP header risks
66
+
67
+ `auth.helmet` applies secure HTTP headers through Helmet.
68
+
69
+ ### OAuth CSRF/state tampering
70
+
71
+ OAuth redirects generate random state and store it in Redis for five minutes under `oauth:state:<state>`. Callback handlers reject missing, invalid, or expired state.
72
+
73
+ ### Duplicate OAuth identities
74
+
75
+ OAuth profiles are normalized into provider, provider ID, email, name, and email verification status. The Identity Engine checks provider and email records before creating a new identity.
76
+
77
+ ### Unverified OAuth email token issuance
78
+
79
+ `issueTokensFromProfile` rejects OAuth profiles whose email is not verified.
80
+
81
+ ### Admin-route access
82
+
83
+ `auth.requireAdmin` checks for a valid JWT with `role: "admin"`.
84
+
85
+ ## Threats Not Fully Addressed
86
+
87
+ ### XSS in your frontend
88
+
89
+ If frontend JavaScript is compromised, tokens stored in memory or browser storage can be stolen. Use a strong frontend CSP, avoid unsafe HTML rendering, and choose token storage deliberately.
90
+
91
+ ### CSRF for cookie-based auth
92
+
93
+ Generated examples use bearer tokens. If you move tokens into cookies, add CSRF protection and strict cookie settings.
94
+
95
+ ### Weak or leaked secrets
96
+
97
+ Authenik8 cannot protect tokens if `JWT_SECRET` or `REFRESH_SECRET` is short, reused, committed, logged, or leaked.
98
+
99
+ ### Public Redis exposure
100
+
101
+ Redis must not be reachable from the public internet. Use private networking, authentication, TLS where available, and provider-level access controls.
102
+
103
+ ### Database authorization bugs
104
+
105
+ Authenik8 authenticates users and provides route middleware. Your application must still enforce object-level authorization, ownership checks, and tenant isolation.
106
+
107
+ ### Password reset, email verification, MFA, and WebAuthn
108
+
109
+ These are not included unless you add them.
110
+
111
+ ### OAuth provider compromise or misconfiguration
112
+
113
+ Provider dashboard settings, app approval screens, callback URLs, and provider secrets must be managed outside the generated app.
114
+
115
+ ### Brute-force protection per credential
116
+
117
+ Global rate limiting is included. Add stricter per-email or per-account login throttling for high-risk apps.
118
+
119
+ ### Token theft before expiry
120
+
121
+ Short-lived access tokens reduce exposure, but a stolen access token can be used until it expires or is rejected by your session policy.
122
+
123
+ ## Production Checklist
124
+
125
+ - Replace generated development secrets with long random values.
126
+ - Run Redis on private networking.
127
+ - Run Postgres or your database on private networking.
128
+ - Use HTTPS only.
129
+ - Set exact OAuth callback URLs in Google/GitHub dashboards.
130
+ - Use `npx prisma migrate deploy` in production.
131
+ - Review CORS policy before connecting a frontend.
132
+ - Add business-level authorization checks to every protected resource route.
133
+ - Add logging and alerting for refresh failures, OAuth failures, and admin actions.
134
+ - Keep `authenik8-core` and generated dependencies updated.
135
+
136
+ ## Security Reporting
137
+
138
+ If you find a vulnerability in the generated app or Authenik8-core integration, do not publish exploit details publicly first. Open a private security report or contact the maintainer through the repository security policy.
@@ -0,0 +1,8 @@
1
+ import { Request, Response } from "express";
2
+ export declare const createProtectedController: () => {
3
+ protected(req: Request, res: Response): void;
4
+ listSessions(req: Request, res: Response): Promise<Response<any, Record<string, any>> | undefined>;
5
+ revokeSession(req: Request, res: Response): Promise<Response<any, Record<string, any>> | undefined>;
6
+ revokeAllSessions(req: Request, res: Response): Promise<Response<any, Record<string, any>> | undefined>;
7
+ };
8
+ //# sourceMappingURL=protected.controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protected.controller.d.ts","sourceRoot":"","sources":["../../../../../templates/express-auth/src/controllers/protected.controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAG5C,eAAO,MAAM,yBAAyB;mBACrB,OAAO,OAAO,QAAQ;sBAIb,OAAO,OAAO,QAAQ;uBAcrB,OAAO,OAAO,QAAQ;2BAclB,OAAO,OAAO,QAAQ;CAanD,CAAC"}
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createProtectedController = void 0;
4
+ const security_1 = require("../utils/security");
5
+ const createProtectedController = () => ({
6
+ protected(req, res) {
7
+ res.json({ message: "Protected route" });
8
+ },
9
+ async listSessions(req, res) {
10
+ try {
11
+ const actions = req.adminActions;
12
+ if (!actions) {
13
+ return res.status(503).json({ success: false, message: "Session management unavailable" });
14
+ }
15
+ const sessions = await actions.listSessions(req.params.userId);
16
+ res.json({ sessions: (0, security_1.sanitizeSessionResponse)(sessions) });
17
+ }
18
+ catch {
19
+ res.status(500).json({ success: false, message: "Failed to retrieve sessions" });
20
+ }
21
+ },
22
+ async revokeSession(req, res) {
23
+ try {
24
+ const actions = req.adminActions;
25
+ if (!actions) {
26
+ return res.status(503).json({ success: false, message: "Session management unavailable" });
27
+ }
28
+ await actions.revokeSession(req.params.userId, req.params.sessionId);
29
+ res.json({ success: true, message: "Session revoked" });
30
+ }
31
+ catch {
32
+ res.status(500).json({ success: false, message: "Failed to revoke session" });
33
+ }
34
+ },
35
+ async revokeAllSessions(req, res) {
36
+ try {
37
+ const actions = req.adminActions;
38
+ if (!actions) {
39
+ return res.status(503).json({ success: false, message: "Session management unavailable" });
40
+ }
41
+ await actions.revokeAllSessions(req.params.userId);
42
+ res.json({ success: true, message: "All sessions revoked" });
43
+ }
44
+ catch {
45
+ res.status(500).json({ success: false, message: "Failed to revoke sessions" });
46
+ }
47
+ },
48
+ });
49
+ exports.createProtectedController = createProtectedController;
50
+ //# sourceMappingURL=protected.controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protected.controller.js","sourceRoot":"","sources":["../../../../../templates/express-auth/src/controllers/protected.controller.ts"],"names":[],"mappings":";;;AACA,gDAA4D;AAErD,MAAM,yBAAyB,GAAG,GAAG,EAAE,CAAC,CAAC;IAC9C,SAAS,CAAC,GAAY,EAAE,GAAa;QACnC,GAAG,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,iBAAiB,EAAE,CAAC,CAAC;IAC3C,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,GAAY,EAAE,GAAa;QAC5C,IAAI,CAAC;YACH,MAAM,OAAO,GAAI,GAAW,CAAC,YAAY,CAAC;YAC1C,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,gCAAgC,EAAE,CAAC,CAAC;YAC7F,CAAC;YAED,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAC/D,GAAG,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAA,kCAAuB,EAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAC5D,CAAC;QAAC,MAAM,CAAC;YACP,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,6BAA6B,EAAE,CAAC,CAAC;QACnF,CAAC;IACH,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,GAAY,EAAE,GAAa;QAC7C,IAAI,CAAC;YACH,MAAM,OAAO,GAAI,GAAW,CAAC,YAAY,CAAC;YAC1C,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,gCAAgC,EAAE,CAAC,CAAC;YAC7F,CAAC;YAED,MAAM,OAAO,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YACrE,GAAG,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,iBAAiB,EAAE,CAAC,CAAC;QAC1D,CAAC;QAAC,MAAM,CAAC;YACP,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,0BAA0B,EAAE,CAAC,CAAC;QAChF,CAAC;IACH,CAAC;IAED,KAAK,CAAC,iBAAiB,CAAC,GAAY,EAAE,GAAa;QACjD,IAAI,CAAC;YACH,MAAM,OAAO,GAAI,GAAW,CAAC,YAAY,CAAC;YAC1C,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,gCAAgC,EAAE,CAAC,CAAC;YAC7F,CAAC;YAED,MAAM,OAAO,CAAC,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YACnD,GAAG,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,sBAAsB,EAAE,CAAC,CAAC;QAC/D,CAAC;QAAC,MAAM,CAAC;YACP,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,2BAA2B,EAAE,CAAC,CAAC;QACjF,CAAC;IACH,CAAC;CACF,CAAC,CAAC;AA9CU,QAAA,yBAAyB,6BA8CnC"}
@@ -0,0 +1,2 @@
1
+ export declare const createProtectedRoutes: (auth: any) => import("express-serve-static-core").Router;
2
+ //# sourceMappingURL=protected.routes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protected.routes.d.ts","sourceRoot":"","sources":["../../../../../templates/express-auth/src/routes/protected.routes.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,qBAAqB,GAAI,MAAM,GAAG,+CAU9C,CAAC"}
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createProtectedRoutes = void 0;
4
+ const express_1 = require("express");
5
+ const protected_controller_1 = require("../controllers/protected.controller");
6
+ const createProtectedRoutes = (auth) => {
7
+ const router = (0, express_1.Router)();
8
+ const controller = (0, protected_controller_1.createProtectedController)();
9
+ router.get("/protected", auth.requireAdmin, controller.protected);
10
+ router.get("/admin/sessions/:userId", auth.requireAdmin, controller.listSessions);
11
+ router.delete("/admin/sessions/:userId/:sessionId", auth.requireAdmin, controller.revokeSession);
12
+ router.delete("/admin/sessions/:userId", auth.requireAdmin, controller.revokeAllSessions);
13
+ return router;
14
+ };
15
+ exports.createProtectedRoutes = createProtectedRoutes;
16
+ //# sourceMappingURL=protected.routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protected.routes.js","sourceRoot":"","sources":["../../../../../templates/express-auth/src/routes/protected.routes.ts"],"names":[],"mappings":";;;AAAA,qCAAiC;AACjC,8EAAgF;AAEzE,MAAM,qBAAqB,GAAG,CAAC,IAAS,EAAE,EAAE;IACjD,MAAM,MAAM,GAAG,IAAA,gBAAM,GAAE,CAAC;IACxB,MAAM,UAAU,GAAG,IAAA,gDAAyB,GAAE,CAAC;IAE/C,MAAM,CAAC,GAAG,CAAC,YAAY,EAAE,IAAI,CAAC,YAAY,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC;IAClE,MAAM,CAAC,GAAG,CAAC,yBAAyB,EAAE,IAAI,CAAC,YAAY,EAAE,UAAU,CAAC,YAAY,CAAC,CAAC;IAClF,MAAM,CAAC,MAAM,CAAC,oCAAoC,EAAE,IAAI,CAAC,YAAY,EAAE,UAAU,CAAC,aAAa,CAAC,CAAC;IACjG,MAAM,CAAC,MAAM,CAAC,yBAAyB,EAAE,IAAI,CAAC,YAAY,EAAE,UAAU,CAAC,iBAAiB,CAAC,CAAC;IAE1F,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AAVW,QAAA,qBAAqB,yBAUhC"}
@@ -0,0 +1,8 @@
1
+ export declare function requiredSecret(name: string): string;
2
+ export declare function parseCredentials(body: unknown): {
3
+ email: string;
4
+ password: string;
5
+ };
6
+ export declare function parseRefreshToken(body: unknown): string;
7
+ export declare function sanitizeSessionResponse(value: unknown): unknown;
8
+ //# sourceMappingURL=security.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../../../../../templates/express-auth/src/utils/security.ts"],"names":[],"mappings":"AAEA,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQnD;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO;;;EAyB7C;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,OAAO,UAY9C;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAc/D"}
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.requiredSecret = requiredSecret;
4
+ exports.parseCredentials = parseCredentials;
5
+ exports.parseRefreshToken = parseRefreshToken;
6
+ exports.sanitizeSessionResponse = sanitizeSessionResponse;
7
+ const sensitiveKeys = new Set(["token", "accessToken", "refreshToken"]);
8
+ function requiredSecret(name) {
9
+ const value = process.env[name];
10
+ if (typeof value !== "string" || value.trim().length < 32) {
11
+ throw new Error(`${name} must be set to at least 32 characters`);
12
+ }
13
+ return value;
14
+ }
15
+ function parseCredentials(body) {
16
+ if (!body || typeof body !== "object") {
17
+ throw new Error("Email and password are required");
18
+ }
19
+ const { email, password } = body;
20
+ if (typeof email !== "string" || typeof password !== "string") {
21
+ throw new Error("Email and password are required");
22
+ }
23
+ const normalizedEmail = email.trim().toLowerCase();
24
+ const atIndex = normalizedEmail.indexOf("@");
25
+ const dotIndex = normalizedEmail.lastIndexOf(".");
26
+ if (atIndex < 1 || atIndex !== normalizedEmail.lastIndexOf("@") || dotIndex < atIndex + 2 || dotIndex === normalizedEmail.length - 1) {
27
+ throw new Error("A valid email is required");
28
+ }
29
+ if (password.length < 8 || password.length > 1024) {
30
+ throw new Error("Password must be between 8 and 1024 characters");
31
+ }
32
+ return { email: normalizedEmail, password };
33
+ }
34
+ function parseRefreshToken(body) {
35
+ if (!body || typeof body !== "object") {
36
+ throw new Error("Refresh token is required");
37
+ }
38
+ const { refreshToken } = body;
39
+ if (typeof refreshToken !== "string" || refreshToken.trim().length < 16) {
40
+ throw new Error("Refresh token is required");
41
+ }
42
+ return refreshToken;
43
+ }
44
+ function sanitizeSessionResponse(value) {
45
+ if (Array.isArray(value)) {
46
+ return value.map(sanitizeSessionResponse);
47
+ }
48
+ if (!value || typeof value !== "object") {
49
+ return value;
50
+ }
51
+ return Object.fromEntries(Object.entries(value)
52
+ .filter(([key]) => !sensitiveKeys.has(key))
53
+ .map(([key, nestedValue]) => [key, sanitizeSessionResponse(nestedValue)]));
54
+ }
55
+ //# sourceMappingURL=security.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.js","sourceRoot":"","sources":["../../../../../templates/express-auth/src/utils/security.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { Request, Response } from "express";
2
+ export declare const createBaseController: (auth: any) => {
3
+ publicRoute(req: Request, res: Response): void;
4
+ guest(req: Request, res: Response): Promise<void>;
5
+ protected(req: Request, res: Response): Promise<void>;
6
+ refresh(req: Request, res: Response): Promise<void>;
7
+ admin(req: Request, res: Response): void;
8
+ listSessions(req: Request, res: Response): Promise<Response<any, Record<string, any>> | undefined>;
9
+ revokeSession(req: Request, res: Response): Promise<Response<any, Record<string, any>> | undefined>;
10
+ revokeAllSessions(req: Request, res: Response): Promise<Response<any, Record<string, any>> | undefined>;
11
+ };
12
+ //# sourceMappingURL=base.controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.controller.d.ts","sourceRoot":"","sources":["../../../../templates/express-base/controllers/base.controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAG5C,eAAO,MAAM,oBAAoB,GAAI,MAAM,GAAG;qBAC3B,OAAO,OAAO,QAAQ;eAItB,OAAO,OAAO,QAAQ;mBAKlB,OAAO,OAAO,QAAQ;iBAWxB,OAAO,OAAO,QAAQ;eAU9B,OAAO,OAAO,QAAQ;sBAIT,OAAO,OAAO,QAAQ;uBAcrB,OAAO,OAAO,QAAQ;2BAclB,OAAO,OAAO,QAAQ;CAanD,CAAC"}
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createBaseController = void 0;
4
+ const security_1 = require("../utils/security");
5
+ const createBaseController = (auth) => ({
6
+ publicRoute(req, res) {
7
+ res.json({ message: "Public route" });
8
+ },
9
+ async guest(req, res) {
10
+ const token = await auth.guestToken({ role: "guest" });
11
+ res.json({ token });
12
+ },
13
+ async protected(req, res) {
14
+ const token = (0, security_1.getBearerToken)(req.headers.authorization);
15
+ try {
16
+ const decoded = await auth.verifyToken(token);
17
+ res.json({ message: "Protected data", user: decoded });
18
+ }
19
+ catch {
20
+ res.status(401).json({ error: "Unauthorized" });
21
+ }
22
+ },
23
+ async refresh(req, res) {
24
+ try {
25
+ const refreshToken = (0, security_1.parseRefreshToken)(req.body);
26
+ const tokens = await auth.refreshToken(refreshToken);
27
+ res.json(tokens);
28
+ }
29
+ catch {
30
+ res.status(401).json({ error: "Invalid refresh token" });
31
+ }
32
+ },
33
+ admin(req, res) {
34
+ res.json({ message: "Admin only" });
35
+ },
36
+ async listSessions(req, res) {
37
+ try {
38
+ const actions = req.adminActions;
39
+ if (!actions) {
40
+ return res.status(503).json({ success: false, message: "Session management unavailable" });
41
+ }
42
+ const sessions = await actions.listSessions(req.params.userId);
43
+ res.json({ sessions: (0, security_1.sanitizeSessionResponse)(sessions) });
44
+ }
45
+ catch {
46
+ res.status(500).json({ success: false, message: "Failed to retrieve sessions" });
47
+ }
48
+ },
49
+ async revokeSession(req, res) {
50
+ try {
51
+ const actions = req.adminActions;
52
+ if (!actions) {
53
+ return res.status(503).json({ success: false, message: "Session management unavailable" });
54
+ }
55
+ await actions.revokeSession(req.params.userId, req.params.sessionId);
56
+ res.json({ success: true, message: "Session revoked" });
57
+ }
58
+ catch {
59
+ res.status(500).json({ success: false, message: "Failed to revoke session" });
60
+ }
61
+ },
62
+ async revokeAllSessions(req, res) {
63
+ try {
64
+ const actions = req.adminActions;
65
+ if (!actions) {
66
+ return res.status(503).json({ success: false, message: "Session management unavailable" });
67
+ }
68
+ await actions.revokeAllSessions(req.params.userId);
69
+ res.json({ success: true, message: "All sessions revoked" });
70
+ }
71
+ catch {
72
+ res.status(500).json({ success: false, message: "Failed to revoke sessions" });
73
+ }
74
+ },
75
+ });
76
+ exports.createBaseController = createBaseController;
77
+ //# sourceMappingURL=base.controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.controller.js","sourceRoot":"","sources":["../../../../templates/express-base/controllers/base.controller.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare const createBaseRoutes: (auth: any) => import("express-serve-static-core").Router;
2
+ //# sourceMappingURL=base.routes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.routes.d.ts","sourceRoot":"","sources":["../../../../templates/express-base/routes/base.routes.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,gBAAgB,GAAI,MAAM,GAAG,+CAezC,CAAC"}
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createBaseRoutes = void 0;
4
+ const express_1 = require("express");
5
+ const base_controller_1 = require("../controllers/base.controller");
6
+ const createBaseRoutes = (auth) => {
7
+ const router = (0, express_1.Router)();
8
+ const controller = (0, base_controller_1.createBaseController)(auth);
9
+ router.get("/public", controller.publicRoute);
10
+ router.get("/guest", controller.guest);
11
+ router.get("/protected", controller.protected);
12
+ router.post("/refresh", controller.refresh);
13
+ router.get("/admin", auth.requireAdmin, controller.admin);
14
+ router.get("/admin/sessions/:userId", auth.requireAdmin, controller.listSessions);
15
+ router.delete("/admin/sessions/:userId/:sessionId", auth.requireAdmin, controller.revokeSession);
16
+ router.delete("/admin/sessions/:userId", auth.requireAdmin, controller.revokeAllSessions);
17
+ return router;
18
+ };
19
+ exports.createBaseRoutes = createBaseRoutes;
20
+ //# sourceMappingURL=base.routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.routes.js","sourceRoot":"","sources":["../../../../templates/express-base/routes/base.routes.ts"],"names":[],"mappings":";;;AAAA,qCAAiC;AACjC,oEAAsE;AAE/D,MAAM,gBAAgB,GAAG,CAAC,IAAS,EAAE,EAAE;IAC5C,MAAM,MAAM,GAAG,IAAA,gBAAM,GAAE,CAAC;IACxB,MAAM,UAAU,GAAG,IAAA,sCAAoB,EAAC,IAAI,CAAC,CAAC;IAE9C,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,UAAU,CAAC,WAAW,CAAC,CAAC;IAC9C,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC;IACvC,MAAM,CAAC,GAAG,CAAC,YAAY,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC;IAC/C,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC;IAE5C,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,YAAY,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC;IAC1D,MAAM,CAAC,GAAG,CAAC,yBAAyB,EAAE,IAAI,CAAC,YAAY,EAAE,UAAU,CAAC,YAAY,CAAC,CAAC;IAClF,MAAM,CAAC,MAAM,CAAC,oCAAoC,EAAE,IAAI,CAAC,YAAY,EAAE,UAAU,CAAC,aAAa,CAAC,CAAC;IACjG,MAAM,CAAC,MAAM,CAAC,yBAAyB,EAAE,IAAI,CAAC,YAAY,EAAE,UAAU,CAAC,iBAAiB,CAAC,CAAC;IAE1F,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AAfW,QAAA,gBAAgB,oBAe3B"}
@@ -0,0 +1,5 @@
1
+ export declare function requiredSecret(name: string): string;
2
+ export declare function getBearerToken(authorizationHeader: string | undefined): string | undefined;
3
+ export declare function parseRefreshToken(body: unknown): string;
4
+ export declare function sanitizeSessionResponse(value: unknown): unknown;
5
+ //# sourceMappingURL=security.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../../../../templates/express-base/utils/security.ts"],"names":[],"mappings":"AAEA,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQnD;AAED,wBAAgB,cAAc,CAAC,mBAAmB,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAG1F;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,OAAO,UAY9C;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAc/D"}
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.requiredSecret = requiredSecret;
4
+ exports.getBearerToken = getBearerToken;
5
+ exports.parseRefreshToken = parseRefreshToken;
6
+ exports.sanitizeSessionResponse = sanitizeSessionResponse;
7
+ const sensitiveKeys = new Set(["token", "accessToken", "refreshToken"]);
8
+ function requiredSecret(name) {
9
+ const value = process.env[name];
10
+ if (typeof value !== "string" || value.trim().length < 32) {
11
+ throw new Error(`${name} must be set to at least 32 characters`);
12
+ }
13
+ return value;
14
+ }
15
+ function getBearerToken(authorizationHeader) {
16
+ const [scheme, token] = authorizationHeader?.split(" ") ?? [];
17
+ return scheme === "Bearer" && token ? token : undefined;
18
+ }
19
+ function parseRefreshToken(body) {
20
+ if (!body || typeof body !== "object") {
21
+ throw new Error("Refresh token is required");
22
+ }
23
+ const { refreshToken } = body;
24
+ if (typeof refreshToken !== "string" || refreshToken.trim().length < 16) {
25
+ throw new Error("Refresh token is required");
26
+ }
27
+ return refreshToken;
28
+ }
29
+ function sanitizeSessionResponse(value) {
30
+ if (Array.isArray(value)) {
31
+ return value.map(sanitizeSessionResponse);
32
+ }
33
+ if (!value || typeof value !== "object") {
34
+ return value;
35
+ }
36
+ return Object.fromEntries(Object.entries(value)
37
+ .filter(([key]) => !sensitiveKeys.has(key))
38
+ .map(([key, nestedValue]) => [key, sanitizeSessionResponse(nestedValue)]));
39
+ }
40
+ //# sourceMappingURL=security.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.js","sourceRoot":"","sources":["../../../../templates/express-base/utils/security.ts"],"names":[],"mappings":";;AAEA,wCAQC;AAED,wCAGC;AAED,8CAYC;AAED,0DAcC;AA7CD,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,aAAa,EAAE,cAAc,CAAC,CAAC,CAAC;AAExE,SAAgB,cAAc,CAAC,IAAY;IACzC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAEhC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;QAC1D,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,wCAAwC,CAAC,CAAC;IACnE,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAgB,cAAc,CAAC,mBAAuC;IACpE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,mBAAmB,EAAE,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;IAC9D,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AAC1D,CAAC;AAED,SAAgB,iBAAiB,CAAC,IAAa;IAC7C,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtC,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;IAC/C,CAAC;IAED,MAAM,EAAE,YAAY,EAAE,GAAG,IAAkC,CAAC;IAE5D,IAAI,OAAO,YAAY,KAAK,QAAQ,IAAI,YAAY,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;QACxE,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;IAC/C,CAAC;IAED,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,SAAgB,uBAAuB,CAAC,KAAc;IACpD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,KAAK,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;IAC5C,CAAC;IAED,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACxC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,OAAO,CAAC,KAAgC,CAAC;SAC7C,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;SAC1C,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,WAAW,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,uBAAuB,CAAC,WAAW,CAAC,CAAC,CAAC,CAC5E,CAAC;AACJ,CAAC"}
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "authenik8-app",
3
+ "description": "Authenik8 generated Express auth app",
4
+ "main": "dist/server.js",
5
+ "type": "commonjs",
6
+ "scripts": {
7
+ "dev": "ts-node-dev --respawn --transpile-only src/server.ts",
8
+ "build": "tsc",
9
+ "start": "node dist/server.js",
10
+ "prisma:migrate": "prisma migrate dev",
11
+ "docker:up": "docker compose up -d",
12
+ "docker:down": "docker compose down"
13
+ },
14
+ "dependencies": {
15
+ "authenik8-core": "^1.0.33",
16
+ "dotenv": "^16.0.0",
17
+ "express": "^4.19.2",
18
+ "@prisma/client": "5.22.0"
19
+ },
20
+ "devDependencies": {
21
+ "@types/express": "^4.17.21",
22
+ "@types/node": "^20.0.0",
23
+ "ts-node-dev": "^2.0.0",
24
+ "typescript": "^5.0.0",
25
+ "prisma": "5.22.0"
26
+ }
27
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-authenik8-app",
3
- "version": "2.4.5",
3
+ "version": "2.4.7",
4
4
  "description": " Fast Express + TypeScript auth starter with secure JWT, refresh rotation, Redis, RBAC, OAuth & Prisma.\nPowered by the Authenik8 Identity Engine.",
5
5
  "bin": {
6
6
  "create-authenik8-app": "dist/src/bin/index.js"
@@ -39,20 +39,21 @@
39
39
  "typescript": "^6.0.3"
40
40
  },
41
41
  "files": [
42
- "dist",
43
- "templates"
42
+ "dist/",
43
+ "templates/"
44
44
  ],
45
45
  "scripts": {
46
+ "build": "tsc && cp -r ./templates/express-auth/package.json ./templates/THREAT_MODEL.md dist/templates",
47
+ "prepublishOnly": "npm run build",
46
48
  "test": "vitest run",
47
49
  "test:watch": "vitest",
48
50
  "test:coverage": "vitest run --coverage",
49
- "test:templates": "node --import tsx --test tests/template-servers.test.mjs",
50
- "build": "tsc && cp -r ./templates/express-auth/package.json ./templates/THREAT_MODEL.md dist/templates"
51
+ "test:templates": "node --import tsx --test tests/template-servers.test.mjs"
51
52
  },
52
53
  "devDependencies": {
53
54
  "@types/express": "^5.0.6",
54
55
  "@types/fs-extra": "^11.0.4",
55
- "@types/node": "^25.5.2",
56
+ "@types/node": "^25.9.1",
56
57
  "@types/supertest": "^7.2.0",
57
58
  "@vitest/coverage-v8": "^4.1.8",
58
59
  "supertest": "^7.2.2",