create-authenik8-app 2.4.12 → 2.4.14
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/README.md +160 -57
- package/assets/logo.svg +53 -0
- package/dist/src/bin/index.js +199 -125
- package/dist/src/bin/index.js.map +1 -1
- package/dist/src/lib/args.d.ts +18 -0
- package/dist/src/lib/args.d.ts.map +1 -0
- package/dist/src/lib/args.js +82 -0
- package/dist/src/lib/args.js.map +1 -0
- package/dist/src/lib/constants.d.ts +1 -0
- package/dist/src/lib/constants.d.ts.map +1 -1
- package/dist/src/lib/constants.js +10 -11
- package/dist/src/lib/constants.js.map +1 -1
- package/dist/src/lib/preflight.d.ts +3 -0
- package/dist/src/lib/preflight.d.ts.map +1 -0
- package/dist/src/lib/preflight.js +21 -0
- package/dist/src/lib/preflight.js.map +1 -0
- package/dist/src/lib/process.d.ts +6 -2
- package/dist/src/lib/process.d.ts.map +1 -1
- package/dist/src/lib/process.js +66 -8
- package/dist/src/lib/process.js.map +1 -1
- package/dist/src/lib/projectName.d.ts +2 -0
- package/dist/src/lib/projectName.d.ts.map +1 -0
- package/dist/src/lib/projectName.js +6 -0
- package/dist/src/lib/projectName.js.map +1 -0
- package/dist/src/lib/schemas.d.ts +192 -0
- package/dist/src/lib/schemas.d.ts.map +1 -0
- package/dist/src/lib/schemas.js +171 -0
- package/dist/src/lib/schemas.js.map +1 -0
- package/dist/src/lib/state.d.ts.map +1 -1
- package/dist/src/lib/state.js +20 -3
- package/dist/src/lib/state.js.map +1 -1
- package/dist/src/lib/types.d.ts +6 -13
- package/dist/src/lib/types.d.ts.map +1 -1
- package/dist/src/lib/ui.d.ts +8 -3
- package/dist/src/lib/ui.d.ts.map +1 -1
- package/dist/src/lib/ui.js +76 -112
- package/dist/src/lib/ui.js.map +1 -1
- package/dist/src/steps/configurePrisma.d.ts.map +1 -1
- package/dist/src/steps/configurePrisma.js +83 -9
- package/dist/src/steps/configurePrisma.js.map +1 -1
- package/dist/src/steps/createProject.d.ts +2 -1
- package/dist/src/steps/createProject.d.ts.map +1 -1
- package/dist/src/steps/createProject.js +148 -27
- package/dist/src/steps/createProject.js.map +1 -1
- package/dist/src/steps/finalSetup.d.ts +3 -3
- package/dist/src/steps/finalSetup.d.ts.map +1 -1
- package/dist/src/steps/finalSetup.js +24 -28
- package/dist/src/steps/finalSetup.js.map +1 -1
- package/dist/src/steps/installAuth.d.ts +1 -1
- package/dist/src/steps/installAuth.d.ts.map +1 -1
- package/dist/src/steps/installAuth.js +5 -4
- package/dist/src/steps/installAuth.js.map +1 -1
- package/dist/src/steps/installDeps.d.ts +11 -4
- package/dist/src/steps/installDeps.d.ts.map +1 -1
- package/dist/src/steps/installDeps.js +45 -77
- package/dist/src/steps/installDeps.js.map +1 -1
- package/dist/src/steps/prompts.d.ts +1 -1
- package/dist/src/steps/prompts.d.ts.map +1 -1
- package/dist/src/steps/prompts.js +42 -30
- package/dist/src/steps/prompts.js.map +1 -1
- package/dist/src/utils/jwk.d.ts +2 -0
- package/dist/src/utils/jwk.d.ts.map +1 -0
- package/dist/src/utils/jwk.js +44 -0
- package/dist/src/utils/jwk.js.map +1 -0
- package/dist/src/utils/output.d.ts +1 -1
- package/dist/src/utils/output.d.ts.map +1 -1
- package/dist/src/utils/output.js +75 -68
- package/dist/src/utils/output.js.map +1 -1
- package/package.json +17 -9
- package/templates/AGENT_IDENTITY.md +112 -0
- package/templates/THREAT_MODEL.md +27 -5
- package/templates/express-auth/README.md +13 -10
- package/templates/express-auth/docker-compose.yml +10 -0
- package/templates/express-auth/gitignore.template +6 -0
- package/templates/express-auth/package.json +12 -5
- package/templates/express-auth/src/app.ts +2 -0
- package/templates/express-auth/src/controllers/auth.controller.ts +2 -6
- package/templates/express-auth/src/controllers/protected.controller.ts +25 -10
- package/templates/express-auth/src/middleware/auth.middleware.ts +1 -0
- package/templates/express-auth/src/routes/protected.routes.ts +3 -1
- package/templates/express-auth/src/server.ts +6 -12
- package/templates/express-auth/src/utils/security.ts +119 -32
- package/templates/express-auth+/README.md +13 -10
- package/templates/express-auth+/docker-compose.yml +10 -0
- package/templates/express-auth+/gitignore.template +6 -0
- package/templates/express-auth+/package.json +12 -5
- package/templates/express-auth+/src/auth/auth.ts +3 -2
- package/templates/express-auth+/src/auth/controllers/password.controller.ts +3 -7
- package/templates/express-auth+/src/auth/controllers/protected.controller.ts +26 -11
- package/templates/express-auth+/src/auth/identity.adapter.ts +90 -0
- package/templates/express-auth+/src/auth/middleware/auth.middleware.ts +3 -4
- package/templates/express-auth+/src/auth/routes/protected.routes.ts +2 -2
- package/templates/express-auth+/src/oauth-providers/github/src/auth/auth.ts +3 -2
- package/templates/express-auth+/src/oauth-providers/google/src/auth/auth.ts +3 -2
- package/templates/express-auth+/src/oauth-providers/google-github/src/auth/auth.ts +3 -2
- package/templates/express-auth+/src/server.ts +5 -10
- package/templates/express-auth+/src/utils/security.ts +109 -28
- package/templates/express-base/README.md +13 -6
- package/templates/express-base/app.ts +2 -0
- package/templates/express-base/controllers/base.controller.ts +33 -19
- package/templates/express-base/docker-compose.yml +10 -0
- package/templates/express-base/gitignore.template +6 -0
- package/templates/express-base/package.json +11 -5
- package/templates/express-base/routes/base.routes.ts +1 -1
- package/templates/express-base/src/.env.example +7 -2
- package/templates/express-base/src/server.ts +6 -12
- package/templates/express-base/tsconfig.json +7 -40
- package/templates/express-base/utils/security.ts +111 -15
- package/templates/fullstack/.env.example +24 -0
- package/templates/fullstack/PRESET_CONTRACT.md +46 -0
- package/templates/fullstack/README.md +65 -0
- package/templates/fullstack/THREAT_MODEL.md +30 -0
- package/templates/fullstack/apps/api/package.json +48 -0
- package/templates/fullstack/apps/api/prisma/schema.prisma +124 -0
- package/templates/fullstack/apps/api/prisma/seed.ts +36 -0
- package/templates/fullstack/apps/api/prisma.config.ts +18 -0
- package/templates/fullstack/apps/api/src/app.ts +68 -0
- package/templates/fullstack/apps/api/src/auth/auth.controller.ts +125 -0
- package/templates/fullstack/apps/api/src/auth/auth.routes.ts +50 -0
- package/templates/fullstack/apps/api/src/auth/auth.service.ts +257 -0
- package/templates/fullstack/apps/api/src/auth/authenik8.ts +67 -0
- package/templates/fullstack/apps/api/src/auth/cookies.ts +36 -0
- package/templates/fullstack/apps/api/src/config/env.ts +72 -0
- package/templates/fullstack/apps/api/src/config/logger.ts +17 -0
- package/templates/fullstack/apps/api/src/config/mailer.ts +32 -0
- package/templates/fullstack/apps/api/src/config/origins.ts +27 -0
- package/templates/fullstack/apps/api/src/config/prisma.ts +9 -0
- package/templates/fullstack/apps/api/src/middleware/authenticate.ts +35 -0
- package/templates/fullstack/apps/api/src/middleware/csrf.ts +60 -0
- package/templates/fullstack/apps/api/src/middleware/origin.ts +12 -0
- package/templates/fullstack/apps/api/src/middleware/request-id.ts +9 -0
- package/templates/fullstack/apps/api/src/modules/admin/admin.controller.ts +17 -0
- package/templates/fullstack/apps/api/src/modules/admin/admin.routes.ts +14 -0
- package/templates/fullstack/apps/api/src/modules/admin/admin.service.ts +54 -0
- package/templates/fullstack/apps/api/src/modules/projects/project.controller.ts +22 -0
- package/templates/fullstack/apps/api/src/modules/projects/project.policy.ts +14 -0
- package/templates/fullstack/apps/api/src/modules/projects/project.repository.ts +20 -0
- package/templates/fullstack/apps/api/src/modules/projects/project.routes.ts +21 -0
- package/templates/fullstack/apps/api/src/modules/projects/project.service.ts +41 -0
- package/templates/fullstack/apps/api/src/modules/users/user.controller.ts +26 -0
- package/templates/fullstack/apps/api/src/modules/users/user.presenter.ts +13 -0
- package/templates/fullstack/apps/api/src/modules/users/user.routes.ts +21 -0
- package/templates/fullstack/apps/api/src/modules/users/user.service.ts +71 -0
- package/templates/fullstack/apps/api/src/openapi.ts +32 -0
- package/templates/fullstack/apps/api/src/server.ts +29 -0
- package/templates/fullstack/apps/api/src/types.ts +15 -0
- package/templates/fullstack/apps/api/src/utils/crypto.ts +4 -0
- package/templates/fullstack/apps/api/src/utils/http.ts +33 -0
- package/templates/fullstack/apps/api/src/utils/sealed-value.ts +37 -0
- package/templates/fullstack/apps/api/tests/project.policy.test.ts +26 -0
- package/templates/fullstack/apps/api/tests/registration.test.ts +69 -0
- package/templates/fullstack/apps/api/tests/security.test.ts +98 -0
- package/templates/fullstack/apps/api/tests/validation.test.ts +37 -0
- package/templates/fullstack/apps/api/tsconfig.json +16 -0
- package/templates/fullstack/apps/api/vitest.config.ts +9 -0
- package/templates/fullstack/apps/web/index.html +14 -0
- package/templates/fullstack/apps/web/package.json +31 -0
- package/templates/fullstack/apps/web/public/authenik8-logo.svg +53 -0
- package/templates/fullstack/apps/web/src/App.tsx +45 -0
- package/templates/fullstack/apps/web/src/auth/AuthProvider.tsx +53 -0
- package/templates/fullstack/apps/web/src/auth/RouteGuards.tsx +16 -0
- package/templates/fullstack/apps/web/src/auth/providers.ts +3 -0
- package/templates/fullstack/apps/web/src/components/AppShell.tsx +80 -0
- package/templates/fullstack/apps/web/src/components/AuthShell.tsx +26 -0
- package/templates/fullstack/apps/web/src/components/Page.tsx +30 -0
- package/templates/fullstack/apps/web/src/features/projects/ProjectPages.tsx +79 -0
- package/templates/fullstack/apps/web/src/main.tsx +24 -0
- package/templates/fullstack/apps/web/src/pages/DashboardPage.tsx +48 -0
- package/templates/fullstack/apps/web/src/pages/StatusPages.tsx +8 -0
- package/templates/fullstack/apps/web/src/pages/admin/AuditPage.tsx +19 -0
- package/templates/fullstack/apps/web/src/pages/admin/UsersPage.tsx +24 -0
- package/templates/fullstack/apps/web/src/pages/auth/LoginPage.tsx +51 -0
- package/templates/fullstack/apps/web/src/pages/auth/OAuthCallbackPage.tsx +26 -0
- package/templates/fullstack/apps/web/src/pages/auth/RecoveryPages.tsx +53 -0
- package/templates/fullstack/apps/web/src/pages/auth/RegisterPage.tsx +86 -0
- package/templates/fullstack/apps/web/src/pages/auth/VerifyEmailPage.tsx +24 -0
- package/templates/fullstack/apps/web/src/pages/settings/ProfilePage.tsx +34 -0
- package/templates/fullstack/apps/web/src/pages/settings/SecurityPage.tsx +57 -0
- package/templates/fullstack/apps/web/src/styles.css +289 -0
- package/templates/fullstack/apps/web/src/token-storage.test.ts +12 -0
- package/templates/fullstack/apps/web/tsconfig.app.json +19 -0
- package/templates/fullstack/apps/web/tsconfig.json +7 -0
- package/templates/fullstack/apps/web/tsconfig.node.json +10 -0
- package/templates/fullstack/apps/web/vite.config.ts +18 -0
- package/templates/fullstack/docker-compose.yml +35 -0
- package/templates/fullstack/docs/PRODUCTION.md +30 -0
- package/templates/fullstack/gitignore.template +8 -0
- package/templates/fullstack/package.json +39 -0
- package/templates/fullstack/packages/api-client/package.json +20 -0
- package/templates/fullstack/packages/api-client/src/index.ts +203 -0
- package/templates/fullstack/packages/api-client/tsconfig.json +14 -0
- package/templates/fullstack/packages/contracts/package.json +20 -0
- package/templates/fullstack/packages/contracts/src/index.ts +146 -0
- package/templates/fullstack/packages/contracts/tsconfig.json +13 -0
- package/templates/fullstack/packages/ui/package.json +22 -0
- package/templates/fullstack/packages/ui/src/index.tsx +33 -0
- package/templates/fullstack/packages/ui/tsconfig.json +14 -0
- package/templates/prisma/postgresql/.env.example +6 -2
- package/templates/prisma/postgresql/client.ts +17 -0
- package/templates/prisma/postgresql/prisma.config.ts +12 -0
- package/templates/prisma/postgresql/schema.prisma +0 -1
- package/templates/prisma/sqlite/.env.example +6 -2
- package/templates/prisma/sqlite/client.ts +16 -0
- package/templates/prisma/sqlite/prisma.config.ts +12 -0
- package/templates/prisma/sqlite/schema.prisma +0 -1
- package/dist/src/tests/templated-routes.test.d.ts +0 -2
- package/dist/src/tests/templated-routes.test.d.ts.map +0 -1
- package/dist/src/tests/templated-routes.test.js +0 -325
- package/dist/src/tests/templated-routes.test.js.map +0 -1
- package/dist/templates/THREAT_MODEL.md +0 -138
- package/dist/templates/express-auth/src/controllers/protected.controller.d.ts +0 -8
- package/dist/templates/express-auth/src/controllers/protected.controller.d.ts.map +0 -1
- package/dist/templates/express-auth/src/controllers/protected.controller.js +0 -50
- package/dist/templates/express-auth/src/controllers/protected.controller.js.map +0 -1
- package/dist/templates/express-auth/src/routes/protected.routes.d.ts +0 -2
- package/dist/templates/express-auth/src/routes/protected.routes.d.ts.map +0 -1
- package/dist/templates/express-auth/src/routes/protected.routes.js +0 -16
- package/dist/templates/express-auth/src/routes/protected.routes.js.map +0 -1
- package/dist/templates/express-auth/src/utils/security.d.ts +0 -8
- package/dist/templates/express-auth/src/utils/security.d.ts.map +0 -1
- package/dist/templates/express-auth/src/utils/security.js +0 -55
- package/dist/templates/express-auth/src/utils/security.js.map +0 -1
- package/dist/templates/express-base/controllers/base.controller.d.ts +0 -12
- package/dist/templates/express-base/controllers/base.controller.d.ts.map +0 -1
- package/dist/templates/express-base/controllers/base.controller.js +0 -77
- package/dist/templates/express-base/controllers/base.controller.js.map +0 -1
- package/dist/templates/express-base/routes/base.routes.d.ts +0 -2
- package/dist/templates/express-base/routes/base.routes.d.ts.map +0 -1
- package/dist/templates/express-base/routes/base.routes.js +0 -20
- package/dist/templates/express-base/routes/base.routes.js.map +0 -1
- package/dist/templates/express-base/utils/security.d.ts +0 -5
- package/dist/templates/express-base/utils/security.d.ts.map +0 -1
- package/dist/templates/express-base/utils/security.js +0 -40
- package/dist/templates/express-base/utils/security.js.map +0 -1
- package/dist/templates/package.json +0 -27
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
3
|
+
color: #27302b;
|
|
4
|
+
background: #f3f5f2;
|
|
5
|
+
font-synthesis: none;
|
|
6
|
+
text-rendering: optimizeLegibility;
|
|
7
|
+
--ink: #27302b;
|
|
8
|
+
--muted: #69736c;
|
|
9
|
+
--line: #dce3dd;
|
|
10
|
+
--surface: #ffffff;
|
|
11
|
+
--navy: #123524;
|
|
12
|
+
--navy-soft: #1a4630;
|
|
13
|
+
--cyan: #218653;
|
|
14
|
+
--cyan-light: #e4f4e9;
|
|
15
|
+
--violet: #4d6880;
|
|
16
|
+
--violet-light: #e8eff4;
|
|
17
|
+
--green: #246a43;
|
|
18
|
+
--green-light: #e2f3e7;
|
|
19
|
+
--amber: #9a6512;
|
|
20
|
+
--amber-light: #fff1ce;
|
|
21
|
+
--red: #bd384c;
|
|
22
|
+
--red-light: #fde8ec;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
* { box-sizing: border-box; letter-spacing: 0; }
|
|
26
|
+
html, body, #root { min-height: 100%; margin: 0; }
|
|
27
|
+
body { min-width: 320px; background: #f3f5f2; }
|
|
28
|
+
button, input, textarea, select { font: inherit; }
|
|
29
|
+
button, a { -webkit-tap-highlight-color: transparent; }
|
|
30
|
+
a { color: var(--cyan); text-decoration: none; }
|
|
31
|
+
a:hover { color: #185f3c; }
|
|
32
|
+
h1, h2, h3, p { margin-top: 0; }
|
|
33
|
+
h1 { margin-bottom: 7px; font-size: 28px; line-height: 1.2; color: #1c2721; }
|
|
34
|
+
h2 { margin-bottom: 5px; font-size: 17px; line-height: 1.35; color: #243029; }
|
|
35
|
+
p { color: var(--muted); line-height: 1.6; }
|
|
36
|
+
code { overflow-wrap: anywhere; color: #246a43; font-family: "SFMono-Regular", Consolas, monospace; font-size: 12px; }
|
|
37
|
+
|
|
38
|
+
.button {
|
|
39
|
+
min-height: 40px;
|
|
40
|
+
padding: 9px 15px;
|
|
41
|
+
border: 1px solid transparent;
|
|
42
|
+
border-radius: 6px;
|
|
43
|
+
display: inline-flex;
|
|
44
|
+
align-items: center;
|
|
45
|
+
justify-content: center;
|
|
46
|
+
gap: 8px;
|
|
47
|
+
color: #fff;
|
|
48
|
+
background: var(--cyan);
|
|
49
|
+
font-weight: 700;
|
|
50
|
+
font-size: 14px;
|
|
51
|
+
line-height: 1;
|
|
52
|
+
cursor: pointer;
|
|
53
|
+
transition: background-color 150ms, border-color 150ms, box-shadow 150ms;
|
|
54
|
+
}
|
|
55
|
+
.button:hover { color: #fff; background: #176b41; }
|
|
56
|
+
.button:focus-visible, .input:focus-visible, .table-select:focus-visible, a:focus-visible { outline: 3px solid rgba(57, 201, 120, .24); outline-offset: 2px; }
|
|
57
|
+
.button:disabled { cursor: not-allowed; opacity: .55; }
|
|
58
|
+
.button-secondary { color: #344039; background: #fff; border-color: #cbd5cd; }
|
|
59
|
+
.button-secondary:hover { color: #1c2721; background: #f1f5f1; border-color: #aab8ad; }
|
|
60
|
+
.button-danger { background: var(--red); }
|
|
61
|
+
.button-danger:hover { background: #9e2e40; }
|
|
62
|
+
.button-ghost { color: #626e66; background: transparent; }
|
|
63
|
+
.button-ghost:hover { color: #26332b; background: #e9eeea; }
|
|
64
|
+
.icon-button { width: 40px; min-width: 40px; padding: 0; }
|
|
65
|
+
.full-width { width: 100%; }
|
|
66
|
+
|
|
67
|
+
.input {
|
|
68
|
+
width: 100%;
|
|
69
|
+
min-height: 42px;
|
|
70
|
+
padding: 9px 11px;
|
|
71
|
+
border: 1px solid #cbd6cd;
|
|
72
|
+
border-radius: 5px;
|
|
73
|
+
color: var(--ink);
|
|
74
|
+
background: #fff;
|
|
75
|
+
outline: 0;
|
|
76
|
+
}
|
|
77
|
+
.input:hover { border-color: #aab9ad; }
|
|
78
|
+
.input:focus { border-color: var(--cyan); box-shadow: 0 0 0 3px rgba(57, 201, 120, .14); }
|
|
79
|
+
.input:disabled { color: #858f88; background: #eef1ee; }
|
|
80
|
+
.textarea { min-height: 130px; resize: vertical; line-height: 1.5; }
|
|
81
|
+
.field { display: grid; gap: 7px; color: #364139; font-size: 13px; font-weight: 700; }
|
|
82
|
+
.field small { color: var(--red); font-weight: 600; }
|
|
83
|
+
.field-hint { margin: -6px 0 3px; font-size: 12px; }
|
|
84
|
+
.form-stack { display: grid; gap: 16px; }
|
|
85
|
+
.form-row { display: flex; gap: 12px; align-items: center; font-size: 13px; }
|
|
86
|
+
.form-row.end { justify-content: flex-end; margin-top: -7px; }
|
|
87
|
+
.form-actions { display: flex; justify-content: flex-end; gap: 10px; padding-top: 8px; }
|
|
88
|
+
.two-fields { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
|
|
89
|
+
|
|
90
|
+
.card, .panel, .form-panel, .detail-grid { border: 1px solid var(--line); border-radius: 7px; background: var(--surface); }
|
|
91
|
+
.badge { display: inline-flex; align-items: center; min-height: 24px; padding: 4px 8px; border-radius: 5px; color: #59635c; background: #ebefec; font-size: 11px; font-weight: 800; text-transform: capitalize; }
|
|
92
|
+
.badge-success { color: #176a46; background: var(--green-light); }
|
|
93
|
+
.badge-warning { color: #80500b; background: var(--amber-light); }
|
|
94
|
+
.badge-danger { color: #982b3d; background: var(--red-light); }
|
|
95
|
+
.badge-accent { color: #3f5f78; background: var(--violet-light); }
|
|
96
|
+
.spinner { width: 22px; height: 22px; display: inline-block; border: 3px solid #d6dbe5; border-top-color: var(--cyan); border-radius: 50%; animation: spin .7s linear infinite; }
|
|
97
|
+
@keyframes spin { to { transform: rotate(360deg); } }
|
|
98
|
+
.screen-loader { min-height: 50vh; display: grid; place-items: center; }
|
|
99
|
+
.panel-loading, .center-status { min-height: 180px; display: grid; place-items: center; }
|
|
100
|
+
|
|
101
|
+
.app-layout { min-height: 100vh; display: grid; grid-template-columns: 236px minmax(0, 1fr); }
|
|
102
|
+
.sidebar, .mobile-sidebar { background: var(--navy); color: #e2eee6; }
|
|
103
|
+
.sidebar { position: sticky; top: 0; height: 100vh; padding: 22px 14px 16px; display: flex; flex-direction: column; }
|
|
104
|
+
.brand { min-width: 0; display: flex; align-items: center; gap: 10px; color: #fff; font-weight: 800; }
|
|
105
|
+
.brand:hover { color: #fff; }
|
|
106
|
+
.brand img { width: 44px; height: 44px; margin: -5px; flex: 0 0 auto; }
|
|
107
|
+
.brand span { min-width: 0; display: grid; font-size: 15px; }
|
|
108
|
+
.brand small { color: #93b5a1; font-size: 10px; font-weight: 600; }
|
|
109
|
+
.side-nav { margin-top: 32px; display: grid; gap: 4px; }
|
|
110
|
+
.nav-label { margin: 18px 10px 5px; color: #769583; font-size: 10px; font-weight: 800; text-transform: uppercase; }
|
|
111
|
+
.side-nav a { min-height: 42px; padding: 10px 11px; border-radius: 5px; display: flex; align-items: center; gap: 11px; color: #b3c9bb; font-size: 13px; font-weight: 650; }
|
|
112
|
+
.side-nav a:hover { color: #fff; background: #19472f; }
|
|
113
|
+
.side-nav a.active { color: #fff; background: #20563a; box-shadow: inset 3px 0 0 #7ce8aa; }
|
|
114
|
+
.sidebar-account { min-width: 0; margin-top: auto; padding: 13px 7px 0; border-top: 1px solid #28533a; display: flex; align-items: center; gap: 10px; }
|
|
115
|
+
.avatar { width: 34px; height: 34px; flex: 0 0 auto; border-radius: 6px; display: grid; place-items: center; color: #17492f; background: #a7dfbf; font-size: 11px; font-weight: 900; }
|
|
116
|
+
.sidebar-account > div:last-child { min-width: 0; display: grid; gap: 2px; }
|
|
117
|
+
.sidebar-account strong, .sidebar-account span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
118
|
+
.sidebar-account strong { color: #f2faf5; font-size: 12px; }
|
|
119
|
+
.sidebar-account span { color: #8fad9a; font-size: 10px; }
|
|
120
|
+
.mobile-sidebar, .mobile-scrim { display: none; }
|
|
121
|
+
|
|
122
|
+
.app-main { min-width: 0; }
|
|
123
|
+
.topbar { height: 64px; padding: 0 28px; border-bottom: 1px solid var(--line); display: flex; align-items: center; gap: 14px; background: rgba(255,255,255,.95); position: sticky; top: 0; z-index: 20; }
|
|
124
|
+
.breadcrumb { min-width: 0; display: flex; align-items: center; gap: 8px; color: #626d65; font-size: 13px; font-weight: 700; }
|
|
125
|
+
.breadcrumb svg { color: var(--green); }
|
|
126
|
+
.topbar > .icon-button:last-child { margin-left: auto; }
|
|
127
|
+
.menu-button { display: none; }
|
|
128
|
+
.page { width: 100%; max-width: 1480px; margin: 0 auto; padding: 32px; }
|
|
129
|
+
.page-header { min-height: 62px; margin-bottom: 24px; display: flex; justify-content: space-between; align-items: flex-start; gap: 20px; }
|
|
130
|
+
.page-header p { margin-bottom: 0; font-size: 14px; }
|
|
131
|
+
.page-actions, .action-row { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 9px; }
|
|
132
|
+
|
|
133
|
+
.stat-grid { margin-bottom: 22px; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 14px; }
|
|
134
|
+
.stat-card { min-height: 92px; padding: 17px; display: flex; align-items: center; gap: 14px; }
|
|
135
|
+
.stat-card > div { min-width: 0; display: grid; gap: 5px; }
|
|
136
|
+
.stat-card span { color: #717c74; font-size: 12px; font-weight: 650; }
|
|
137
|
+
.stat-card strong { overflow-wrap: anywhere; color: #27302b; font-size: 21px; line-height: 1.1; }
|
|
138
|
+
.stat-icon { width: 38px; height: 38px; flex: 0 0 auto; border-radius: 6px; display: grid; place-items: center; }
|
|
139
|
+
.stat-icon.cyan { color: #1d7549; background: var(--cyan-light); }
|
|
140
|
+
.stat-icon.violet { color: #46647b; background: var(--violet-light); }
|
|
141
|
+
.stat-icon.green { color: #246a43; background: var(--green-light); }
|
|
142
|
+
.stat-icon.amber { color: #8a5a0f; background: var(--amber-light); }
|
|
143
|
+
.dashboard-grid { display: grid; grid-template-columns: minmax(0, 1.65fr) minmax(280px, .7fr); gap: 18px; align-items: start; }
|
|
144
|
+
.panel { min-width: 0; overflow: hidden; }
|
|
145
|
+
.panel-heading { min-height: 72px; padding: 18px 20px; border-bottom: 1px solid #e8eaf0; display: flex; justify-content: space-between; align-items: center; gap: 16px; }
|
|
146
|
+
.panel-heading h2, .panel-heading p { margin-bottom: 0; }
|
|
147
|
+
.panel-heading p { margin-top: 2px; font-size: 12px; }
|
|
148
|
+
.text-link, .back-link { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; font-weight: 750; }
|
|
149
|
+
.back-link { margin-bottom: 13px; }
|
|
150
|
+
.security-panel { padding-bottom: 18px; }
|
|
151
|
+
.check-list { margin: 0; padding: 8px 20px 18px; list-style: none; }
|
|
152
|
+
.check-list li { padding: 14px 0; border-bottom: 1px solid #eceef3; display: flex; align-items: center; gap: 11px; }
|
|
153
|
+
.check-list svg { color: var(--green); }
|
|
154
|
+
.check-list li.pending svg { color: var(--amber); }
|
|
155
|
+
.check-list span { display: grid; gap: 3px; }
|
|
156
|
+
.check-list strong { font-size: 13px; }
|
|
157
|
+
.check-list small { color: var(--muted); font-size: 11px; }
|
|
158
|
+
.security-panel > .button { margin: 0 20px; width: calc(100% - 40px); }
|
|
159
|
+
|
|
160
|
+
.table-wrap { max-width: 100%; overflow-x: auto; }
|
|
161
|
+
table { width: 100%; border-collapse: collapse; font-size: 13px; }
|
|
162
|
+
th, td { padding: 13px 18px; border-bottom: 1px solid #eceef3; text-align: left; vertical-align: middle; }
|
|
163
|
+
th { color: #737b8d; background: #fafbfc; font-size: 10px; font-weight: 850; text-transform: uppercase; white-space: nowrap; }
|
|
164
|
+
tbody tr:last-child td { border-bottom: 0; }
|
|
165
|
+
tbody tr:hover { background: #fbfcfd; }
|
|
166
|
+
.table-link { display: block; color: #2a352e; font-weight: 750; }
|
|
167
|
+
.table-subtitle { max-width: 320px; margin-top: 3px; display: block; overflow: hidden; color: #858c9b; font-size: 11px; text-overflow: ellipsis; white-space: nowrap; }
|
|
168
|
+
.icon-link { width: 34px; height: 34px; border-radius: 5px; display: grid; place-items: center; color: #667084; }
|
|
169
|
+
.icon-link:hover { color: var(--cyan); background: var(--cyan-light); }
|
|
170
|
+
.table-select { min-width: 104px; min-height: 34px; padding: 5px 8px; border: 1px solid #d6dae4; border-radius: 5px; color: #343a4d; background: #fff; }
|
|
171
|
+
.empty-state { min-height: 310px; padding: 42px 20px; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; }
|
|
172
|
+
.empty-state h2 { margin-bottom: 4px; }
|
|
173
|
+
.empty-state p { max-width: 390px; margin-bottom: 18px; font-size: 13px; }
|
|
174
|
+
.empty-icon, .status-icon { width: 48px; height: 48px; margin-bottom: 14px; border-radius: 7px; display: grid; place-items: center; color: #246a43; background: var(--green-light); }
|
|
175
|
+
|
|
176
|
+
.form-panel { width: min(100%, 760px); padding: 24px; display: grid; gap: 19px; }
|
|
177
|
+
.form-section-heading { padding-bottom: 18px; border-bottom: 1px solid #e8eaf0; display: flex; align-items: center; gap: 13px; }
|
|
178
|
+
.form-section-heading h2, .form-section-heading p { margin: 0; }
|
|
179
|
+
.form-section-heading p { margin-top: 2px; font-size: 12px; }
|
|
180
|
+
.detail-grid { display: grid; grid-template-columns: minmax(0, 1.6fr) minmax(270px, .6fr); overflow: hidden; }
|
|
181
|
+
.detail-main { min-height: 270px; padding: 28px; border-right: 1px solid var(--line); }
|
|
182
|
+
.detail-main > p:last-child { color: #373d50; white-space: pre-wrap; }
|
|
183
|
+
.detail-label { color: #82899a; font-size: 11px; font-weight: 800; text-transform: uppercase; }
|
|
184
|
+
.detail-meta { margin: 0; padding: 13px 24px; }
|
|
185
|
+
.detail-meta > div { padding: 16px 0; border-bottom: 1px solid #eceef3; }
|
|
186
|
+
.detail-meta > div:last-child { border-bottom: 0; }
|
|
187
|
+
.detail-meta dt { margin-bottom: 7px; color: #858c9c; font-size: 10px; font-weight: 800; text-transform: uppercase; }
|
|
188
|
+
.detail-meta dd { margin: 0; color: #353b4e; font-size: 13px; }
|
|
189
|
+
|
|
190
|
+
.settings-layout { display: grid; grid-template-columns: 180px minmax(0, 760px); gap: 24px; align-items: start; }
|
|
191
|
+
.settings-nav { display: grid; gap: 4px; }
|
|
192
|
+
.settings-nav a { min-height: 39px; padding: 9px 12px; border-left: 3px solid transparent; color: #68736b; font-size: 13px; font-weight: 700; }
|
|
193
|
+
.settings-nav a:hover { color: #26332b; background: #e9eeea; }
|
|
194
|
+
.settings-nav a.active { color: #1c6841; border-color: var(--cyan); background: var(--cyan-light); }
|
|
195
|
+
.settings-stack { min-width: 0; display: grid; gap: 18px; }
|
|
196
|
+
.settings-panel { padding: 24px; }
|
|
197
|
+
.provider-list, .session-list { margin-top: 3px; display: grid; }
|
|
198
|
+
.provider-row, .session-row { min-width: 0; padding: 15px 0; border-bottom: 1px solid #eceef3; display: flex; align-items: center; gap: 12px; }
|
|
199
|
+
.provider-row:last-child, .session-row:last-child { border-bottom: 0; }
|
|
200
|
+
.provider-icon, .device-icon { width: 36px; height: 36px; flex: 0 0 auto; border: 1px solid #dfe3eb; border-radius: 6px; display: grid; place-items: center; color: #4d5569; }
|
|
201
|
+
.provider-row > div, .session-row > div { min-width: 0; margin-right: auto; display: grid; gap: 3px; }
|
|
202
|
+
.provider-row strong, .session-row strong { overflow: hidden; color: #353b4e; font-size: 13px; text-overflow: ellipsis; white-space: nowrap; }
|
|
203
|
+
.provider-row small, .session-row small { overflow: hidden; color: #82899a; font-size: 11px; text-overflow: ellipsis; white-space: nowrap; }
|
|
204
|
+
.provider-g { color: #3775d6; font-weight: 900; }
|
|
205
|
+
|
|
206
|
+
.notice { min-height: 42px; padding: 10px 12px; border: 1px solid; border-radius: 5px; display: flex; align-items: flex-start; gap: 9px; font-size: 13px; line-height: 1.5; }
|
|
207
|
+
.notice svg { flex: 0 0 auto; margin-top: 1px; }
|
|
208
|
+
.notice-error { color: #912c3d; border-color: #f3bdc6; background: var(--red-light); }
|
|
209
|
+
.notice-success { color: #146b45; border-color: #b9e5ca; background: var(--green-light); }
|
|
210
|
+
|
|
211
|
+
.auth-layout { min-height: 100vh; display: grid; grid-template-columns: minmax(360px, .8fr) minmax(500px, 1.2fr); background: #fff; }
|
|
212
|
+
.auth-brand-panel { min-height: 100vh; padding: 34px 42px; position: relative; overflow: hidden; display: flex; flex-direction: column; color: #fff; background: var(--navy); border-right: 1px solid #286342; }
|
|
213
|
+
.auth-brand-copy { max-width: 470px; margin: auto 0; position: relative; z-index: 1; }
|
|
214
|
+
.auth-logo { width: 220px; height: 220px; margin: 0 0 2px -34px; display: block; }
|
|
215
|
+
.security-mark { margin-bottom: 18px; display: block; color: #7ce8aa; font-family: "SFMono-Regular", Consolas, monospace; font-size: 11px; font-weight: 800; }
|
|
216
|
+
.auth-brand-copy h1 { color: #fff; font-size: 38px; line-height: 1.15; }
|
|
217
|
+
.auth-brand-copy p { max-width: 390px; margin: 17px 0 0; color: #b4cbbb; font-size: 15px; }
|
|
218
|
+
.auth-signal { display: flex; align-items: center; gap: 8px; color: #93b29f; font-size: 11px; }
|
|
219
|
+
.signal-dot { width: 8px; height: 8px; border-radius: 50%; background: #7ce8aa; box-shadow: 0 0 0 4px rgba(124,232,170,.12); }
|
|
220
|
+
.auth-form-panel { min-width: 0; padding: 50px 7vw; display: grid; place-items: center; }
|
|
221
|
+
.auth-form-wrap { width: min(100%, 440px); }
|
|
222
|
+
.auth-form-wrap > header { margin-bottom: 27px; }
|
|
223
|
+
.auth-form-wrap > header h2 { margin-bottom: 6px; font-size: 26px; }
|
|
224
|
+
.auth-form-wrap > header p { margin: 0; font-size: 14px; }
|
|
225
|
+
.auth-form-wrap > footer { margin-top: 24px; color: #71788a; font-size: 13px; text-align: center; }
|
|
226
|
+
.auth-form-wrap > footer a { display: inline-flex; align-items: center; gap: 5px; font-weight: 700; }
|
|
227
|
+
.auth-form-wrap .notice { margin-bottom: 17px; }
|
|
228
|
+
.divider { margin: 22px 0; display: flex; align-items: center; gap: 12px; color: #9197a5; font-size: 11px; }
|
|
229
|
+
.divider::before, .divider::after { content: ""; height: 1px; flex: 1; background: #e2e5eb; }
|
|
230
|
+
.oauth-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
|
|
231
|
+
.status-page { min-height: 100vh; padding: 32px; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; }
|
|
232
|
+
.status-page p { max-width: 430px; margin-bottom: 20px; }
|
|
233
|
+
.sr-only { width: 1px; height: 1px; padding: 0; margin: -1px; position: absolute; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; }
|
|
234
|
+
|
|
235
|
+
@media (max-width: 1050px) {
|
|
236
|
+
.stat-grid { grid-template-columns: 1fr 1fr; }
|
|
237
|
+
.dashboard-grid { grid-template-columns: 1fr; }
|
|
238
|
+
.security-panel { max-width: none; }
|
|
239
|
+
.auth-layout { grid-template-columns: minmax(300px, .7fr) minmax(440px, 1fr); }
|
|
240
|
+
.auth-brand-copy h1 { font-size: 32px; }
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
@media (max-width: 760px) {
|
|
244
|
+
.app-layout { display: block; }
|
|
245
|
+
.sidebar { display: none; }
|
|
246
|
+
.mobile-scrim { display: block; position: fixed; inset: 0; z-index: 39; background: rgba(11,35,23,.58); }
|
|
247
|
+
.mobile-sidebar { width: min(84vw, 280px); padding: 20px 14px; position: fixed; inset: 0 auto 0 0; z-index: 40; display: flex; flex-direction: column; transform: translateX(-105%); transition: transform 180ms ease; }
|
|
248
|
+
.mobile-sidebar.is-open { transform: translateX(0); }
|
|
249
|
+
.topbar { height: 58px; padding: 0 16px; }
|
|
250
|
+
.menu-button { display: inline-flex; }
|
|
251
|
+
.page { padding: 22px 16px 36px; }
|
|
252
|
+
.page-header { min-height: 0; margin-bottom: 18px; display: grid; }
|
|
253
|
+
.page-header h1 { font-size: 24px; }
|
|
254
|
+
.page-actions { justify-content: flex-start; }
|
|
255
|
+
.stat-grid { grid-template-columns: 1fr 1fr; gap: 10px; }
|
|
256
|
+
.stat-card { min-height: 86px; padding: 13px; }
|
|
257
|
+
.stat-card strong { font-size: 17px; }
|
|
258
|
+
.settings-layout { grid-template-columns: 1fr; gap: 16px; }
|
|
259
|
+
.settings-nav { grid-template-columns: 1fr 1fr; }
|
|
260
|
+
.settings-nav a { border-left: 0; border-bottom: 3px solid transparent; text-align: center; }
|
|
261
|
+
.detail-grid { grid-template-columns: 1fr; }
|
|
262
|
+
.detail-main { min-height: 190px; border-right: 0; border-bottom: 1px solid var(--line); }
|
|
263
|
+
.two-fields { grid-template-columns: 1fr; }
|
|
264
|
+
.auth-layout { display: block; background: #fff; }
|
|
265
|
+
.auth-brand-panel { min-height: 220px; padding: 22px; }
|
|
266
|
+
.auth-brand-copy { margin: auto 0 0; }
|
|
267
|
+
.auth-brand-copy h1 { max-width: 480px; margin-bottom: 7px; font-size: 26px; }
|
|
268
|
+
.auth-brand-copy p { display: none; }
|
|
269
|
+
.auth-logo { width: 104px; height: 104px; margin: -18px 0 -12px -18px; }
|
|
270
|
+
.auth-signal { display: none; }
|
|
271
|
+
.security-mark { margin-bottom: 10px; }
|
|
272
|
+
.auth-form-panel { min-height: calc(100vh - 220px); padding: 34px 20px; align-items: start; }
|
|
273
|
+
th, td { padding: 12px 14px; }
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
@media (max-width: 480px) {
|
|
277
|
+
.stat-grid { grid-template-columns: 1fr; }
|
|
278
|
+
.oauth-grid { grid-template-columns: 1fr; }
|
|
279
|
+
.form-panel, .settings-panel { padding: 18px; }
|
|
280
|
+
.form-actions, .action-row { justify-content: stretch; }
|
|
281
|
+
.form-actions .button, .action-row .button { flex: 1; }
|
|
282
|
+
.provider-row, .session-row { align-items: flex-start; flex-wrap: wrap; }
|
|
283
|
+
.provider-row > div, .session-row > div { width: calc(100% - 50px); }
|
|
284
|
+
.provider-row > .badge, .provider-row > .button, .session-row > .badge, .session-row > .button { margin-left: 48px; }
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
@media (prefers-reduced-motion: reduce) {
|
|
288
|
+
*, *::before, *::after { scroll-behavior: auto !important; animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; }
|
|
289
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { describe, expect, it } from "vitest";
|
|
4
|
+
|
|
5
|
+
describe("browser token storage rule", () => {
|
|
6
|
+
it("keeps the generated API client free of browser storage APIs", async () => {
|
|
7
|
+
const source = await readFile(path.resolve(process.cwd(), "../../packages/api-client/src/index.ts"), "utf8");
|
|
8
|
+
expect(source).not.toMatch(/localStorage|sessionStorage|indexedDB/);
|
|
9
|
+
expect(source).toContain("let accessToken: string | null = null");
|
|
10
|
+
expect(source).toContain('credentials: "include"');
|
|
11
|
+
});
|
|
12
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"useDefineForClassFields": true,
|
|
5
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"moduleResolution": "Bundler",
|
|
8
|
+
"allowImportingTsExtensions": false,
|
|
9
|
+
"resolveJsonModule": true,
|
|
10
|
+
"isolatedModules": true,
|
|
11
|
+
"noEmit": true,
|
|
12
|
+
"jsx": "react-jsx",
|
|
13
|
+
"strict": true,
|
|
14
|
+
"skipLibCheck": true,
|
|
15
|
+
"types": ["vite/client"]
|
|
16
|
+
},
|
|
17
|
+
"include": ["src"],
|
|
18
|
+
"exclude": ["src/**/*.test.ts", "src/**/*.test.tsx"]
|
|
19
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { defineConfig } from "vite";
|
|
2
|
+
import react from "@vitejs/plugin-react";
|
|
3
|
+
|
|
4
|
+
const apiProxy = {
|
|
5
|
+
"/api": { target: "http://localhost:3000", changeOrigin: false },
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export default defineConfig({
|
|
9
|
+
plugins: [react()],
|
|
10
|
+
server: {
|
|
11
|
+
port: 5173,
|
|
12
|
+
proxy: apiProxy,
|
|
13
|
+
},
|
|
14
|
+
preview: {
|
|
15
|
+
port: 4173,
|
|
16
|
+
proxy: apiProxy,
|
|
17
|
+
},
|
|
18
|
+
});
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
services:
|
|
2
|
+
postgres:
|
|
3
|
+
image: postgres:16-alpine
|
|
4
|
+
environment:
|
|
5
|
+
POSTGRES_DB: authenik8
|
|
6
|
+
POSTGRES_USER: postgres
|
|
7
|
+
POSTGRES_PASSWORD: postgres
|
|
8
|
+
ports:
|
|
9
|
+
- "5432:5432"
|
|
10
|
+
volumes:
|
|
11
|
+
- postgres-data:/var/lib/postgresql/data
|
|
12
|
+
healthcheck:
|
|
13
|
+
test: ["CMD-SHELL", "pg_isready -U postgres -d authenik8"]
|
|
14
|
+
interval: 5s
|
|
15
|
+
timeout: 3s
|
|
16
|
+
retries: 10
|
|
17
|
+
restart: unless-stopped
|
|
18
|
+
|
|
19
|
+
redis:
|
|
20
|
+
image: redis:7-alpine
|
|
21
|
+
command: redis-server --appendonly yes
|
|
22
|
+
ports:
|
|
23
|
+
- "6379:6379"
|
|
24
|
+
volumes:
|
|
25
|
+
- redis-data:/data
|
|
26
|
+
healthcheck:
|
|
27
|
+
test: ["CMD", "redis-cli", "ping"]
|
|
28
|
+
interval: 5s
|
|
29
|
+
timeout: 3s
|
|
30
|
+
retries: 10
|
|
31
|
+
restart: unless-stopped
|
|
32
|
+
|
|
33
|
+
volumes:
|
|
34
|
+
postgres-data:
|
|
35
|
+
redis-data:
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Production checklist
|
|
2
|
+
|
|
3
|
+
## Secrets and transport
|
|
4
|
+
|
|
5
|
+
- Store the generated ES256 signing key ring and high-entropy `REFRESH_SECRET` in a deployment secret manager. Never commit private JWK fields.
|
|
6
|
+
- Rotate access-token keys by appending a new private JWK, switching `AUTHENIK8_ACTIVE_KID`, and retaining old public keys until their tokens expire.
|
|
7
|
+
- Terminate TLS at a maintained reverse proxy or load balancer and redirect HTTP to HTTPS.
|
|
8
|
+
- Set `COOKIE_SECURE=true`, an exact HTTPS `WEB_ORIGIN`, and `TRUST_PROXY=true` only when requests pass through a trusted proxy that overwrites forwarding headers.
|
|
9
|
+
|
|
10
|
+
## Data services
|
|
11
|
+
|
|
12
|
+
- Keep PostgreSQL and Redis on private networks with authentication and encryption where supported.
|
|
13
|
+
- Configure automated PostgreSQL backups and perform restore drills.
|
|
14
|
+
- Configure Redis persistence appropriate to the session availability requirement. Never expose port 6379 publicly.
|
|
15
|
+
- Keep `AUTHENIK8_AGENTS={}` unless machine identity is intentionally enabled. In production, prefer a database-backed registry and authenticate workloads with mTLS, cloud identity, or signed assertions before issuing tokens.
|
|
16
|
+
- Run Prisma migrations as a controlled release step, not concurrently from every application replica.
|
|
17
|
+
|
|
18
|
+
## Identity operations
|
|
19
|
+
|
|
20
|
+
- Replace the development token output with a transactional email provider before accepting real users.
|
|
21
|
+
- Register exact OAuth callback URLs and rotate provider secrets through a secret manager.
|
|
22
|
+
- Change or remove the seed administrator password after the first deployment.
|
|
23
|
+
|
|
24
|
+
## Runtime and observability
|
|
25
|
+
|
|
26
|
+
- Run `npm run build`, then start with `NODE_ENV=production npm start`.
|
|
27
|
+
- Send structured logs to centralized storage and preserve `x-request-id` across the proxy.
|
|
28
|
+
- Monitor `/api/health/live` and `/api/health/ready`, request latency, rate-limit responses, Redis availability, login failures, and refresh replay failures.
|
|
29
|
+
- Alert on administrator role changes and session revocation spikes.
|
|
30
|
+
- Review dependency advisories and apply security updates with the full test suite.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "authenik8-fullstack-app",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"workspaces": [
|
|
7
|
+
"apps/*",
|
|
8
|
+
"packages/*"
|
|
9
|
+
],
|
|
10
|
+
"engines": {
|
|
11
|
+
"node": "^20.19 || ^22.12 || >=24"
|
|
12
|
+
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build:packages": "npm run build -w @authenik8/contracts && npm run build -w @authenik8/api-client && npm run build -w @authenik8/ui",
|
|
15
|
+
"dev": "npm run build:packages && concurrently -n contracts,client,ui,api,web -c blue,green,yellow,cyan,magenta \"npm run dev -w @authenik8/contracts\" \"npm run dev -w @authenik8/api-client\" \"npm run dev -w @authenik8/ui\" \"npm run dev -w @authenik8/api\" \"npm run dev -w @authenik8/web\"",
|
|
16
|
+
"build": "npm run build:packages && npm run build -w @authenik8/web && npm run build -w @authenik8/api",
|
|
17
|
+
"start": "npm run start -w @authenik8/api",
|
|
18
|
+
"test": "npm run build:packages && npm run test -w @authenik8/api && npm run test -w @authenik8/web",
|
|
19
|
+
"typecheck": "npm run typecheck --workspaces --if-present",
|
|
20
|
+
"db:generate": "npm run prisma:generate -w @authenik8/api",
|
|
21
|
+
"db:migrate": "npm run prisma:migrate -w @authenik8/api",
|
|
22
|
+
"db:seed": "npm run prisma:seed -w @authenik8/api",
|
|
23
|
+
"db:studio": "npm run prisma:studio -w @authenik8/api",
|
|
24
|
+
"docker:up": "docker compose up -d --wait",
|
|
25
|
+
"docker:down": "docker compose down"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"concurrently": "^9.2.1",
|
|
29
|
+
"typescript": "^6.0.3"
|
|
30
|
+
},
|
|
31
|
+
"overrides": {
|
|
32
|
+
"@hono/node-server": "1.19.13"
|
|
33
|
+
},
|
|
34
|
+
"allowScripts": {
|
|
35
|
+
"prisma@7.8.0": true,
|
|
36
|
+
"@prisma/engines@7.8.0": true,
|
|
37
|
+
"esbuild": true
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@authenik8/api-client",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": ["dist"],
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc -p tsconfig.json",
|
|
11
|
+
"dev": "tsc -p tsconfig.json --watch --preserveWatchOutput",
|
|
12
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@authenik8/contracts": "0.1.0"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"typescript": "^6.0.3"
|
|
19
|
+
}
|
|
20
|
+
}
|