create-authenik8-app 2.0.1 → 2.0.2
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 +203 -10
- package/dist/bin/index.js +221 -36
- package/dist/bin/index.js.map +1 -1
- package/package.json +2 -2
- package/templates/express-auth/package.json +4 -1
- package/templates/express-auth/src/.env +9 -0
- package/templates/express-auth/src/app.ts +14 -0
- package/templates/express-auth/src/controllers/auth.controller.ts +43 -0
- package/templates/express-auth/src/routes/auth.routes.ts +13 -0
- package/templates/express-auth/src/routes/protected.routes.ts +11 -0
- package/templates/express-auth/src/server.ts +23 -64
- package/templates/express-auth/src/services/auth.services.ts +28 -0
- package/templates/express-auth+/ecosystem.config.ts +15 -0
- package/templates/express-auth+/package.json +27 -0
- package/templates/express-auth+/src/.env +9 -0
- package/templates/express-auth+/src/auth/auth.ts +37 -0
- package/templates/express-auth+/src/auth/oauth.routes.ts +43 -0
- package/templates/express-auth+/src/auth/password.route.ts +43 -0
- package/templates/express-auth+/src/auth/protected.routes.ts +11 -0
- package/templates/express-auth+/src/prisma/client.ts +15 -0
- package/templates/express-auth+/src/server.ts +38 -0
- package/templates/express-auth+/src/utils/hash.ts +12 -0
- package/templates/express-auth+/tsconfig.json +16 -0
- package/templates/express-base/app.ts +15 -0
- package/templates/express-base/controllers/base.controller.ts +32 -0
- package/templates/express-base/ecosystem.config.ts +15 -0
- package/templates/express-base/package.json +4 -1
- package/templates/express-base/routes/base.routes.ts +16 -0
- package/templates/express-base/src/server.ts +21 -41
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import express from "express";
|
|
2
|
+
import { createAuthRoutes } from "./routes/auth.routes";
|
|
3
|
+
import { createProtectedRoutes } from "./routes/protected.routes";
|
|
4
|
+
|
|
5
|
+
export const createApp = (auth: any) => {
|
|
6
|
+
const app = express();
|
|
7
|
+
|
|
8
|
+
app.use(express.json());
|
|
9
|
+
|
|
10
|
+
app.use("/auth", createAuthRoutes(auth));
|
|
11
|
+
app.use("/", createProtectedRoutes(auth));
|
|
12
|
+
|
|
13
|
+
return app;
|
|
14
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Request, Response } from "express";
|
|
2
|
+
import { AuthService } from "../services/auth.services";
|
|
3
|
+
|
|
4
|
+
export const createAuthController = (auth: any) => ({
|
|
5
|
+
async register(req: Request, res: Response) {
|
|
6
|
+
try {
|
|
7
|
+
const { email, password } = req.body;
|
|
8
|
+
|
|
9
|
+
const user = await AuthService.register(email, password);
|
|
10
|
+
|
|
11
|
+
res.json({ message: "User created", userId: user.id });
|
|
12
|
+
} catch (err) {
|
|
13
|
+
res.status(400).json({ error: (err as Error).message });
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
async login(req: Request, res: Response) {
|
|
18
|
+
try {
|
|
19
|
+
const { email, password } = req.body;
|
|
20
|
+
|
|
21
|
+
const user = await AuthService.login(email, password);
|
|
22
|
+
|
|
23
|
+
const accessToken = auth.signToken({
|
|
24
|
+
userId: user.id,
|
|
25
|
+
email: user.email,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const refreshToken = await auth.generateRefreshToken({
|
|
29
|
+
userId: user.id,
|
|
30
|
+
email: user.email,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
res.json({ accessToken, refreshToken });
|
|
34
|
+
} catch (err) {
|
|
35
|
+
res.status(401).json({ error: (err as Error).message });
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
async refresh(req: Request, res: Response) {
|
|
40
|
+
const tokens = await auth.refreshToken(req.body.refreshToken);
|
|
41
|
+
res.json(tokens);
|
|
42
|
+
},
|
|
43
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Router } from "express";
|
|
2
|
+
import { createAuthController } from "../controllers/auth.controller";
|
|
3
|
+
|
|
4
|
+
export const createAuthRoutes = (auth: any) => {
|
|
5
|
+
const router = Router();
|
|
6
|
+
const controller = createAuthController(auth);
|
|
7
|
+
|
|
8
|
+
router.post("/register", controller.register);
|
|
9
|
+
router.post("/login", controller.login);
|
|
10
|
+
router.post("/refresh", controller.refresh);
|
|
11
|
+
|
|
12
|
+
return router;
|
|
13
|
+
};
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import dotenv from "dotenv";
|
|
2
2
|
import { createAuthenik8 } from "authenik8-core";
|
|
3
|
-
import {
|
|
4
|
-
import {prisma} from "./prisma/client"
|
|
3
|
+
import { createApp } from "./app";
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
app.use(express.json());
|
|
5
|
+
dotenv.config();
|
|
8
6
|
|
|
9
7
|
async function start() {
|
|
10
8
|
const auth = await createAuthenik8({
|
|
@@ -12,67 +10,28 @@ async function start() {
|
|
|
12
10
|
refreshSecret: process.env.REFRESH_SECRET!,
|
|
13
11
|
});
|
|
14
12
|
|
|
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
|
-
});
|
|
13
|
+
const app = createApp(auth);
|
|
72
14
|
|
|
73
15
|
app.listen(3000, () => {
|
|
74
|
-
console.log("
|
|
16
|
+
console.log(" Server running on http://localhost:3000");
|
|
75
17
|
});
|
|
76
18
|
}
|
|
77
|
-
|
|
19
|
+
process.on("uncaughtException", (err) => {
|
|
20
|
+
console.error(" Uncaught Exception:", err);
|
|
21
|
+
process.exit(1);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
process.on("unhandledRejection", (err) => {
|
|
25
|
+
console.error(" Unhandled Rejection:", err);
|
|
26
|
+
process.exit(1);
|
|
27
|
+
|
|
28
|
+
});
|
|
29
|
+
setInterval(() => {
|
|
30
|
+
const used = process.memoryUsage().heapUsed / 1024 / 1024;
|
|
31
|
+
|
|
32
|
+
if (used > 300) {
|
|
33
|
+
console.error(`Memory exceeded: ${used.toFixed(2)} MB`);
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
}, 10000);
|
|
78
37
|
start();
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { prisma } from "../prisma/client";
|
|
2
|
+
import { hashPassword, comparePassword } from "../utils/hash";
|
|
3
|
+
|
|
4
|
+
export const AuthService = {
|
|
5
|
+
async register(email: string, password: string) {
|
|
6
|
+
const hashedPassword = await hashPassword(password);
|
|
7
|
+
|
|
8
|
+
const user = await prisma.user.create({
|
|
9
|
+
data: { email, password: hashedPassword },
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
return user;
|
|
13
|
+
},
|
|
14
|
+
|
|
15
|
+
async login(email: string, password: string) {
|
|
16
|
+
const user = await prisma.user.findUnique({
|
|
17
|
+
where: { email },
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
if (!user) throw new Error("Invalid credentials");
|
|
21
|
+
|
|
22
|
+
const isValid = await comparePassword(password, user.password);
|
|
23
|
+
|
|
24
|
+
if (!isValid) throw new Error("Invalid credentials");
|
|
25
|
+
|
|
26
|
+
return user;
|
|
27
|
+
},
|
|
28
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
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
|
+
"pm2:start": "pm2 start ecosystem.config.js",
|
|
11
|
+
"pm2:stop": "pm2 stop authenik8-app",
|
|
12
|
+
"pm2:logs": "pm2 logs",
|
|
13
|
+
"start": "node dist/server.js",
|
|
14
|
+
"prisma:generate": "prisma generate",
|
|
15
|
+
"prisma:migrate": "prisma migrate dev"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"authenik8-core": "^1.0.3",
|
|
19
|
+
"express": "^4.19.2"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@types/express": "^4.17.21",
|
|
23
|
+
"@types/node": "^20.0.0",
|
|
24
|
+
"ts-node-dev": "^2.0.0",
|
|
25
|
+
"typescript": "^5.0.0"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { createAuthenik8 } from "authenik8-core";
|
|
2
|
+
import dotenv from "dotenv";
|
|
3
|
+
|
|
4
|
+
dotenv.config();
|
|
5
|
+
|
|
6
|
+
let authInstance: any;
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
export async function initAuth() {
|
|
11
|
+
authInstance= await createAuthenik8({
|
|
12
|
+
jwtSecret: process.env.JWT_SECRET!,
|
|
13
|
+
refreshSecret: process.env.REFRESH_SECRET!,
|
|
14
|
+
|
|
15
|
+
oauth: {
|
|
16
|
+
google: {
|
|
17
|
+
clientId: process.env.GOOGLE_CLIENT_ID!,
|
|
18
|
+
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
|
|
19
|
+
redirectUri: "http://localhost:3000/auth/google/callback",
|
|
20
|
+
},
|
|
21
|
+
github: {
|
|
22
|
+
clientId: process.env.GITHUB_CLIENT_ID!,
|
|
23
|
+
clientSecret: process.env.GITHUB_CLIENT_SECRET!,
|
|
24
|
+
redirectUri: "http://localhost:3000/auth/github/callback",
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
}
|
|
30
|
+
export function getAuth() {
|
|
31
|
+
if (!authInstance) {
|
|
32
|
+
throw new Error("Auth not initialized. Call initAuth() first.");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return authInstance;
|
|
36
|
+
}
|
|
37
|
+
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import express from "express";
|
|
2
|
+
import { auth } from "./auth";
|
|
3
|
+
|
|
4
|
+
const router = express.Router();
|
|
5
|
+
|
|
6
|
+
// GOOGLE
|
|
7
|
+
router.get("/google", (req, res) => {
|
|
8
|
+
auth.oauth?.google?.redirect(req, res);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
router.get("/google/callback", async (req, res) => {
|
|
12
|
+
const result = await auth.oauth?.google?.handleCallback(req);
|
|
13
|
+
|
|
14
|
+
res.json({
|
|
15
|
+
provider: "google",
|
|
16
|
+
...result,
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
// GITHUB
|
|
21
|
+
router.get("/github", (req, res) => {
|
|
22
|
+
auth.oauth?.github?.redirect(req, res);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
router.get("/github/callback", async (req, res) => {
|
|
26
|
+
const result = await auth.oauth?.github?.handleCallback(req);
|
|
27
|
+
|
|
28
|
+
res.json({
|
|
29
|
+
provider: "github",
|
|
30
|
+
...result,
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
router.get("/google/link", (req, res) => {
|
|
36
|
+
auth.oauth?.google?.redirect(req, res, "link");
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
router.get("/github/link", (req, res) => {
|
|
40
|
+
auth.oauth?.github?.redirect(req, res, "link");
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
export default router;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { auth } from "./auth";
|
|
2
|
+
import { prisma } from "../prisma/client";
|
|
3
|
+
import { hashPassword, comparePassword } from "../utils/hash";
|
|
4
|
+
import express from "express";
|
|
5
|
+
|
|
6
|
+
const router = express.Router();
|
|
7
|
+
|
|
8
|
+
router.post("/register", async (req, res) => {
|
|
9
|
+
const { email, password } = req.body;
|
|
10
|
+
|
|
11
|
+
const user = await prisma.user.create({
|
|
12
|
+
data: {
|
|
13
|
+
email,
|
|
14
|
+
password: await hashPassword(password),
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
res.json({ message: "User created", userId: user.id });
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
router.post("/login", async (req, res) => {
|
|
22
|
+
const { email, password } = req.body;
|
|
23
|
+
|
|
24
|
+
const user = await prisma.user.findUnique({ where: { email } });
|
|
25
|
+
|
|
26
|
+
if (!user || !(await comparePassword(password, user.password))) {
|
|
27
|
+
return res.status(401).json({ error: "Invalid credentials" });
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const accessToken = auth.signToken({
|
|
31
|
+
userId: user.id,
|
|
32
|
+
email: user.email,
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const refreshToken = await auth.generateRefreshToken({
|
|
36
|
+
userId: user.id,
|
|
37
|
+
email: user.email,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
res.json({ accessToken, refreshToken });
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
export default router;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import express from "express";
|
|
2
|
+
import { getAuth } from "./auth";
|
|
3
|
+
|
|
4
|
+
const router = express.Router();
|
|
5
|
+
const auth = getAuth();
|
|
6
|
+
|
|
7
|
+
router.get("/protected", auth.requireAdmin, (req, res) => {
|
|
8
|
+
res.json({ message: "Protected route" });
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
export default router;
|
|
@@ -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,38 @@
|
|
|
1
|
+
import express from "express";
|
|
2
|
+
import passwordRoutes from "./auth/password.route";
|
|
3
|
+
import oauthRoutes from "./auth/oauth.routes";
|
|
4
|
+
import protectedRoutes from "./auth/protected.routes";
|
|
5
|
+
import { initAuth } from "./auth";
|
|
6
|
+
const app = express();
|
|
7
|
+
app.use(express.json());
|
|
8
|
+
|
|
9
|
+
app.use("/auth", passwordRoutes);
|
|
10
|
+
app.use("/auth", oauthRoutes);
|
|
11
|
+
app.use("/", protectedRoutes);
|
|
12
|
+
|
|
13
|
+
async function start(){
|
|
14
|
+
await initAuth();
|
|
15
|
+
|
|
16
|
+
app.listen(3000, () => {
|
|
17
|
+
console.log("Auth system running on http://localhost:3000");
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
start();
|
|
22
|
+
process.on("uncaughtException", (err) => {
|
|
23
|
+
console.error(" Uncaught Exception:", err);
|
|
24
|
+
process.exit(1);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
process.on("unhandledRejection", (err) => {
|
|
28
|
+
console.error(" Unhandled Rejection:", err);
|
|
29
|
+
process.exit(1);
|
|
30
|
+
});
|
|
31
|
+
setInterval(() => {
|
|
32
|
+
const used = process.memoryUsage().heapUsed / 1024 / 1024;
|
|
33
|
+
|
|
34
|
+
if (used > 300) {
|
|
35
|
+
console.error(` Memory exceeded: ${used.toFixed(2)} MB`);
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
}, 10000);
|
|
@@ -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,15 @@
|
|
|
1
|
+
import express from "express";
|
|
2
|
+
import { createBaseRoutes } from "./routes/base.routes";
|
|
3
|
+
|
|
4
|
+
export const createApp = (auth: any) => {
|
|
5
|
+
const app = express();
|
|
6
|
+
|
|
7
|
+
app.use(express.json());
|
|
8
|
+
|
|
9
|
+
app.use(auth.helmet);
|
|
10
|
+
app.use(auth.rateLimit);
|
|
11
|
+
|
|
12
|
+
app.use("/", createBaseRoutes(auth));
|
|
13
|
+
|
|
14
|
+
return app;
|
|
15
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Request, Response } from "express";
|
|
2
|
+
|
|
3
|
+
export const createBaseController = (auth: any) => ({
|
|
4
|
+
publicRoute(req: Request, res: Response) {
|
|
5
|
+
res.json({ message: "Public route" });
|
|
6
|
+
},
|
|
7
|
+
|
|
8
|
+
async guest(req: Request, res: Response) {
|
|
9
|
+
const token = await auth.guestToken({ role: "guest" });
|
|
10
|
+
res.json({ token });
|
|
11
|
+
},
|
|
12
|
+
|
|
13
|
+
async protected(req: Request, res: Response) {
|
|
14
|
+
const token = req.headers.authorization?.split(" ")[1];
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
const decoded = await auth.verifyToken(token);
|
|
18
|
+
res.json({ message: "Protected data", user: decoded });
|
|
19
|
+
} catch {
|
|
20
|
+
res.status(401).json({ error: "Unauthorized" });
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
async refresh(req: Request, res: Response) {
|
|
25
|
+
const tokens = await auth.refreshToken(req.body.refreshToken);
|
|
26
|
+
res.json(tokens);
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
admin(req: Request, res: Response) {
|
|
30
|
+
res.json({ message: "Admin only" });
|
|
31
|
+
},
|
|
32
|
+
});
|
|
@@ -3,11 +3,14 @@
|
|
|
3
3
|
"version": "1.0.5",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"dev": "ts-node-dev --respawn --transpile-only ./src/server.ts",
|
|
6
|
+
"pm2:start": "pm2 start ecosystem.config.js",
|
|
7
|
+
"pm2:stop": "pm2 stop authenik8-app",
|
|
8
|
+
"pm2:logs": "pm2 logs",
|
|
6
9
|
"build": "tsc",
|
|
7
10
|
"start": "node dist/server.js"
|
|
8
11
|
},
|
|
9
12
|
"dependencies": {
|
|
10
|
-
"authenik8-core": "^0.
|
|
13
|
+
"authenik8-core": "^1.0.3",
|
|
11
14
|
"dotenv": "^16.0.0",
|
|
12
15
|
"express": "^4.18.2"
|
|
13
16
|
},
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Router } from "express";
|
|
2
|
+
import { createBaseController } from "../controllers/base.controller";
|
|
3
|
+
|
|
4
|
+
export const createBaseRoutes = (auth: any) => {
|
|
5
|
+
const router = Router();
|
|
6
|
+
const controller = createBaseController(auth);
|
|
7
|
+
|
|
8
|
+
router.get("/public", controller.publicRoute);
|
|
9
|
+
router.get("/guest", controller.guest);
|
|
10
|
+
router.get("/protected", controller.protected);
|
|
11
|
+
router.post("/refresh", controller.refresh);
|
|
12
|
+
|
|
13
|
+
router.get("/admin", auth.requireAdmin, controller.admin);
|
|
14
|
+
|
|
15
|
+
return router;
|
|
16
|
+
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import dotenv from "dotenv";
|
|
2
2
|
import { createAuthenik8 } from "authenik8-core";
|
|
3
|
+
import { createApp } from "../app";
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
app.use(express.json());
|
|
5
|
+
dotenv.config();
|
|
6
6
|
|
|
7
7
|
async function start() {
|
|
8
8
|
const auth = await createAuthenik8({
|
|
@@ -10,47 +10,27 @@ async function start() {
|
|
|
10
10
|
refreshSecret: process.env.REFRESH_SECRET!,
|
|
11
11
|
});
|
|
12
12
|
|
|
13
|
-
app
|
|
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
|
-
});
|
|
13
|
+
const app = createApp(auth);
|
|
50
14
|
|
|
51
15
|
app.listen(3000, () => {
|
|
52
16
|
console.log("🚀 Server running on http://localhost:3000");
|
|
53
17
|
});
|
|
54
18
|
}
|
|
55
|
-
|
|
19
|
+
process.on("uncaughtException", (err) => {
|
|
20
|
+
console.error(" Uncaught Exception:", err);
|
|
21
|
+
process.exit(1);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
process.on("unhandledRejection", (err) => {
|
|
25
|
+
console.error(" Unhandled Rejection:", err);
|
|
26
|
+
process.exit(1);
|
|
27
|
+
});
|
|
28
|
+
setInterval(() => {
|
|
29
|
+
const used = process.memoryUsage().heapUsed / 1024 / 1024;
|
|
30
|
+
|
|
31
|
+
if (used > 300) {
|
|
32
|
+
console.error(`Memory exceeded: ${used.toFixed(2)} MB`);
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
}, 10000);
|
|
56
36
|
start();
|