create-authenik8-app 1.0.6 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,4 +1,8 @@
1
1
 
2
+
3
+
4
+ ---
5
+
2
6
  # create-authenik8-app
3
7
 
4
8
  <p align="center">
@@ -11,7 +15,7 @@
11
15
 
12
16
  ---
13
17
 
14
- ## Usage
18
+ ## 📦 Usage
15
19
 
16
20
  Create a new project:
17
21
 
@@ -23,8 +27,8 @@ Then:
23
27
  cd my-app
24
28
  npm install
25
29
  npm run dev
26
-
27
30
  ```
31
+
28
32
  ---
29
33
 
30
34
  ## What you get instantly
@@ -33,19 +37,19 @@ A fully working Express authentication starter with:
33
37
 
34
38
  JWT authentication (access + refresh tokens)
35
39
 
36
- Secure refresh token rotation
40
+ Secure refresh token rotation
37
41
 
38
- Redis-based token storage
42
+ Redis-based token storage
39
43
 
40
- Role-Based Access Control (RBAC)
44
+ Role-Based Access Control (RBAC)
41
45
 
42
46
  TypeScript setup
43
47
 
44
- Express server preconfigured
48
+ Express server preconfigured
45
49
 
46
50
  Clean scalable folder structure
47
51
 
48
- .env file generated automatically
52
+ .env file generated automatically
49
53
 
50
54
 
51
55
 
@@ -79,8 +83,8 @@ Redis (required for refresh tokens)
79
83
 
80
84
  ---
81
85
 
82
- ## Redis Setup
83
- ```
86
+ ## Redis Setup
87
+ ```
84
88
 
85
89
  Local
86
90
 
@@ -89,10 +93,11 @@ redis-server
89
93
  Docker
90
94
 
91
95
  docker run -p 6379:6379 redis
96
+
92
97
  ```
93
98
  ---
94
99
 
95
- Environment Variables
100
+ ## Environment Variables
96
101
 
97
102
  Generated automatically:
98
103
  ```
@@ -101,22 +106,22 @@ REFRESH_SECRET=your-refresh-secret
101
106
 
102
107
  REDIS_HOST=127.0.0.1
103
108
  REDIS_PORT=6379
104
- ```
105
109
 
110
+ ```
106
111
  ---
107
112
 
108
- RBAC Example
109
-
110
- Example of a protected route:
113
+ ## RBAC Example
111
114
  ```
115
+ Example of a protected route:
116
+
112
117
  app.get("/admin", auth.requireAdmin, (req, res) => {
113
118
  res.json({ message: "Admin only route" });
114
119
  });
115
- ```
116
120
 
121
+ ```
117
122
  ---
118
123
 
119
- ## Powered by
124
+ 📦 Powered by
120
125
 
121
126
  authenik8-core
122
127
 
@@ -126,9 +131,10 @@ authenik8-core
126
131
 
127
132
  ## Project Structure
128
133
  ```
134
+
129
135
  my-app/
130
136
  ├── src/
131
-
137
+ |
132
138
  │ ├
133
139
  │ └── server.ts
134
140
  ├── .env
@@ -150,7 +156,7 @@ RBAC is included via middleware (e.g. requireAdmin)
150
156
 
151
157
  ---
152
158
 
153
- ## Roadmap
159
+ ## Roadmap
154
160
 
155
161
  OAuth providers (Google, GitHub)
156
162
 
@@ -162,3 +168,6 @@ Admin dashboard
162
168
 
163
169
  Production presets
164
170
 
171
+
172
+
173
+ ---
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/bin/index.ts"],"names":[],"mappings":""}
@@ -0,0 +1,250 @@
1
+ #!/usr/bin/env node
2
+ import fs from "fs-extra";
3
+ import path from "path";
4
+ import chalk from "chalk";
5
+ import inquirer from "inquirer";
6
+ import { ExitPromptError } from "@inquirer/core";
7
+ import ora from "ora";
8
+ import { execSync } from "child_process";
9
+ import { fileURLToPath } from "url";
10
+ const __filename = fileURLToPath(import.meta.url);
11
+ const __dirname = path.dirname(__filename);
12
+ const projectName = process.argv[2];
13
+ if (!projectName) {
14
+ console.log(chalk.red("❌ Please provide a project name"));
15
+ process.exit(1);
16
+ }
17
+ const targetDir = path.join(process.cwd(), projectName);
18
+ let projectCreated = false;
19
+ async function main() {
20
+ console.log(chalk.blue.bold("\n🚀 Authenik8 App Generator\n"));
21
+ if (process.argv.includes("--help")) {
22
+ console.log(`
23
+ Authenik8 CLI
24
+
25
+ Usage:
26
+ create-authenik8-app <project-name>
27
+
28
+ Options:
29
+ --help Show this help message
30
+
31
+ Features:
32
+ - Express backend (default)
33
+ - Optional Prisma ORM
34
+ - PostgreSQL (production)
35
+ - SQLite (quick start)
36
+ - Optional Git initialization
37
+
38
+ Examples:
39
+ create-authenik8-app my-app
40
+ `);
41
+ process.exit(0);
42
+ }
43
+ console.log(chalk.gray(`
44
+ Available options:
45
+
46
+ Frameworks:
47
+ - Express
48
+ - Fastify(coming soon)
49
+
50
+ Database (if Prisma enabled):
51
+ - PostgreSQL
52
+ - SQLite (quick start)
53
+
54
+ Features:
55
+ - Prisma ORM (optional)
56
+ - Git initialization (optional)
57
+ `));
58
+ // 🔥 PROMPTS
59
+ const answers = await inquirer.prompt([
60
+ {
61
+ type: "list",
62
+ name: "framework",
63
+ message: "Choose framework:",
64
+ choices: ["Express", "Fastify (coming soon)"],
65
+ },
66
+ {
67
+ type: "confirm",
68
+ name: "usePrisma",
69
+ message: "Use Prisma?",
70
+ default: true,
71
+ },
72
+ {
73
+ type: "list",
74
+ name: "database",
75
+ message: "Choose database:",
76
+ choices: [
77
+ { name: "PostgreSQL", value: "postgresql(recommended for auth)" },
78
+ { name: "SQLite (quick start, limited features)", value: "sqlite" }
79
+ ],
80
+ when: (answers) => answers.usePrisma,
81
+ },
82
+ {
83
+ type: "confirm",
84
+ name: "useGit",
85
+ message: "Initialize git?",
86
+ default: true,
87
+ },
88
+ {
89
+ type: "confirm",
90
+ name: "usePasswordAuth",
91
+ message: "Include email/password authentication?",
92
+ default: true,
93
+ when: (answers) => answers.usePrisma && answers.database === "postgresql"
94
+ },
95
+ ]);
96
+ // 🚫 Prevent overwrite
97
+ if (fs.existsSync(targetDir)) {
98
+ console.log(chalk.red("\n❌ Folder already exists"));
99
+ process.exit(1);
100
+ }
101
+ console.log(chalk.cyan("\n⚙️ Setting things up...\n"));
102
+ const templateRoot = path.resolve(__dirname, "../../templates");
103
+ let templateName = "express-base";
104
+ if (answers.usePasswordAuth && answers.usePrisma) {
105
+ templateName = "express-auth";
106
+ }
107
+ const templatePath = path.join(templateRoot, templateName);
108
+ // 📁 Create project (SPINNER)
109
+ const createSpinner = ora("Creating project structure...").start();
110
+ try {
111
+ await fs.copy(templatePath, targetDir);
112
+ projectCreated = true;
113
+ createSpinner.succeed("Project files created");
114
+ }
115
+ catch (err) {
116
+ createSpinner.fail("Failed to create project");
117
+ console.error(err);
118
+ process.exit(1);
119
+ }
120
+ if (answers.usePrisma) {
121
+ const prismaSpinner = ora("Adding Prisma setup...").start();
122
+ try {
123
+ const dbType = answers.database ===
124
+ "postgresql" ? "postgresql"
125
+ : "sqlite";
126
+ const prismaTemplatePath = path.join(templateRoot, `prisma/${dbType}`);
127
+ // Copy prisma schema
128
+ await fs.copy(path.join(prismaTemplatePath, "schema.prisma"), path.join(targetDir, "prisma/schema.prisma"));
129
+ // Copy env
130
+ await fs.copy(path.join(prismaTemplatePath, ".env"), path.join(targetDir, ".env"));
131
+ const pkgPath = path.join(targetDir, "package.json");
132
+ const pkg = await fs.readJson(pkgPath);
133
+ await fs.writeJson(pkgPath, pkg, { spaces: 2 });
134
+ // Inject dependencies
135
+ pkg.dependencies = {
136
+ ...pkg.dependencies,
137
+ "@prisma/client": "5.22.0",
138
+ };
139
+ pkg.devDependencies = {
140
+ ...pkg.devDependencies,
141
+ prisma: "5.22.0",
142
+ };
143
+ // Add scripts
144
+ pkg.scripts = {
145
+ ...pkg.scripts,
146
+ "prisma:generate": "prisma generate",
147
+ "prisma:migrate": "prisma migrate dev",
148
+ };
149
+ prismaSpinner.succeed(`Prisma (${dbType}) configured`);
150
+ }
151
+ catch (err) {
152
+ prismaSpinner.fail("Failed to setup Prisma");
153
+ console.error(err);
154
+ }
155
+ const installSpinner = ora("Installing dependencies...(this may take a few minutes)").start();
156
+ try {
157
+ execSync("npm install", {
158
+ cwd: targetDir,
159
+ stdio: "ignore",
160
+ });
161
+ installSpinner.succeed("Dependencies installed");
162
+ }
163
+ catch (err) {
164
+ installSpinner.fail("Failed to install dependencies");
165
+ console.error(err);
166
+ process.exit(1);
167
+ }
168
+ if (answers.usePrisma) {
169
+ const prismaGenSpinner = ora("Generating Prisma client...").start();
170
+ try {
171
+ execSync("npx prisma@5.22.0 generate", {
172
+ cwd: targetDir,
173
+ stdio: "inherit"
174
+ });
175
+ prismaGenSpinner.succeed("Prisma client generated");
176
+ }
177
+ catch (err) {
178
+ prismaGenSpinner.fail("Failed to generate Prisma client");
179
+ console.error(err);
180
+ }
181
+ }
182
+ const authSpinner = ora("Installing password auth...").start();
183
+ try {
184
+ execSync("npm install argon2", {
185
+ cwd: targetDir,
186
+ stdio: "ignore",
187
+ });
188
+ authSpinner.succeed("Password auth ready (argon2)");
189
+ }
190
+ catch (err) {
191
+ authSpinner.fail("Failed to install password auth");
192
+ console.error(err);
193
+ process.exit(1);
194
+ }
195
+ }
196
+ if (answers.useGit) {
197
+ const gitSpinner = ora("Initializing git...").start();
198
+ try {
199
+ execSync("git init", {
200
+ cwd: targetDir,
201
+ stdio: "ignore",
202
+ });
203
+ gitSpinner.succeed("Git initialized");
204
+ }
205
+ catch (err) {
206
+ gitSpinner.fail("Git init failed");
207
+ }
208
+ }
209
+ console.log(chalk.green.bold("\n🎉 Authenik8 app created successfully!\n"));
210
+ console.log(chalk.white(`
211
+ Next steps:
212
+
213
+ cd ${projectName}
214
+ cp .env.example .env
215
+ npm run dev
216
+
217
+ 🔥 Your Authenik8 server is ready to go!
218
+ `));
219
+ console.log(`
220
+ ✔ Auth: ${answers.usePasswordAuth ? "JWT + Password" : "JWT only"}
221
+ ✔ Database: ${answers.usePrisma ? answers.database : "None"}
222
+ ✔ ORM: ${answers.usePrisma ? "Prisma" : "None"}
223
+ `);
224
+ }
225
+ process.on("SIGINT", async () => {
226
+ console.log("\n👋 Authenik8 setup cancelled.");
227
+ if (projectCreated && fs.existsSync(targetDir)) {
228
+ await fs.remove(targetDir);
229
+ console.log("🧹 Cleaned up incomplete project.");
230
+ }
231
+ process.exit(0);
232
+ });
233
+ main().catch(async (err) => {
234
+ if (err instanceof ExitPromptError) {
235
+ console.log("\n👋 Authenik8 setup cancelled.");
236
+ if (projectCreated && fs.existsSync(targetDir)) {
237
+ await fs.remove(targetDir);
238
+ console.log("🧹 Cleaned up incomplete project.");
239
+ }
240
+ process.exit(0);
241
+ }
242
+ console.error("\n❌ Unexpected error:");
243
+ console.error(err);
244
+ if (projectCreated && fs.existsSync(targetDir)) {
245
+ await fs.remove(targetDir);
246
+ console.log("🧹 Cleaned up incomplete project.");
247
+ }
248
+ process.exit(1);
249
+ });
250
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/bin/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-authenik8-app",
3
- "version": "1.0.6",
3
+ "version": "2.0.0",
4
4
  "description":"Create production-ready backend APIs in seconds. Authenik8 scaffolds Express + Prisma projects with JWT authentication, database setup (PostgreSQL or SQLite), and scalable architecture out of the box.",
5
5
  "bin": {
6
6
  "create-authenik8-app": "dist/bin/index.js"
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "authenik8-app",
3
+ "version": "1.0.6",
4
+ "description": "Authenik8 generated Express auth app",
5
+ "main": "dist/server.js",
6
+ "type": "commonjs",
7
+ "scripts": {
8
+ "dev": "ts-node-dev --respawn --transpile-only src/server.ts",
9
+ "build": "tsc",
10
+ "start": "node dist/server.js",
11
+ "prisma:generate": "prisma generate",
12
+ "prisma:migrate": "prisma migrate dev"
13
+ },
14
+ "dependencies": {
15
+ "authenik8-core": "0.1.5",
16
+ "express": "^4.19.2"
17
+ },
18
+ "devDependencies": {
19
+ "@types/express": "^4.17.21",
20
+ "@types/node": "^20.0.0",
21
+ "ts-node-dev": "^2.0.0",
22
+ "typescript": "^5.0.0"
23
+ }
24
+ }
@@ -0,0 +1,15 @@
1
+ import { PrismaClient } from "@prisma/client";
2
+
3
+ const globalForPrisma = globalThis as unknown as {
4
+ prisma: PrismaClient | undefined;
5
+ };
6
+
7
+ export const prisma =
8
+ globalForPrisma.prisma ??
9
+ new PrismaClient({
10
+ log: ["error", "warn"],
11
+ });
12
+
13
+ if (process.env.NODE_ENV !== "production") {
14
+ globalForPrisma.prisma = prisma;
15
+ }
@@ -0,0 +1,78 @@
1
+ import express from "express";
2
+ import { createAuthenik8 } from "authenik8-core";
3
+ import { hashPassword, comparePassword } from "./utils/hash";
4
+ import {prisma} from "./prisma/client"
5
+
6
+ const app = express();
7
+ app.use(express.json());
8
+
9
+ async function start() {
10
+ const auth = await createAuthenik8({
11
+ jwtSecret: process.env.JWT_SECRET!,
12
+ refreshSecret: process.env.REFRESH_SECRET!,
13
+ });
14
+
15
+
16
+ app.post("/register", async (req, res) => {
17
+ const { email, password } = req.body;
18
+
19
+ const hashedPassword = await hashPassword(password);
20
+
21
+ const user = await prisma.user.create({
22
+ data: {
23
+ email,
24
+ password: hashedPassword,
25
+ },
26
+ });
27
+
28
+ res.json({ message: "User created", userId: user.id });
29
+ });
30
+
31
+
32
+ app.post("/login", async (req, res) => {
33
+ const { email, password } = req.body;
34
+
35
+ const user = await prisma.user.findUnique({
36
+ where: { email },
37
+ });
38
+
39
+ if (!user) {
40
+ return res.status(401).json({ error: "Invalid credentials" });
41
+ }
42
+
43
+ const isValid = await comparePassword(password, user.password);
44
+
45
+ if (!isValid) {
46
+ return res.status(401).json({ error: "Invalid credentials" });
47
+ }
48
+
49
+ const accessToken = auth.signToken({
50
+ id: user.id,
51
+ email: user.email,
52
+ });
53
+
54
+ const refreshToken = await auth.generateRefreshToken({
55
+ id: user.id,
56
+ email: user.email,
57
+ });
58
+
59
+ res.json({ accessToken, refreshToken });
60
+ });
61
+
62
+
63
+ app.post("/refresh", async (req, res) => {
64
+ const tokens = await auth.refreshToken(req.body.refreshToken);
65
+ res.json(tokens);
66
+ });
67
+
68
+ // ✅ PROTECTED
69
+ app.get("/protected", auth.requireAdmin, (req, res) => {
70
+ res.json({ message: "Protected route" });
71
+ });
72
+
73
+ app.listen(3000, () => {
74
+ console.log("🚀 Server running on http://localhost:3000");
75
+ });
76
+ }
77
+
78
+ start();
@@ -0,0 +1,12 @@
1
+ import argon2 from "argon2";
2
+
3
+ export const hashPassword = async (password: string): Promise<string> => {
4
+ return argon2.hash(password);
5
+ };
6
+
7
+ export const comparePassword = async (
8
+ password: string,
9
+ hash: string
10
+ ): Promise<boolean> => {
11
+ return argon2.verify(hash, password);
12
+ };
@@ -0,0 +1,16 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "commonjs",
5
+ "rootDir": "./src",
6
+ "outDir": "./dist",
7
+
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "skipLibCheck": true,
11
+
12
+ "forceConsistentCasingInFileNames": true
13
+ },
14
+ "include": ["src"],
15
+ "exclude": ["node_modules", "dist"]
16
+ }
@@ -0,0 +1,56 @@
1
+ import express from "express";
2
+ import { createAuthenik8 } from "authenik8-core";
3
+
4
+ const app = express();
5
+ app.use(express.json());
6
+
7
+ async function start() {
8
+ const auth = await createAuthenik8({
9
+ jwtSecret: process.env.JWT_SECRET!,
10
+ refreshSecret: process.env.REFRESH_SECRET!,
11
+ });
12
+
13
+ app.use(auth.helmet);
14
+ app.use(auth.rateLimit);
15
+
16
+
17
+ app.get("/public", (req, res) => {
18
+ res.json({ message: "Public route" });
19
+ });
20
+
21
+
22
+ app.get("/guest", async (req, res) => {
23
+ const token = await auth.guestToken({ role: "guest" });
24
+ res.json({ token });
25
+ });
26
+
27
+
28
+
29
+ app.get("/protected", async (req, res) => {
30
+ const token = req.headers.authorization?.split(" ")[1];
31
+
32
+ try {
33
+ const decoded = await auth.verifyToken(token);
34
+ res.json({ message: "Protected data", user: decoded });
35
+ } catch {
36
+ res.status(401).json({ error: "Unauthorized" });
37
+ }
38
+ });
39
+
40
+
41
+ app.post("/refresh", async (req, res) => {
42
+ const tokens = await auth.refreshToken(req.body.refreshToken);
43
+ res.json(tokens);
44
+ });
45
+
46
+ // 🛡️ Admin route
47
+ app.get("/admin", auth.requireAdmin, (req, res) => {
48
+ res.json({ message: "Admin only" });
49
+ });
50
+
51
+ app.listen(3000, () => {
52
+ console.log("🚀 Server running on http://localhost:3000");
53
+ });
54
+ }
55
+
56
+ start();
@@ -11,7 +11,7 @@ model User {
11
11
  id String @id @default(uuid())
12
12
  email String @unique
13
13
  password String
14
- role Role @default(USER)
14
+ role String @default("USER")
15
15
  verified Boolean @default(false)
16
16
 
17
17
  createdAt DateTime @default(now())
@@ -30,8 +30,3 @@ model Session {
30
30
 
31
31
  createdAt DateTime @default(now())
32
32
  }
33
-
34
- enum Role {
35
- USER
36
- ADMIN
37
- }
package/LICENSE DELETED
@@ -1,22 +0,0 @@
1
-
2
- MIT License
3
-
4
- Copyright (c) 2026 TheSBD
5
-
6
- Permission is hereby granted, free of charge, to any person obtaining a copy
7
- of this software and associated documentation files (the "Software"), to deal
8
- in the Software without restriction, including without limitation the rights
9
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
- copies of the Software, and to permit persons to whom the Software is
11
- furnished to do so, subject to the following conditions:
12
-
13
- The above copyright notice and this permission notice shall be included in all
14
- copies or substantial portions of the Software.
15
-
16
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
- SOFTWARE.
@@ -1,36 +0,0 @@
1
- import express from "express";
2
- import { createAuthenik8 } from "authenik8-core";
3
-
4
- const app = express();
5
- app.use(express.json());
6
-
7
- async function start() {
8
- const auth = await createAuthenik8({
9
- jwtSecret: process.env.JWT_SECRET!,
10
- refreshSecret: process.env.REFRESH_SECRET!,
11
- });
12
-
13
- app.post("/login", async (req, res) => {
14
- const user = { id: "123", email: "test@test.com" };
15
-
16
- const accessToken = auth.signToken(user);
17
- const refreshToken = await auth.generateRefreshToken(user);
18
-
19
- res.json({ accessToken, refreshToken });
20
- });
21
-
22
- app.post("/refresh", async (req, res) => {
23
- const tokens = await auth.refreshToken(req.body.refreshToken);
24
- res.json(tokens);
25
- });
26
-
27
- app.get("/protected", auth.requireAdmin, (req, res) => {
28
- res.json({ message: "Protected route" });
29
- });
30
-
31
- app.listen(3000, () => {
32
- console.log("🚀 Server running on http://localhost:3000");
33
- });
34
- }
35
-
36
- start();