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.
- package/README.md +34 -516
- package/dist/src/bin/cli.d.ts +3 -0
- package/dist/src/bin/cli.d.ts.map +1 -0
- package/dist/src/bin/cli.js +112 -0
- package/dist/src/bin/cli.js.map +1 -0
- package/dist/src/bin/index.js +108 -23
- package/dist/src/bin/index.js.map +1 -1
- package/dist/src/commands/add/apply.d.ts +6 -0
- package/dist/src/commands/add/apply.d.ts.map +1 -0
- package/dist/src/commands/add/apply.js +123 -0
- package/dist/src/commands/add/apply.js.map +1 -0
- package/dist/src/commands/add/ci.d.ts +6 -0
- package/dist/src/commands/add/ci.d.ts.map +1 -0
- package/dist/src/commands/add/ci.js +108 -0
- package/dist/src/commands/add/ci.js.map +1 -0
- package/dist/src/commands/add/context.d.ts +5 -0
- package/dist/src/commands/add/context.d.ts.map +1 -0
- package/dist/src/commands/add/context.js +19 -0
- package/dist/src/commands/add/context.js.map +1 -0
- package/dist/src/commands/add/diff.d.ts +4 -0
- package/dist/src/commands/add/diff.d.ts.map +1 -0
- package/dist/src/commands/add/diff.js +114 -0
- package/dist/src/commands/add/diff.js.map +1 -0
- package/dist/src/commands/add/index.d.ts +6 -0
- package/dist/src/commands/add/index.d.ts.map +1 -0
- package/dist/src/commands/add/index.js +61 -0
- package/dist/src/commands/add/index.js.map +1 -0
- package/dist/src/commands/add/output.d.ts +5 -0
- package/dist/src/commands/add/output.d.ts.map +1 -0
- package/dist/src/commands/add/output.js +58 -0
- package/dist/src/commands/add/output.js.map +1 -0
- package/dist/src/commands/add/plan.d.ts +6 -0
- package/dist/src/commands/add/plan.d.ts.map +1 -0
- package/dist/src/commands/add/plan.js +93 -0
- package/dist/src/commands/add/plan.js.map +1 -0
- package/dist/src/commands/add/registry.d.ts +4 -0
- package/dist/src/commands/add/registry.d.ts.map +1 -0
- package/dist/src/commands/add/registry.js +37 -0
- package/dist/src/commands/add/registry.js.map +1 -0
- package/dist/src/commands/add/types.d.ts +37 -0
- package/dist/src/commands/add/types.d.ts.map +1 -0
- package/dist/src/commands/add/types.js +2 -0
- package/dist/src/commands/add/types.js.map +1 -0
- package/dist/src/commands/doctor/checks.d.ts +3 -0
- package/dist/src/commands/doctor/checks.d.ts.map +1 -0
- package/dist/src/commands/doctor/checks.js +353 -0
- package/dist/src/commands/doctor/checks.js.map +1 -0
- package/dist/src/commands/doctor/context.d.ts +5 -0
- package/dist/src/commands/doctor/context.d.ts.map +1 -0
- package/dist/src/commands/doctor/context.js +134 -0
- package/dist/src/commands/doctor/context.js.map +1 -0
- package/dist/src/commands/doctor/index.d.ts +9 -0
- package/dist/src/commands/doctor/index.d.ts.map +1 -0
- package/dist/src/commands/doctor/index.js +80 -0
- package/dist/src/commands/doctor/index.js.map +1 -0
- package/dist/src/commands/doctor/output.d.ts +4 -0
- package/dist/src/commands/doctor/output.d.ts.map +1 -0
- package/dist/src/commands/doctor/output.js +53 -0
- package/dist/src/commands/doctor/output.js.map +1 -0
- package/dist/src/commands/doctor/postGeneration.d.ts +7 -0
- package/dist/src/commands/doctor/postGeneration.d.ts.map +1 -0
- package/dist/src/commands/doctor/postGeneration.js +22 -0
- package/dist/src/commands/doctor/postGeneration.js.map +1 -0
- package/dist/src/commands/doctor/services.d.ts +5 -0
- package/dist/src/commands/doctor/services.d.ts.map +1 -0
- package/dist/src/commands/doctor/services.js +80 -0
- package/dist/src/commands/doctor/services.js.map +1 -0
- package/dist/src/commands/doctor/types.d.ts +69 -0
- package/dist/src/commands/doctor/types.d.ts.map +1 -0
- package/dist/src/commands/doctor/types.js +2 -0
- package/dist/src/commands/doctor/types.js.map +1 -0
- package/dist/src/commands/upgrade/context.d.ts +5 -0
- package/dist/src/commands/upgrade/context.d.ts.map +1 -0
- package/dist/src/commands/upgrade/context.js +57 -0
- package/dist/src/commands/upgrade/context.js.map +1 -0
- package/dist/src/commands/upgrade/index.d.ts +7 -0
- package/dist/src/commands/upgrade/index.d.ts.map +1 -0
- package/dist/src/commands/upgrade/index.js +35 -0
- package/dist/src/commands/upgrade/index.js.map +1 -0
- package/dist/src/commands/upgrade/migrations.d.ts +4 -0
- package/dist/src/commands/upgrade/migrations.d.ts.map +1 -0
- package/dist/src/commands/upgrade/migrations.js +22 -0
- package/dist/src/commands/upgrade/migrations.js.map +1 -0
- package/dist/src/commands/upgrade/output.d.ts +4 -0
- package/dist/src/commands/upgrade/output.d.ts.map +1 -0
- package/dist/src/commands/upgrade/output.js +52 -0
- package/dist/src/commands/upgrade/output.js.map +1 -0
- package/dist/src/commands/upgrade/plan.d.ts +3 -0
- package/dist/src/commands/upgrade/plan.d.ts.map +1 -0
- package/dist/src/commands/upgrade/plan.js +119 -0
- package/dist/src/commands/upgrade/plan.js.map +1 -0
- package/dist/src/commands/upgrade/types.d.ts +48 -0
- package/dist/src/commands/upgrade/types.d.ts.map +1 -0
- package/dist/src/commands/upgrade/types.js +2 -0
- package/dist/src/commands/upgrade/types.js.map +1 -0
- package/dist/src/lib/args.d.ts +21 -0
- package/dist/src/lib/args.d.ts.map +1 -1
- package/dist/src/lib/args.js +119 -1
- package/dist/src/lib/args.js.map +1 -1
- package/dist/src/lib/constants.d.ts +1 -1
- package/dist/src/lib/constants.d.ts.map +1 -1
- package/dist/src/lib/constants.js +3 -1
- package/dist/src/lib/constants.js.map +1 -1
- package/dist/src/lib/expressOAuth.d.ts +10 -0
- package/dist/src/lib/expressOAuth.d.ts.map +1 -0
- package/dist/src/lib/expressOAuth.js +164 -0
- package/dist/src/lib/expressOAuth.js.map +1 -0
- package/dist/src/lib/interruption.d.ts +14 -0
- package/dist/src/lib/interruption.d.ts.map +1 -0
- package/dist/src/lib/interruption.js +16 -0
- package/dist/src/lib/interruption.js.map +1 -0
- package/dist/src/lib/nonInteractive.d.ts +8 -0
- package/dist/src/lib/nonInteractive.d.ts.map +1 -0
- package/dist/src/lib/nonInteractive.js +111 -0
- package/dist/src/lib/nonInteractive.js.map +1 -0
- package/dist/src/lib/oauth.d.ts +9 -0
- package/dist/src/lib/oauth.d.ts.map +1 -0
- package/dist/src/lib/oauth.js +62 -0
- package/dist/src/lib/oauth.js.map +1 -0
- package/dist/src/lib/onboarding.d.ts +8 -0
- package/dist/src/lib/onboarding.d.ts.map +1 -0
- package/dist/src/lib/onboarding.js +35 -0
- package/dist/src/lib/onboarding.js.map +1 -0
- package/dist/src/lib/packageManagerCommands.d.ts +11 -0
- package/dist/src/lib/packageManagerCommands.d.ts.map +1 -0
- package/dist/src/lib/packageManagerCommands.js +34 -0
- package/dist/src/lib/packageManagerCommands.js.map +1 -0
- package/dist/src/lib/process.d.ts.map +1 -1
- package/dist/src/lib/process.js +9 -0
- package/dist/src/lib/process.js.map +1 -1
- package/dist/src/lib/projectManifest.d.ts +67 -0
- package/dist/src/lib/projectManifest.d.ts.map +1 -0
- package/dist/src/lib/projectManifest.js +134 -0
- package/dist/src/lib/projectManifest.js.map +1 -0
- package/dist/src/lib/release.d.ts +9 -0
- package/dist/src/lib/release.d.ts.map +1 -0
- package/dist/src/lib/release.js +48 -0
- package/dist/src/lib/release.js.map +1 -0
- package/dist/src/lib/rootCommand.d.ts +15 -0
- package/dist/src/lib/rootCommand.d.ts.map +1 -0
- package/dist/src/lib/rootCommand.js +17 -0
- package/dist/src/lib/rootCommand.js.map +1 -0
- package/dist/src/lib/schemas.d.ts +15 -6
- package/dist/src/lib/schemas.d.ts.map +1 -1
- package/dist/src/lib/schemas.js +8 -1
- package/dist/src/lib/schemas.js.map +1 -1
- package/dist/src/lib/semver.d.ts +10 -0
- package/dist/src/lib/semver.d.ts.map +1 -0
- package/dist/src/lib/semver.js +51 -0
- package/dist/src/lib/semver.js.map +1 -0
- package/dist/src/lib/types.d.ts +5 -1
- package/dist/src/lib/types.d.ts.map +1 -1
- package/dist/src/steps/configurePrisma.d.ts.map +1 -1
- package/dist/src/steps/configurePrisma.js +18 -23
- package/dist/src/steps/configurePrisma.js.map +1 -1
- package/dist/src/steps/configureReadme.d.ts +4 -0
- package/dist/src/steps/configureReadme.d.ts.map +1 -0
- package/dist/src/steps/configureReadme.js +22 -0
- package/dist/src/steps/configureReadme.js.map +1 -0
- package/dist/src/steps/createProject.d.ts.map +1 -1
- package/dist/src/steps/createProject.js +16 -170
- package/dist/src/steps/createProject.js.map +1 -1
- package/dist/src/steps/finalSetup.d.ts +3 -2
- package/dist/src/steps/finalSetup.d.ts.map +1 -1
- package/dist/src/steps/finalSetup.js +14 -9
- package/dist/src/steps/finalSetup.js.map +1 -1
- package/dist/src/steps/installDeps.d.ts +1 -0
- package/dist/src/steps/installDeps.d.ts.map +1 -1
- package/dist/src/steps/installDeps.js +11 -0
- package/dist/src/steps/installDeps.js.map +1 -1
- package/dist/src/steps/prompts.d.ts.map +1 -1
- package/dist/src/steps/prompts.js +32 -13
- package/dist/src/steps/prompts.js.map +1 -1
- package/dist/src/utils/output.d.ts.map +1 -1
- package/dist/src/utils/output.js +23 -11
- package/dist/src/utils/output.js.map +1 -1
- package/package.json +5 -4
- package/templates/express-auth/README.md +21 -12
- package/templates/express-auth/package.json +11 -7
- package/templates/express-auth/src/config/redis.ts +109 -0
- package/templates/express-auth/src/server.ts +2 -0
- package/templates/express-auth+/README.md +25 -18
- package/templates/express-auth+/package.json +11 -7
- package/templates/express-auth+/src/auth/auth.ts +2 -0
- package/templates/express-auth+/src/auth/controllers/password.controller.ts +12 -1
- package/templates/express-auth+/src/auth/routes/password.route.ts +1 -0
- package/templates/express-auth+/src/config/redis.ts +109 -0
- package/templates/express-auth+/src/utils/security.ts +12 -0
- package/templates/express-base/README.md +21 -12
- package/templates/express-base/package.json +11 -8
- package/templates/express-base/src/.env.example +1 -1
- package/templates/express-base/src/config/redis.ts +109 -0
- package/templates/express-base/src/server.ts +2 -0
- package/templates/fullstack/.env.example +3 -2
- package/templates/fullstack/PRESET_CONTRACT.md +7 -3
- package/templates/fullstack/README.md +45 -7
- package/templates/fullstack/apps/api/package.json +6 -4
- package/templates/fullstack/apps/api/prisma/migrations/20260721000000_init/migration.sql +163 -0
- package/templates/fullstack/apps/api/prisma/migrations/migration_lock.toml +3 -0
- package/templates/fullstack/apps/api/src/auth/authenik8.ts +13 -4
- package/templates/fullstack/apps/api/src/config/env.ts +9 -1
- package/templates/fullstack/apps/api/src/config/logger.ts +21 -11
- package/templates/fullstack/apps/api/tests/logger.test.ts +43 -0
- package/templates/fullstack/apps/web/package.json +3 -1
- package/templates/fullstack/apps/web/src/App.tsx +1 -1
- package/templates/fullstack/apps/web/src/auth/RouteGuards.tsx +1 -1
- package/templates/fullstack/apps/web/src/components/AppShell.tsx +90 -45
- package/templates/fullstack/apps/web/src/components/AuthShell.tsx +10 -7
- package/templates/fullstack/apps/web/src/components/Page.tsx +6 -3
- package/templates/fullstack/apps/web/src/features/projects/ProjectPages.tsx +1 -1
- package/templates/fullstack/apps/web/src/main.tsx +13 -6
- package/templates/fullstack/apps/web/src/pages/DashboardPage.tsx +163 -23
- package/templates/fullstack/apps/web/src/pages/StatusPages.tsx +1 -1
- package/templates/fullstack/apps/web/src/pages/auth/LoginPage.tsx +93 -17
- package/templates/fullstack/apps/web/src/pages/auth/OAuthCallbackPage.tsx +1 -1
- package/templates/fullstack/apps/web/src/pages/auth/RecoveryPages.tsx +1 -1
- package/templates/fullstack/apps/web/src/pages/auth/RegisterPage.tsx +1 -1
- package/templates/fullstack/apps/web/src/pages/auth/VerifyEmailPage.tsx +1 -1
- package/templates/fullstack/apps/web/src/styles.css +119 -43
- package/templates/fullstack/apps/web/vite.config.ts +12 -0
- package/templates/fullstack/docker-compose.yml +2 -2
- package/templates/fullstack/gitignore.template +1 -0
- package/templates/fullstack/package.json +17 -8
- package/templates/fullstack/scripts/run-local.mjs +157 -0
- package/templates/prisma/postgresql/.env.example +1 -2
- package/templates/prisma/sqlite/.env.example +1 -2
- package/templates/prisma/sqlite/client.ts +2 -2
package/dist/src/utils/output.js
CHANGED
|
@@ -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
|
|
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 ? [
|
|
41
|
-
...(hasDockerCompose && hasDockerDaemon
|
|
42
|
-
|
|
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.
|
|
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
|
-
|
|
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":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"output.js","sourceRoot":"","sources":["../../../src/utils/output.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-authenik8-app",
|
|
3
|
-
"version": "2.4.
|
|
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/
|
|
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": "^
|
|
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.
|
|
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
|
|
10
|
-
npm run prisma:migrate
|
|
9
|
+
npm run db:migrate
|
|
11
10
|
npm run dev
|
|
12
11
|
```
|
|
13
12
|
|
|
14
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
- `
|
|
137
|
-
- `REDIS_PORT`: Redis
|
|
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`:
|
|
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
|
-
`
|
|
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
|
|
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": "
|
|
10
|
+
"dev": "tsx watch src/server.ts",
|
|
11
11
|
"build": "tsc",
|
|
12
12
|
"start": "node dist/server.js",
|
|
13
|
-
"
|
|
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.
|
|
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
|
-
"
|
|
28
|
-
"
|
|
29
|
-
|
|
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
|
-
"
|
|
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
|
|
10
|
-
npm run prisma:migrate
|
|
9
|
+
npm run db:migrate
|
|
11
10
|
npm run dev
|
|
12
11
|
```
|
|
13
12
|
|
|
14
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
- `
|
|
161
|
-
- `REDIS_PORT`: Redis
|
|
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`:
|
|
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
|
-
`
|
|
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
|
-
`
|
|
243
|
+
`GitHub OAuth is not configured`: set the GitHub client ID, secret, and callback URL in `.env`.
|
|
237
244
|
|
|
238
|
-
`
|
|
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
|
|
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": "
|
|
10
|
+
"dev": "tsx watch src/server.ts",
|
|
11
11
|
"build": "tsc",
|
|
12
12
|
"start": "node dist/server.js",
|
|
13
|
-
"
|
|
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.
|
|
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
|
-
"
|
|
28
|
-
"
|
|
29
|
-
|
|
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
|
-
"
|
|
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
|
};
|