create-authenik8-app 2.4.14 → 2.4.15

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 (227) hide show
  1. package/README.md +34 -516
  2. package/dist/src/bin/cli.d.ts +3 -0
  3. package/dist/src/bin/cli.d.ts.map +1 -0
  4. package/dist/src/bin/cli.js +112 -0
  5. package/dist/src/bin/cli.js.map +1 -0
  6. package/dist/src/bin/index.js +108 -23
  7. package/dist/src/bin/index.js.map +1 -1
  8. package/dist/src/commands/add/apply.d.ts +6 -0
  9. package/dist/src/commands/add/apply.d.ts.map +1 -0
  10. package/dist/src/commands/add/apply.js +123 -0
  11. package/dist/src/commands/add/apply.js.map +1 -0
  12. package/dist/src/commands/add/ci.d.ts +6 -0
  13. package/dist/src/commands/add/ci.d.ts.map +1 -0
  14. package/dist/src/commands/add/ci.js +108 -0
  15. package/dist/src/commands/add/ci.js.map +1 -0
  16. package/dist/src/commands/add/context.d.ts +5 -0
  17. package/dist/src/commands/add/context.d.ts.map +1 -0
  18. package/dist/src/commands/add/context.js +19 -0
  19. package/dist/src/commands/add/context.js.map +1 -0
  20. package/dist/src/commands/add/diff.d.ts +4 -0
  21. package/dist/src/commands/add/diff.d.ts.map +1 -0
  22. package/dist/src/commands/add/diff.js +114 -0
  23. package/dist/src/commands/add/diff.js.map +1 -0
  24. package/dist/src/commands/add/index.d.ts +6 -0
  25. package/dist/src/commands/add/index.d.ts.map +1 -0
  26. package/dist/src/commands/add/index.js +61 -0
  27. package/dist/src/commands/add/index.js.map +1 -0
  28. package/dist/src/commands/add/output.d.ts +5 -0
  29. package/dist/src/commands/add/output.d.ts.map +1 -0
  30. package/dist/src/commands/add/output.js +58 -0
  31. package/dist/src/commands/add/output.js.map +1 -0
  32. package/dist/src/commands/add/plan.d.ts +6 -0
  33. package/dist/src/commands/add/plan.d.ts.map +1 -0
  34. package/dist/src/commands/add/plan.js +93 -0
  35. package/dist/src/commands/add/plan.js.map +1 -0
  36. package/dist/src/commands/add/registry.d.ts +4 -0
  37. package/dist/src/commands/add/registry.d.ts.map +1 -0
  38. package/dist/src/commands/add/registry.js +37 -0
  39. package/dist/src/commands/add/registry.js.map +1 -0
  40. package/dist/src/commands/add/types.d.ts +37 -0
  41. package/dist/src/commands/add/types.d.ts.map +1 -0
  42. package/dist/src/commands/add/types.js +2 -0
  43. package/dist/src/commands/add/types.js.map +1 -0
  44. package/dist/src/commands/doctor/checks.d.ts +3 -0
  45. package/dist/src/commands/doctor/checks.d.ts.map +1 -0
  46. package/dist/src/commands/doctor/checks.js +353 -0
  47. package/dist/src/commands/doctor/checks.js.map +1 -0
  48. package/dist/src/commands/doctor/context.d.ts +5 -0
  49. package/dist/src/commands/doctor/context.d.ts.map +1 -0
  50. package/dist/src/commands/doctor/context.js +134 -0
  51. package/dist/src/commands/doctor/context.js.map +1 -0
  52. package/dist/src/commands/doctor/index.d.ts +9 -0
  53. package/dist/src/commands/doctor/index.d.ts.map +1 -0
  54. package/dist/src/commands/doctor/index.js +80 -0
  55. package/dist/src/commands/doctor/index.js.map +1 -0
  56. package/dist/src/commands/doctor/output.d.ts +4 -0
  57. package/dist/src/commands/doctor/output.d.ts.map +1 -0
  58. package/dist/src/commands/doctor/output.js +53 -0
  59. package/dist/src/commands/doctor/output.js.map +1 -0
  60. package/dist/src/commands/doctor/postGeneration.d.ts +7 -0
  61. package/dist/src/commands/doctor/postGeneration.d.ts.map +1 -0
  62. package/dist/src/commands/doctor/postGeneration.js +22 -0
  63. package/dist/src/commands/doctor/postGeneration.js.map +1 -0
  64. package/dist/src/commands/doctor/services.d.ts +5 -0
  65. package/dist/src/commands/doctor/services.d.ts.map +1 -0
  66. package/dist/src/commands/doctor/services.js +80 -0
  67. package/dist/src/commands/doctor/services.js.map +1 -0
  68. package/dist/src/commands/doctor/types.d.ts +69 -0
  69. package/dist/src/commands/doctor/types.d.ts.map +1 -0
  70. package/dist/src/commands/doctor/types.js +2 -0
  71. package/dist/src/commands/doctor/types.js.map +1 -0
  72. package/dist/src/commands/upgrade/context.d.ts +5 -0
  73. package/dist/src/commands/upgrade/context.d.ts.map +1 -0
  74. package/dist/src/commands/upgrade/context.js +57 -0
  75. package/dist/src/commands/upgrade/context.js.map +1 -0
  76. package/dist/src/commands/upgrade/index.d.ts +7 -0
  77. package/dist/src/commands/upgrade/index.d.ts.map +1 -0
  78. package/dist/src/commands/upgrade/index.js +35 -0
  79. package/dist/src/commands/upgrade/index.js.map +1 -0
  80. package/dist/src/commands/upgrade/migrations.d.ts +4 -0
  81. package/dist/src/commands/upgrade/migrations.d.ts.map +1 -0
  82. package/dist/src/commands/upgrade/migrations.js +22 -0
  83. package/dist/src/commands/upgrade/migrations.js.map +1 -0
  84. package/dist/src/commands/upgrade/output.d.ts +4 -0
  85. package/dist/src/commands/upgrade/output.d.ts.map +1 -0
  86. package/dist/src/commands/upgrade/output.js +52 -0
  87. package/dist/src/commands/upgrade/output.js.map +1 -0
  88. package/dist/src/commands/upgrade/plan.d.ts +3 -0
  89. package/dist/src/commands/upgrade/plan.d.ts.map +1 -0
  90. package/dist/src/commands/upgrade/plan.js +119 -0
  91. package/dist/src/commands/upgrade/plan.js.map +1 -0
  92. package/dist/src/commands/upgrade/types.d.ts +48 -0
  93. package/dist/src/commands/upgrade/types.d.ts.map +1 -0
  94. package/dist/src/commands/upgrade/types.js +2 -0
  95. package/dist/src/commands/upgrade/types.js.map +1 -0
  96. package/dist/src/lib/args.d.ts +21 -0
  97. package/dist/src/lib/args.d.ts.map +1 -1
  98. package/dist/src/lib/args.js +119 -1
  99. package/dist/src/lib/args.js.map +1 -1
  100. package/dist/src/lib/constants.d.ts +1 -1
  101. package/dist/src/lib/constants.d.ts.map +1 -1
  102. package/dist/src/lib/constants.js +3 -1
  103. package/dist/src/lib/constants.js.map +1 -1
  104. package/dist/src/lib/expressOAuth.d.ts +10 -0
  105. package/dist/src/lib/expressOAuth.d.ts.map +1 -0
  106. package/dist/src/lib/expressOAuth.js +164 -0
  107. package/dist/src/lib/expressOAuth.js.map +1 -0
  108. package/dist/src/lib/interruption.d.ts +14 -0
  109. package/dist/src/lib/interruption.d.ts.map +1 -0
  110. package/dist/src/lib/interruption.js +16 -0
  111. package/dist/src/lib/interruption.js.map +1 -0
  112. package/dist/src/lib/nonInteractive.d.ts +8 -0
  113. package/dist/src/lib/nonInteractive.d.ts.map +1 -0
  114. package/dist/src/lib/nonInteractive.js +111 -0
  115. package/dist/src/lib/nonInteractive.js.map +1 -0
  116. package/dist/src/lib/oauth.d.ts +9 -0
  117. package/dist/src/lib/oauth.d.ts.map +1 -0
  118. package/dist/src/lib/oauth.js +62 -0
  119. package/dist/src/lib/oauth.js.map +1 -0
  120. package/dist/src/lib/onboarding.d.ts +8 -0
  121. package/dist/src/lib/onboarding.d.ts.map +1 -0
  122. package/dist/src/lib/onboarding.js +35 -0
  123. package/dist/src/lib/onboarding.js.map +1 -0
  124. package/dist/src/lib/packageManagerCommands.d.ts +11 -0
  125. package/dist/src/lib/packageManagerCommands.d.ts.map +1 -0
  126. package/dist/src/lib/packageManagerCommands.js +34 -0
  127. package/dist/src/lib/packageManagerCommands.js.map +1 -0
  128. package/dist/src/lib/process.d.ts.map +1 -1
  129. package/dist/src/lib/process.js +9 -0
  130. package/dist/src/lib/process.js.map +1 -1
  131. package/dist/src/lib/projectManifest.d.ts +67 -0
  132. package/dist/src/lib/projectManifest.d.ts.map +1 -0
  133. package/dist/src/lib/projectManifest.js +134 -0
  134. package/dist/src/lib/projectManifest.js.map +1 -0
  135. package/dist/src/lib/release.d.ts +9 -0
  136. package/dist/src/lib/release.d.ts.map +1 -0
  137. package/dist/src/lib/release.js +48 -0
  138. package/dist/src/lib/release.js.map +1 -0
  139. package/dist/src/lib/rootCommand.d.ts +15 -0
  140. package/dist/src/lib/rootCommand.d.ts.map +1 -0
  141. package/dist/src/lib/rootCommand.js +17 -0
  142. package/dist/src/lib/rootCommand.js.map +1 -0
  143. package/dist/src/lib/schemas.d.ts +15 -6
  144. package/dist/src/lib/schemas.d.ts.map +1 -1
  145. package/dist/src/lib/schemas.js +8 -1
  146. package/dist/src/lib/schemas.js.map +1 -1
  147. package/dist/src/lib/semver.d.ts +10 -0
  148. package/dist/src/lib/semver.d.ts.map +1 -0
  149. package/dist/src/lib/semver.js +51 -0
  150. package/dist/src/lib/semver.js.map +1 -0
  151. package/dist/src/lib/types.d.ts +5 -1
  152. package/dist/src/lib/types.d.ts.map +1 -1
  153. package/dist/src/steps/configurePrisma.d.ts.map +1 -1
  154. package/dist/src/steps/configurePrisma.js +18 -23
  155. package/dist/src/steps/configurePrisma.js.map +1 -1
  156. package/dist/src/steps/configureReadme.d.ts +4 -0
  157. package/dist/src/steps/configureReadme.d.ts.map +1 -0
  158. package/dist/src/steps/configureReadme.js +22 -0
  159. package/dist/src/steps/configureReadme.js.map +1 -0
  160. package/dist/src/steps/createProject.d.ts.map +1 -1
  161. package/dist/src/steps/createProject.js +16 -170
  162. package/dist/src/steps/createProject.js.map +1 -1
  163. package/dist/src/steps/finalSetup.d.ts +3 -2
  164. package/dist/src/steps/finalSetup.d.ts.map +1 -1
  165. package/dist/src/steps/finalSetup.js +14 -9
  166. package/dist/src/steps/finalSetup.js.map +1 -1
  167. package/dist/src/steps/installDeps.d.ts +1 -0
  168. package/dist/src/steps/installDeps.d.ts.map +1 -1
  169. package/dist/src/steps/installDeps.js +11 -0
  170. package/dist/src/steps/installDeps.js.map +1 -1
  171. package/dist/src/steps/prompts.d.ts.map +1 -1
  172. package/dist/src/steps/prompts.js +32 -13
  173. package/dist/src/steps/prompts.js.map +1 -1
  174. package/dist/src/utils/output.d.ts.map +1 -1
  175. package/dist/src/utils/output.js +23 -11
  176. package/dist/src/utils/output.js.map +1 -1
  177. package/package.json +5 -4
  178. package/templates/express-auth/README.md +21 -12
  179. package/templates/express-auth/package.json +11 -7
  180. package/templates/express-auth/src/config/redis.ts +109 -0
  181. package/templates/express-auth/src/server.ts +2 -0
  182. package/templates/express-auth+/README.md +25 -18
  183. package/templates/express-auth+/package.json +11 -7
  184. package/templates/express-auth+/src/auth/auth.ts +2 -0
  185. package/templates/express-auth+/src/auth/controllers/password.controller.ts +12 -1
  186. package/templates/express-auth+/src/auth/routes/password.route.ts +1 -0
  187. package/templates/express-auth+/src/config/redis.ts +109 -0
  188. package/templates/express-auth+/src/utils/security.ts +12 -0
  189. package/templates/express-base/README.md +21 -12
  190. package/templates/express-base/package.json +11 -8
  191. package/templates/express-base/src/.env.example +1 -1
  192. package/templates/express-base/src/config/redis.ts +109 -0
  193. package/templates/express-base/src/server.ts +2 -0
  194. package/templates/fullstack/.env.example +3 -2
  195. package/templates/fullstack/PRESET_CONTRACT.md +7 -3
  196. package/templates/fullstack/README.md +45 -7
  197. package/templates/fullstack/apps/api/package.json +6 -4
  198. package/templates/fullstack/apps/api/prisma/migrations/20260721000000_init/migration.sql +163 -0
  199. package/templates/fullstack/apps/api/prisma/migrations/migration_lock.toml +3 -0
  200. package/templates/fullstack/apps/api/src/auth/authenik8.ts +13 -4
  201. package/templates/fullstack/apps/api/src/config/env.ts +9 -1
  202. package/templates/fullstack/apps/api/src/config/logger.ts +21 -11
  203. package/templates/fullstack/apps/api/tests/logger.test.ts +43 -0
  204. package/templates/fullstack/apps/web/package.json +3 -1
  205. package/templates/fullstack/apps/web/src/App.tsx +1 -1
  206. package/templates/fullstack/apps/web/src/auth/RouteGuards.tsx +1 -1
  207. package/templates/fullstack/apps/web/src/components/AppShell.tsx +90 -45
  208. package/templates/fullstack/apps/web/src/components/AuthShell.tsx +10 -7
  209. package/templates/fullstack/apps/web/src/components/Page.tsx +6 -3
  210. package/templates/fullstack/apps/web/src/features/projects/ProjectPages.tsx +1 -1
  211. package/templates/fullstack/apps/web/src/main.tsx +13 -6
  212. package/templates/fullstack/apps/web/src/pages/DashboardPage.tsx +163 -23
  213. package/templates/fullstack/apps/web/src/pages/StatusPages.tsx +1 -1
  214. package/templates/fullstack/apps/web/src/pages/auth/LoginPage.tsx +93 -17
  215. package/templates/fullstack/apps/web/src/pages/auth/OAuthCallbackPage.tsx +1 -1
  216. package/templates/fullstack/apps/web/src/pages/auth/RecoveryPages.tsx +1 -1
  217. package/templates/fullstack/apps/web/src/pages/auth/RegisterPage.tsx +1 -1
  218. package/templates/fullstack/apps/web/src/pages/auth/VerifyEmailPage.tsx +1 -1
  219. package/templates/fullstack/apps/web/src/styles.css +119 -43
  220. package/templates/fullstack/apps/web/vite.config.ts +12 -0
  221. package/templates/fullstack/docker-compose.yml +2 -2
  222. package/templates/fullstack/gitignore.template +1 -0
  223. package/templates/fullstack/package.json +17 -8
  224. package/templates/fullstack/scripts/run-local.mjs +157 -0
  225. package/templates/prisma/postgresql/.env.example +1 -2
  226. package/templates/prisma/sqlite/.env.example +1 -2
  227. package/templates/prisma/sqlite/client.ts +2 -2
@@ -1,4 +1,6 @@
1
1
  import chalk from "chalk";
2
+ import { doctorCommand, firstSuccessGuide } from "../lib/onboarding.js";
3
+ import { installCommand, runScriptCommand } from "../lib/packageManagerCommands.js";
2
4
  function selectedOAuthProviders(state) {
3
5
  const providers = state.oauthProviders?.filter((provider) => provider === "google" || provider === "github");
4
6
  return providers ?? ["google", "github"];
@@ -31,18 +33,23 @@ function databaseLabel(state) {
31
33
  return state.database === "postgresql" ? "PostgreSQL with Prisma" : "SQLite with Prisma";
32
34
  }
33
35
  function runCommand(state, script) {
34
- return `${state.packageManager ?? "npm"} run ${script}`;
36
+ return runScriptCommand(state.packageManager ?? "npm", script);
35
37
  }
36
38
  export function printSummary(state, isProduction, hasDockerCompose = true, hasDockerDaemon = true) {
37
39
  const packageManager = state.packageManager ?? "npm";
40
+ const firstSuccess = firstSuccessGuide(state.authMode ?? "base");
41
+ const isFullstack = state.authMode === "fullstack";
42
+ const needsPostgres = !isFullstack
43
+ && state.usePrisma
44
+ && state.database === "postgresql";
38
45
  const commands = [
39
46
  `cd ${state.projectName}`,
40
- ...(state.installDeps === false ? [`${packageManager} install`] : []),
41
- ...(hasDockerCompose && hasDockerDaemon ? [runCommand(state, "docker:up")] : []),
42
- ...(state.usePrisma
43
- ? [runCommand(state, state.authMode === "fullstack" ? "db:migrate" : "prisma:migrate")]
47
+ ...(state.installDeps === false ? [installCommand(packageManager)] : []),
48
+ ...(needsPostgres && hasDockerCompose && hasDockerDaemon
49
+ ? [runCommand(state, "docker:up")]
44
50
  : []),
45
- ...(state.authMode === "fullstack" ? [runCommand(state, "db:seed")] : []),
51
+ ...(!isFullstack && state.usePrisma ? [runCommand(state, "db:migrate")] : []),
52
+ doctorCommand(packageManager),
46
53
  runCommand(state, "dev"),
47
54
  ];
48
55
  const details = [
@@ -60,12 +67,11 @@ export function printSummary(state, isProduction, hasDockerCompose = true, hasDo
60
67
  console.log(`${chalk.green("◇")} ${chalk.dim(label.padEnd(labelWidth))} ${value}`);
61
68
  }
62
69
  console.log(chalk.dim("│"));
63
- if (!hasDockerCompose) {
64
- const services = state.database === "postgresql" ? "Redis and PostgreSQL" : "Redis";
65
- console.log(`${chalk.yellow("!")} Docker Compose was not found. Install it or start ${services} manually.`);
70
+ if (needsPostgres && !hasDockerCompose) {
71
+ console.log(`${chalk.yellow("!")} Docker Compose was not found. Install it or provide PostgreSQL through DATABASE_URL.`);
66
72
  console.log(chalk.dim("│"));
67
73
  }
68
- else if (!hasDockerDaemon) {
74
+ else if (needsPostgres && !hasDockerDaemon) {
69
75
  console.log(`${chalk.yellow("!")} Docker is installed, but its daemon is not reachable. Start Docker Desktop or the Docker service.`);
70
76
  console.log(chalk.dim("│"));
71
77
  }
@@ -73,6 +79,12 @@ export function printSummary(state, isProduction, hasDockerCompose = true, hasDo
73
79
  for (const command of commands) {
74
80
  console.log(` ${chalk.cyan(command)}`);
75
81
  }
82
+ console.log(chalk.dim("│"));
83
+ console.log(`${chalk.cyan("└")} ${chalk.bold("First success")}`);
84
+ console.log(` ${chalk.bold(firstSuccess.title)}`);
85
+ firstSuccess.steps.forEach((step, index) => {
86
+ console.log(` ${chalk.cyan(`${index + 1}.`)} ${step}`);
87
+ });
76
88
  if (state.authMode === "fullstack") {
77
89
  console.log(chalk.dim("\n Web http://localhost:5173"));
78
90
  console.log(chalk.dim(" API http://localhost:3000/api"));
@@ -83,6 +95,6 @@ export function printSummary(state, isProduction, hasDockerCompose = true, hasDo
83
95
  if (isProduction && state.authMode !== "fullstack") {
84
96
  console.log(chalk.dim(`\n Production process ${runCommand(state, "pm2:start")}`));
85
97
  }
86
- console.log(chalk.dim("\n Review .env, README.md, and THREAT_MODEL.md before deployment.\n"));
98
+ console.log(chalk.dim("\n Review .env, authenik8.json, README.md, and THREAT_MODEL.md before deployment.\n"));
87
99
  }
88
100
  //# sourceMappingURL=output.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"output.js","sourceRoot":"","sources":["../../../src/utils/output.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"output.js","sourceRoot":"","sources":["../../../src/utils/output.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AAGpF,SAAS,sBAAsB,CAAC,KAAe;IAC7C,MAAM,SAAS,GAAG,KAAK,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAC1D,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,QAAQ,CAC/C,CAAC;IAEF,OAAO,SAAS,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;AAC3C,CAAC;AAED,SAAS,kBAAkB,CAAC,KAAe;IACzC,OAAO,sBAAsB,CAAC,KAAK,CAAC;SACjC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;SAC9D,IAAI,CAAC,GAAG,CAAC,CAAC;AACf,CAAC;AAED,SAAS,SAAS,CAAC,KAAe;IAChC,IAAI,KAAK,CAAC,QAAQ,KAAK,MAAM;QAAE,OAAO,KAAK,CAAC;IAC5C,IAAI,KAAK,CAAC,QAAQ,KAAK,MAAM;QAAE,OAAO,oBAAoB,CAAC;IAC3D,MAAM,SAAS,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;IAC5C,OAAO,SAAS,CAAC,CAAC,CAAC,wBAAwB,SAAS,EAAE,CAAC,CAAC,CAAC,oBAAoB,CAAC;AAChF,CAAC;AAED,SAAS,WAAW,CAAC,KAAe;IAClC,IAAI,KAAK,CAAC,QAAQ,KAAK,WAAW;QAAE,OAAO,wBAAwB,CAAC;IACpE,IAAI,KAAK,CAAC,QAAQ,KAAK,YAAY;QAAE,OAAO,qBAAqB,CAAC;IAClE,IAAI,KAAK,CAAC,QAAQ,KAAK,MAAM;QAAE,OAAO,8BAA8B,CAAC;IACrE,OAAO,wBAAwB,CAAC;AAClC,CAAC;AAED,SAAS,aAAa,CAAC,KAAe;IACpC,IAAI,CAAC,KAAK,CAAC,SAAS;QAAE,OAAO,MAAM,CAAC;IACpC,OAAO,KAAK,CAAC,QAAQ,KAAK,YAAY,CAAC,CAAC,CAAC,wBAAwB,CAAC,CAAC,CAAC,oBAAoB,CAAC;AAC3F,CAAC;AAED,SAAS,UAAU,CAAC,KAAe,EAAE,MAAc;IACjD,OAAO,gBAAgB,CAAC,KAAK,CAAC,cAAc,IAAI,KAAK,EAAE,MAAM,CAAC,CAAC;AACjE,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,KAAe,EACf,YAAqB,EACrB,gBAAgB,GAAG,IAAI,EACvB,eAAe,GAAG,IAAI;IAEtB,MAAM,cAAc,GAAG,KAAK,CAAC,cAAc,IAAI,KAAK,CAAC;IACrD,MAAM,YAAY,GAAG,iBAAiB,CAAC,KAAK,CAAC,QAAQ,IAAI,MAAM,CAAC,CAAC;IACjE,MAAM,WAAW,GAAG,KAAK,CAAC,QAAQ,KAAK,WAAW,CAAC;IACnD,MAAM,aAAa,GAAG,CAAC,WAAW;WAC7B,KAAK,CAAC,SAAS;WACf,KAAK,CAAC,QAAQ,KAAK,YAAY,CAAC;IACrC,MAAM,QAAQ,GAAG;QACf,MAAM,KAAK,CAAC,WAAW,EAAE;QACzB,GAAG,CAAC,KAAK,CAAC,WAAW,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACxE,GAAG,CAAC,aAAa,IAAI,gBAAgB,IAAI,eAAe;YACtD,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;YAClC,CAAC,CAAC,EAAE,CAAC;QACP,GAAG,CAAC,CAAC,WAAW,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7E,aAAa,CAAC,cAAc,CAAC;QAC7B,UAAU,CAAC,KAAK,EAAE,KAAK,CAAC;KACzB,CAAC;IACF,MAAM,OAAO,GAA4B;QACvC,CAAC,UAAU,EAAE,KAAK,KAAK,CAAC,WAAW,EAAE,CAAC;QACtC,CAAC,QAAQ,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC;QAC9B,CAAC,gBAAgB,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC;QACpC,CAAC,UAAU,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC;QAClC,CAAC,iBAAiB,EAAE,cAAc,CAAC;KACpC,CAAC;IACF,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;IAEvE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,WAAW,WAAW,CAAC,EAAE,CAAC,CAAC;IACxF,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5B,KAAK,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,OAAO,EAAE,CAAC;QACrC,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC;IACvF,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5B,IAAI,aAAa,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACvC,OAAO,CAAC,GAAG,CACT,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,wFAAwF,CAC7G,CAAC;QACF,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9B,CAAC;SAAM,IAAI,aAAa,IAAI,CAAC,eAAe,EAAE,CAAC;QAC7C,OAAO,CAAC,GAAG,CACT,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,qGAAqG,CAC1H,CAAC;QACF,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9B,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;IAC9D,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC1C,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5B,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;IACjE,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACnD,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QACzC,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;IAEH,IAAI,KAAK,CAAC,QAAQ,KAAK,WAAW,EAAE,CAAC;QACnC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC,CAAC;QACzD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC,CAAC;IAC7D,CAAC;IACD,IAAI,KAAK,CAAC,QAAQ,KAAK,YAAY,EAAE,CAAC;QACpC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,iBAAiB,kBAAkB,CAAC,KAAK,CAAC,oDAAoD,CAAC,CAAC,CAAC;IACzH,CAAC;IACD,IAAI,YAAY,IAAI,KAAK,CAAC,QAAQ,KAAK,WAAW,EAAE,CAAC;QACnD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,2BAA2B,UAAU,CAAC,KAAK,EAAE,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC;IACtF,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,sFAAsF,CAAC,CAAC,CAAC;AACjH,CAAC"}
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "create-authenik8-app",
3
- "version": "2.4.14",
3
+ "version": "2.4.15",
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
- "create-authenik8-app": "dist/src/bin/index.js"
6
+ "create-authenik8-app": "dist/src/bin/cli.js"
7
7
  },
8
8
  "keywords": [
9
9
  "cli",
@@ -32,7 +32,7 @@
32
32
  "node": "^20.19 || ^22.12 || >=24"
33
33
  },
34
34
  "dependencies": {
35
- "@inquirer/core": "^10.3.2",
35
+ "@inquirer/core": "^11.2.1",
36
36
  "chalk": "^5.6.2",
37
37
  "fs-extra": "^11.3.4",
38
38
  "inquirer": "^12.11.1",
@@ -62,9 +62,10 @@
62
62
  "@vitest/coverage-v8": "^4.1.8",
63
63
  "authenik8-core": "2.0.3",
64
64
  "fast-check": "^4.8.0",
65
+ "ioredis-mock": "^8.13.1",
65
66
  "jose": "6.2.3",
66
67
  "supertest": "^7.2.2",
67
- "tsx": "^4.23.1",
68
+ "tsx": "^4.22.4",
68
69
  "typescript": "^6.0.3",
69
70
  "vitest": "^4.1.8"
70
71
  },
@@ -6,12 +6,21 @@ Generated by `create-authenik8-app`.
6
6
 
7
7
  ```bash
8
8
  npm install
9
- npm run docker:up
10
- npm run prisma:migrate
9
+ npm run db:migrate
11
10
  npm run dev
12
11
  ```
13
12
 
14
- For SQLite, Postgres in `docker-compose.yml` is optional. Redis is required for refresh-token rotation and replay protection.
13
+ The generated local environment uses an in-process Redis-compatible store, so Redis and Docker are optional during development. If you selected PostgreSQL, start it with `npm run docker:up` or point `DATABASE_URL` to an existing instance before migrating.
14
+
15
+ Validate the generated auth configuration and Redis connection at any time:
16
+
17
+ ```bash
18
+ npx create-authenik8-app@latest doctor
19
+ ```
20
+
21
+ `authenik8.json` records the generated architecture and Authenik8 engine version. It contains no secrets and should be committed with the project.
22
+
23
+ After committing the package-manager lockfile, run `npx create-authenik8-app@latest add ci-github` to add the pinned Doctor and upgrade-policy workflow. Preview it first with `--dry-run`.
15
24
 
16
25
  ## Environment
17
26
 
@@ -27,8 +36,7 @@ AUTHENIK8_ISSUER=http://localhost:3000
27
36
  AUTHENIK8_AUDIENCE=your-app-api
28
37
  AUTHENIK8_AGENTS={}
29
38
  REFRESH_SECRET=<generated-random-secret>
30
- REDIS_HOST=127.0.0.1
31
- REDIS_PORT=6379
39
+ REDIS_URL=memory://
32
40
  ```
33
41
 
34
42
  ## API Contract
@@ -80,8 +88,7 @@ Authorization: Bearer <accessToken>
80
88
  Start the API in one terminal:
81
89
 
82
90
  ```bash
83
- npm run docker:up
84
- npm run prisma:migrate
91
+ npm run db:migrate
85
92
  npm run dev
86
93
  ```
87
94
 
@@ -133,8 +140,8 @@ curl -s -X POST http://localhost:3000/auth/refresh \
133
140
  - `AUTHENIK8_ISSUER` / `AUTHENIK8_AUDIENCE`: required claims checked during verification.
134
141
  - `AUTHENIK8_AGENTS`: optional JSON map of agent IDs to exact `resource:action` scopes; keep `{}` to disable agent identity. See `AGENT_IDENTITY.md`.
135
142
  - `REFRESH_SECRET`: signs refresh tokens. Use a different long random value in production.
136
- - `REDIS_HOST`: Redis host for refresh-token/session security.
137
- - `REDIS_PORT`: Redis port, usually `6379` locally.
143
+ - `REDIS_URL`: use `memory://` for local development or `redis://` / `rediss://` for an external service. Production rejects `memory://`.
144
+ - `REDIS_HOST` / `REDIS_PORT` / `REDIS_PASSWORD`: optional external Redis settings used when `REDIS_URL` is omitted.
138
145
 
139
146
  ## Frontend Use
140
147
 
@@ -176,9 +183,11 @@ export async function getProtected() {
176
183
 
177
184
  ## Troubleshooting
178
185
 
179
- `Redis connection refused`: run `npm run docker:up` or start Redis locally with `redis-server --daemonize yes`.
186
+ `Redis connection refused`: verify `REDIS_URL`, or omit it and check `REDIS_HOST`, `REDIS_PORT`, and `REDIS_PASSWORD`.
187
+
188
+ `Prisma Client did not initialize`: run `npm run db:migrate`, then restart `npm run dev`.
180
189
 
181
- `Prisma Client did not initialize`: run `npm run prisma:migrate`, then restart `npm run dev`.
190
+ `REDIS_URL=memory:// is for local development only`: configure a `redis://` or `rediss://` endpoint before running in production.
182
191
 
183
192
  `AUTHENIK8_SIGNING_JWKS must be a valid JSON array`: restore the generated `.env` value or provide an ES256 P-256 key ring and matching `AUTHENIK8_ACTIVE_KID`.
184
193
 
@@ -196,4 +205,4 @@ Read `THREAT_MODEL.md` before deploying. It explains what Authenik8 protects, wh
196
205
 
197
206
  ## Deploy
198
207
 
199
- Use `npm run build`, run `npx prisma migrate deploy` for production databases, set real secrets in your host, and point Redis/Postgres env vars at managed services.
208
+ Use `npm run build`, run `npx prisma migrate deploy` for production databases, set `NODE_ENV=production`, store real secrets in your host, and point Redis/Postgres environment variables at managed services.
@@ -7,10 +7,11 @@
7
7
  "node": "^20.19 || ^22.12 || >=24"
8
8
  },
9
9
  "scripts": {
10
- "dev": "ts-node-dev --respawn --transpile-only src/server.ts",
10
+ "dev": "tsx watch src/server.ts",
11
11
  "build": "tsc",
12
12
  "start": "node dist/server.js",
13
- "prisma:migrate": "prisma migrate dev && prisma generate",
13
+ "db:migrate": "prisma db push && prisma generate",
14
+ "prisma:migrate": "prisma db push && prisma generate",
14
15
  "docker:up": "docker compose up -d --wait",
15
16
  "docker:down": "docker compose down"
16
17
  },
@@ -18,17 +19,20 @@
18
19
  "authenik8-core": "2.0.3",
19
20
  "dotenv": "^16.0.0",
20
21
  "express": "^4.19.2",
21
- "@prisma/client": "7.8.0",
22
+ "@prisma/client": "7.9.0",
23
+ "ioredis": "^5.8.1",
22
24
  "zod": "^4.4.3"
23
25
  },
24
26
  "devDependencies": {
25
27
  "@types/express": "^4.17.21",
26
28
  "@types/node": "^26.0.1",
27
- "ts-node-dev": "^2.0.0",
28
- "typescript": "^5.0.0",
29
- "prisma": "7.8.0"
29
+ "ioredis-mock": "8.13.1",
30
+ "prisma": "7.9.0",
31
+ "tsx": "^4.22.4",
32
+ "typescript": "^5.0.0"
30
33
  },
31
34
  "overrides": {
32
- "@hono/node-server": "1.19.13"
35
+ "find-my-way": "9.7.0",
36
+ "valibot": "1.4.2"
33
37
  }
34
38
  }
@@ -0,0 +1,109 @@
1
+ import Redis, { type Redis as RedisClient } from "ioredis";
2
+
3
+ const localRedisUrl = "memory://";
4
+ const redisOptions = {
5
+ connectTimeout: 5_000,
6
+ enableReadyCheck: true,
7
+ maxRetriesPerRequest: 2,
8
+ };
9
+
10
+ function externalRedisUrl(source: string): string {
11
+ let url: URL;
12
+ try {
13
+ url = new URL(source);
14
+ } catch {
15
+ throw new Error("REDIS_URL must be memory://, redis://, or rediss://");
16
+ }
17
+
18
+ if (url.protocol !== "redis:" && url.protocol !== "rediss:") {
19
+ throw new Error("REDIS_URL must be memory://, redis://, or rediss://");
20
+ }
21
+
22
+ return source;
23
+ }
24
+
25
+ function redisPort(): number {
26
+ const port = Number(process.env.REDIS_PORT?.trim() || "6379");
27
+ if (!Number.isInteger(port) || port < 1 || port > 65_535) {
28
+ throw new Error("REDIS_PORT must be an integer from 1 to 65535");
29
+ }
30
+ return port;
31
+ }
32
+
33
+ function waitForRedis(client: RedisClient): Promise<RedisClient> {
34
+ return new Promise((resolve, reject) => {
35
+ let settled = false;
36
+ let readinessCheckStarted = false;
37
+ const cleanup = () => {
38
+ client.off("ready", handleReady);
39
+ client.off("error", handleError);
40
+ };
41
+ const finish = (error?: Error) => {
42
+ if (settled) return;
43
+ settled = true;
44
+ cleanup();
45
+ if (error) {
46
+ client.disconnect();
47
+ reject(error);
48
+ } else {
49
+ resolve(client);
50
+ }
51
+ };
52
+ const handleReady = () => {
53
+ if (readinessCheckStarted) return;
54
+ readinessCheckStarted = true;
55
+ void client.ping().then(() => finish(), (error: Error) => finish(error));
56
+ };
57
+ const handleError = (error: Error) => finish(error);
58
+
59
+ client.once("ready", handleReady);
60
+ client.once("error", handleError);
61
+ if (client.status === "ready") handleReady();
62
+ });
63
+ }
64
+
65
+ export async function createRedisClient(): Promise<RedisClient> {
66
+ const redisUrl = process.env.REDIS_URL?.trim();
67
+ const nodeEnv = process.env.NODE_ENV?.trim() || "development";
68
+
69
+ const hasExternalRedisConfig = Boolean(
70
+ redisUrl ||
71
+ process.env.REDIS_HOST?.trim() ||
72
+ process.env.REDIS_PORT?.trim() ||
73
+ process.env.REDIS_PASSWORD?.trim(),
74
+ );
75
+
76
+ if (redisUrl === localRedisUrl && nodeEnv === "production") {
77
+ throw new Error(
78
+ "REDIS_URL=memory:// is for local development only; use redis:// or rediss:// in production",
79
+ );
80
+ }
81
+
82
+ const shouldUseMemoryRedis =
83
+ redisUrl === localRedisUrl ||
84
+ (!hasExternalRedisConfig && nodeEnv !== "production");
85
+
86
+ if (shouldUseMemoryRedis) {
87
+ const { default: RedisMock } = await import("ioredis-mock");
88
+ return new RedisMock() as unknown as RedisClient;
89
+ }
90
+
91
+ if (nodeEnv === "production" && !hasExternalRedisConfig) {
92
+ throw new Error(
93
+ "REDIS_URL=memory:// is for local development only; use redis:// or rediss:// in production",
94
+ );
95
+ }
96
+
97
+ if (redisUrl) {
98
+ return waitForRedis(new Redis(externalRedisUrl(redisUrl), redisOptions));
99
+ }
100
+
101
+ return waitForRedis(new Redis({
102
+ ...redisOptions,
103
+ host: process.env.REDIS_HOST?.trim() || "127.0.0.1",
104
+ port: redisPort(),
105
+ ...(process.env.REDIS_PASSWORD?.trim()
106
+ ? { password: process.env.REDIS_PASSWORD.trim() }
107
+ : {}),
108
+ }));
109
+ }
@@ -1,6 +1,7 @@
1
1
  import dotenv from "dotenv";
2
2
  import { createAuthenik8 } from "authenik8-core";
3
3
  import { createApp } from "./app";
4
+ import { createRedisClient } from "./config/redis";
4
5
  import { agentIdentityConfig, authJwkConfig, requiredPort, requiredSecret } from "./utils/security";
5
6
 
6
7
  dotenv.config();
@@ -10,6 +11,7 @@ async function start() {
10
11
  jwt: authJwkConfig(),
11
12
  refreshSecret: requiredSecret("REFRESH_SECRET"),
12
13
  agent: agentIdentityConfig(),
14
+ redis: await createRedisClient(),
13
15
  });
14
16
 
15
17
  const app = createApp(auth);
@@ -6,12 +6,21 @@ Generated by `create-authenik8-app`.
6
6
 
7
7
  ```bash
8
8
  npm install
9
- npm run docker:up
10
- npm run prisma:migrate
9
+ npm run db:migrate
11
10
  npm run dev
12
11
  ```
13
12
 
14
- For SQLite, Postgres in `docker-compose.yml` is optional. Redis is required for refresh-token rotation and replay protection.
13
+ The generated local environment uses an in-process Redis-compatible store, so Redis and Docker are optional during development. If you selected PostgreSQL, start it with `npm run docker:up` or point `DATABASE_URL` to an existing instance before migrating.
14
+
15
+ Validate the generated auth configuration and Redis connection at any time:
16
+
17
+ ```bash
18
+ npx create-authenik8-app@latest doctor
19
+ ```
20
+
21
+ `authenik8.json` records the generated architecture and Authenik8 engine version. It contains no secrets and should be committed with the project.
22
+
23
+ After committing the package-manager lockfile, run `npx create-authenik8-app@latest add ci-github` to add the pinned Doctor and upgrade-policy workflow. Preview it first with `--dry-run`.
15
24
 
16
25
  ## Environment
17
26
 
@@ -27,12 +36,10 @@ AUTHENIK8_ISSUER=http://localhost:3000
27
36
  AUTHENIK8_AUDIENCE=your-app-api
28
37
  AUTHENIK8_AGENTS={}
29
38
  REFRESH_SECRET=<generated-random-secret>
30
- REDIS_HOST=127.0.0.1
31
- REDIS_PORT=6379
32
- AUTHENIK8_OAUTH_PROVIDERS=google,github
39
+ REDIS_URL=memory://
33
40
  ```
34
41
 
35
- OAuth provider config is only required for providers listed in `AUTHENIK8_OAUTH_PROVIDERS`.
42
+ OAuth provider config is only required for providers selected during generation.
36
43
 
37
44
  ```bash
38
45
  GOOGLE_CLIENT_ID=your-google-client-id
@@ -103,8 +110,7 @@ Authorization: Bearer <accessToken>
103
110
  Start the API in one terminal:
104
111
 
105
112
  ```bash
106
- npm run docker:up
107
- npm run prisma:migrate
113
+ npm run db:migrate
108
114
  npm run dev
109
115
  ```
110
116
 
@@ -147,7 +153,7 @@ http://localhost:3000/auth/google
147
153
  http://localhost:3000/auth/github
148
154
  ```
149
155
 
150
- If a provider is not listed in `AUTHENIK8_OAUTH_PROVIDERS`, that provider route returns a clear `404` JSON response.
156
+ Only provider routes selected during generation are included in the project.
151
157
 
152
158
  ## Environment Variables
153
159
 
@@ -157,9 +163,8 @@ If a provider is not listed in `AUTHENIK8_OAUTH_PROVIDERS`, that provider route
157
163
  - `AUTHENIK8_ISSUER` / `AUTHENIK8_AUDIENCE`: required claims checked during verification.
158
164
  - `AUTHENIK8_AGENTS`: optional JSON map of agent IDs to exact `resource:action` scopes; keep `{}` to disable agent identity. See `AGENT_IDENTITY.md`.
159
165
  - `REFRESH_SECRET`: signs refresh tokens. Use a different long random value in production.
160
- - `REDIS_HOST`: Redis host for refresh-token/session security.
161
- - `REDIS_PORT`: Redis port, usually `6379` locally.
162
- - `AUTHENIK8_OAUTH_PROVIDERS`: comma-separated enabled providers, for example `google`, `github`, or `google,github`.
166
+ - `REDIS_URL`: use `memory://` for local development or `redis://` / `rediss://` for an external service. Production rejects `memory://`.
167
+ - `REDIS_HOST` / `REDIS_PORT` / `REDIS_PASSWORD`: optional external Redis settings used when `REDIS_URL` is omitted.
163
168
  - `GOOGLE_REDIRECT_URI`: must exactly match the callback URL configured in Google Cloud.
164
169
  - `GITHUB_REDIRECT_URI`: must exactly match the callback URL configured in GitHub OAuth Apps.
165
170
 
@@ -223,9 +228,11 @@ The callback URL in `.env` must match the provider dashboard exactly, including
223
228
 
224
229
  ## Troubleshooting
225
230
 
226
- `Redis connection refused`: run `npm run docker:up` or start Redis locally with `redis-server --daemonize yes`.
231
+ `Redis connection refused`: verify `REDIS_URL`, or omit it and check `REDIS_HOST`, `REDIS_PORT`, and `REDIS_PASSWORD`.
232
+
233
+ `Prisma Client did not initialize`: run `npm run db:migrate`, then restart `npm run dev`.
227
234
 
228
- `Prisma Client did not initialize`: run `npm run prisma:migrate`, then restart `npm run dev`.
235
+ `REDIS_URL=memory:// is for local development only`: configure a `redis://` or `rediss://` endpoint before running in production.
229
236
 
230
237
  `AUTHENIK8_SIGNING_JWKS must be a valid JSON array`: restore the generated `.env` value or provide an ES256 P-256 key ring and matching `AUTHENIK8_ACTIVE_KID`.
231
238
 
@@ -233,9 +240,9 @@ The callback URL in `.env` must match the provider dashboard exactly, including
233
240
 
234
241
  `OAuth redirect_uri_mismatch`: copy the callback URL from `.env` into the provider dashboard exactly.
235
242
 
236
- `github OAuth is not configured`: add `github` to `AUTHENIK8_OAUTH_PROVIDERS` and set the GitHub env vars, or use only the enabled provider route.
243
+ `GitHub OAuth is not configured`: set the GitHub client ID, secret, and callback URL in `.env`.
237
244
 
238
- `google OAuth is not configured`: add `google` to `AUTHENIK8_OAUTH_PROVIDERS` and set the Google env vars, or use only the enabled provider route.
245
+ `Google OAuth is not configured`: set the Google client ID, secret, and callback URL in `.env`.
239
246
 
240
247
  `Port 3000 already in use`: stop the other process or set `PORT` in `.env`.
241
248
 
@@ -247,4 +254,4 @@ Read `THREAT_MODEL.md` before deploying. It explains what Authenik8 protects, wh
247
254
 
248
255
  ## Deploy
249
256
 
250
- Use `npm run build`, run `npx prisma migrate deploy` for production databases, set real secrets in your host, and point Redis/Postgres env vars at managed services.
257
+ Use `npm run build`, run `npx prisma migrate deploy` for production databases, set `NODE_ENV=production`, store real secrets in your host, and point Redis/Postgres environment variables at managed services.
@@ -7,10 +7,11 @@
7
7
  "node": "^20.19 || ^22.12 || >=24"
8
8
  },
9
9
  "scripts": {
10
- "dev": "ts-node-dev --respawn --transpile-only src/server.ts",
10
+ "dev": "tsx watch src/server.ts",
11
11
  "build": "tsc",
12
12
  "start": "node dist/server.js",
13
- "prisma:migrate": "prisma migrate dev && prisma generate",
13
+ "db:migrate": "prisma db push && prisma generate",
14
+ "prisma:migrate": "prisma db push && prisma generate",
14
15
  "docker:up": "docker compose up -d --wait",
15
16
  "docker:down": "docker compose down"
16
17
  },
@@ -18,17 +19,20 @@
18
19
  "authenik8-core": "2.0.3",
19
20
  "dotenv": "^16.0.0",
20
21
  "express": "^4.19.2",
21
- "@prisma/client": "7.8.0",
22
+ "@prisma/client": "7.9.0",
23
+ "ioredis": "^5.8.1",
22
24
  "zod": "^4.4.3"
23
25
  },
24
26
  "devDependencies": {
25
27
  "@types/express": "^4.17.21",
26
28
  "@types/node": "^26.0.1",
27
- "ts-node-dev": "^2.0.0",
28
- "typescript": "^5.0.0",
29
- "prisma": "7.8.0"
29
+ "ioredis-mock": "8.13.1",
30
+ "prisma": "7.9.0",
31
+ "tsx": "^4.22.4",
32
+ "typescript": "^5.0.0"
30
33
  },
31
34
  "overrides": {
32
- "@hono/node-server": "1.19.13"
35
+ "find-my-way": "9.7.0",
36
+ "valibot": "1.4.2"
33
37
  }
34
38
  }
@@ -1,5 +1,6 @@
1
1
  import { createAuthenik8 } from "authenik8-core";
2
2
  import dotenv from "dotenv";
3
+ import { createRedisClient } from "../config/redis";
3
4
  import { agentIdentityConfig, authJwkConfig, requiredSecret } from "../utils/security";
4
5
 
5
6
  dotenv.config();
@@ -15,6 +16,7 @@ export async function initAuth() {
15
16
  jwt: authJwkConfig(),
16
17
  refreshSecret: requiredSecret("REFRESH_SECRET"),
17
18
  agent: agentIdentityConfig(),
19
+ redis: await createRedisClient(),
18
20
  oauth: oauthConfig(),
19
21
  });
20
22
 
@@ -2,7 +2,7 @@ import { Request, Response } from "express";
2
2
  import { getAuth } from "../auth";
3
3
  import { prisma } from "../../prisma/client";
4
4
  import { hashPassword, comparePassword } from "../../utils/hash";
5
- import { parseCredentials } from "../../utils/security";
5
+ import { parseCredentials, parseRefreshToken } from "../../utils/security";
6
6
 
7
7
  export const passwordController = {
8
8
  async register(req: Request, res: Response) {
@@ -48,4 +48,15 @@ export const passwordController = {
48
48
  res.status(401).json({ error: "Invalid credentials" });
49
49
  }
50
50
  },
51
+
52
+ async refresh(req: Request, res: Response) {
53
+ try {
54
+ const refreshToken = parseRefreshToken(req.body);
55
+ const tokens = await getAuth().refreshToken(refreshToken);
56
+
57
+ res.json(tokens);
58
+ } catch {
59
+ res.status(401).json({ error: "Invalid refresh token" });
60
+ }
61
+ },
51
62
  };
@@ -5,5 +5,6 @@ const router = express.Router();
5
5
 
6
6
  router.post("/register", passwordController.register);
7
7
  router.post("/login", passwordController.login);
8
+ router.post("/refresh", passwordController.refresh);
8
9
 
9
10
  export default router;