authenik8-core 0.1.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/.env +2 -0
- package/README.md +93 -0
- package/authenik8-core-0.1.0.tgz +0 -0
- package/dist/auth/guestModeService.d.ts +3 -0
- package/dist/auth/guestModeService.d.ts.map +1 -0
- package/dist/auth/guestModeService.js +24 -0
- package/dist/auth/guestModeService.js.map +1 -0
- package/dist/auth/jwtAuth.d.ts +28 -0
- package/dist/auth/jwtAuth.d.ts.map +1 -0
- package/dist/auth/jwtAuth.js +67 -0
- package/dist/auth/jwtAuth.js.map +1 -0
- package/dist/auth/refreshService.d.ts +41 -0
- package/dist/auth/refreshService.d.ts.map +1 -0
- package/dist/auth/refreshService.js +77 -0
- package/dist/auth/refreshService.js.map +1 -0
- package/dist/creatAuthenik8.d.ts +2 -0
- package/dist/creatAuthenik8.d.ts.map +1 -0
- package/dist/creatAuthenik8.js +3 -0
- package/dist/creatAuthenik8.js.map +1 -0
- package/dist/createAuthenik8.d.ts +4 -0
- package/dist/createAuthenik8.d.ts.map +1 -0
- package/dist/createAuthenik8.js +58 -0
- package/dist/createAuthenik8.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/adminService.d.ts +4 -0
- package/dist/middleware/adminService.d.ts.map +1 -0
- package/dist/middleware/adminService.js +40 -0
- package/dist/middleware/adminService.js.map +1 -0
- package/dist/redis/redisService.d.ts +26 -0
- package/dist/redis/redisService.d.ts.map +1 -0
- package/dist/redis/redisService.js +104 -0
- package/dist/redis/redisService.js.map +1 -0
- package/dist/security/ipService.d.ts +36 -0
- package/dist/security/ipService.d.ts.map +1 -0
- package/dist/security/ipService.js +160 -0
- package/dist/security/ipService.js.map +1 -0
- package/dist/security/limiter.d.ts +5 -0
- package/dist/security/limiter.d.ts.map +1 -0
- package/dist/security/limiter.js +93 -0
- package/dist/security/limiter.js.map +1 -0
- package/dist/storage/RedisTokenStore.d.ts +21 -0
- package/dist/storage/RedisTokenStore.d.ts.map +1 -0
- package/dist/storage/RedisTokenStore.js +86 -0
- package/dist/storage/RedisTokenStore.js.map +1 -0
- package/dist/storage/userStorage.d.ts +7 -0
- package/dist/storage/userStorage.d.ts.map +1 -0
- package/dist/storage/userStorage.js +18 -0
- package/dist/storage/userStorage.js.map +1 -0
- package/dist/tests/full.intergration.test.d.ts +2 -0
- package/dist/tests/full.intergration.test.d.ts.map +1 -0
- package/dist/tests/full.intergration.test.js +79 -0
- package/dist/tests/full.intergration.test.js.map +1 -0
- package/dist/tests/testApp.d.ts +7 -0
- package/dist/tests/testApp.d.ts.map +1 -0
- package/dist/tests/testApp.js +53 -0
- package/dist/tests/testApp.js.map +1 -0
- package/dist/types/admin.d.ts +6 -0
- package/dist/types/admin.d.ts.map +1 -0
- package/dist/types/admin.js +3 -0
- package/dist/types/admin.js.map +1 -0
- package/dist/types/config.d.ts +9 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +3 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/public.d.ts +17 -0
- package/dist/types/public.d.ts.map +1 -0
- package/dist/types/public.js +3 -0
- package/dist/types/public.js.map +1 -0
- package/dist/types/storage.d.ts +14 -0
- package/dist/types/storage.d.ts.map +1 -0
- package/dist/types/storage.js +3 -0
- package/dist/types/storage.js.map +1 -0
- package/dump.rdb +0 -0
- package/jest.config.js +11 -0
- package/package.json +56 -0
- package/src/1 +22 -0
- package/src/auth/guestModeService.ts +31 -0
- package/src/auth/jwtAuth.ts +99 -0
- package/src/auth/refreshService.ts +134 -0
- package/src/creatAuthenik8.ts +0 -0
- package/src/createAuthenik8.ts +66 -0
- package/src/index.ts +1 -0
- package/src/middleware/adminService.ts +50 -0
- package/src/redis/redisService.ts +137 -0
- package/src/security/ipService.ts +180 -0
- package/src/security/limiter.ts +116 -0
- package/src/storage/RedisTokenStore.ts +99 -0
- package/src/storage/userStorage.ts +16 -0
- package/src/tests/full.intergration.test.ts +100 -0
- package/src/tests/testApp.ts +56 -0
- package/src/types/admin.ts +7 -0
- package/src/types/config.ts +11 -0
- package/src/types/public.ts +22 -0
- package/src/types/storage.ts +15 -0
- package/tsconfig.json +51 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
// tests/full.integration.test.ts
|
|
2
|
+
import { createTestApp } from "./testApp";
|
|
3
|
+
|
|
4
|
+
describe("Authenik8 Full Integration", () => {
|
|
5
|
+
let request: any;
|
|
6
|
+
let auth: any;
|
|
7
|
+
|
|
8
|
+
let accessToken: string;
|
|
9
|
+
let refreshToken: string;
|
|
10
|
+
|
|
11
|
+
beforeAll(async () => {
|
|
12
|
+
const setup = await createTestApp();
|
|
13
|
+
request = setup.request;
|
|
14
|
+
auth = setup.auth;
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
afterAll(async () => {
|
|
18
|
+
if (auth.redis) {
|
|
19
|
+
await auth.redis.flushdb();
|
|
20
|
+
await auth.redis.quit();
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// 🔐 LOGIN
|
|
25
|
+
test("should login and receive tokens", async () => {
|
|
26
|
+
const res = await request.post("/login");
|
|
27
|
+
|
|
28
|
+
expect(res.status).toBe(200);
|
|
29
|
+
expect(res.body).toHaveProperty("accessToken");
|
|
30
|
+
expect(res.body).toHaveProperty("refreshToken");
|
|
31
|
+
|
|
32
|
+
accessToken = res.body.accessToken;
|
|
33
|
+
refreshToken = res.body.refreshToken;
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// 🔒 PROTECTED ROUTE
|
|
37
|
+
test("should access protected route with valid token", async () => {
|
|
38
|
+
const res = await request
|
|
39
|
+
.get("/protected")
|
|
40
|
+
.set("Authorization", `Bearer ${accessToken}`);
|
|
41
|
+
|
|
42
|
+
expect(res.status).toBe(200);
|
|
43
|
+
expect(res.body).toHaveProperty("data", "secure data");
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// 🚫 NO TOKEN
|
|
47
|
+
test("should reject request without token", async () => {
|
|
48
|
+
const res = await request.get("/protected");
|
|
49
|
+
|
|
50
|
+
expect(res.status).toBe(401);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// 🔄 REFRESH TOKEN
|
|
54
|
+
test("should refresh access token", async () => {
|
|
55
|
+
const res = await request
|
|
56
|
+
.post("/refresh")
|
|
57
|
+
.send({ refreshToken });
|
|
58
|
+
|
|
59
|
+
expect(res.status).toBe(200);
|
|
60
|
+
expect(res.body).toHaveProperty("accessToken");
|
|
61
|
+
expect(res.body).toHaveProperty("refreshToken");
|
|
62
|
+
|
|
63
|
+
// update tokens
|
|
64
|
+
accessToken = res.body.accessToken;
|
|
65
|
+
refreshToken = res.body.refreshToken;
|
|
66
|
+
|
|
67
|
+
if (res.body.refreshToken) {
|
|
68
|
+
refreshToken = res.body.refreshToken;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// 🔥 ROTATION (IMPORTANT)
|
|
74
|
+
test("should NOT allow reuse of old refresh token", async () => {
|
|
75
|
+
const originalToken = refreshToken;
|
|
76
|
+
|
|
77
|
+
// first use → rotates token
|
|
78
|
+
const firstRes = await request
|
|
79
|
+
.post("/refresh")
|
|
80
|
+
.send({ refreshToken: originalToken });
|
|
81
|
+
|
|
82
|
+
expect(firstRes.status).toBe(200);
|
|
83
|
+
|
|
84
|
+
const newToken = firstRes.body.refreshToken;
|
|
85
|
+
|
|
86
|
+
// second use with OLD token → should fail
|
|
87
|
+
const res = await request
|
|
88
|
+
.post("/refresh")
|
|
89
|
+
.send({ refreshToken: originalToken });
|
|
90
|
+
|
|
91
|
+
expect(res.status).toBe(401);
|
|
92
|
+
|
|
93
|
+
// sanity check: new token should work
|
|
94
|
+
const validRes = await request
|
|
95
|
+
.post("/refresh")
|
|
96
|
+
.send({ refreshToken: newToken });
|
|
97
|
+
|
|
98
|
+
expect(validRes.status).toBe(200);
|
|
99
|
+
});
|
|
100
|
+
});
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// tests/testApp.ts
|
|
2
|
+
import express from "express";
|
|
3
|
+
import request from "supertest";
|
|
4
|
+
import { createAuthenik8 } from "../createAuthenik8";
|
|
5
|
+
|
|
6
|
+
export const createTestApp = async () => {
|
|
7
|
+
const auth = await createAuthenik8({
|
|
8
|
+
jwtSecret: "test-secret",
|
|
9
|
+
refreshSecret: "refresh-secret",
|
|
10
|
+
jwtExpiry: "15m"
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
const app = express();
|
|
14
|
+
app.use(express.json());
|
|
15
|
+
|
|
16
|
+
// 🔐 Login (simulate user)
|
|
17
|
+
app.post("/login", async(req, res) => {
|
|
18
|
+
const user = { userId: "user_1", email:"test@test.com" };
|
|
19
|
+
|
|
20
|
+
const accessToken = auth.signToken(user);
|
|
21
|
+
const refreshToken = await auth.generateRefreshToken(user);
|
|
22
|
+
|
|
23
|
+
res.json({ accessToken, refreshToken });
|
|
24
|
+
console.log("Refresh Token",refreshToken)
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// 🔒 Protected route
|
|
28
|
+
app.get("/protected", (req, res) => {
|
|
29
|
+
const token = req.headers.authorization?.split(" ")[1];
|
|
30
|
+
|
|
31
|
+
if(!token){
|
|
32
|
+
return res.status(401).json({error:"Invalid token"})
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const decoded = auth.verifyToken(token);
|
|
36
|
+
|
|
37
|
+
if (!decoded) {
|
|
38
|
+
return res.status(401).json({ error: "Unauthorized" });
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
res.json({ data: "secure data", user: decoded });
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// 🔄 Refresh
|
|
45
|
+
app.post("/refresh", async (req, res) => {
|
|
46
|
+
try {
|
|
47
|
+
const result = await auth.refreshToken(req.body.refreshToken);
|
|
48
|
+
res.json(result);
|
|
49
|
+
} catch (err) {
|
|
50
|
+
res.status(401).json({ error: "Invalid refresh token" });
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
return { app, auth, request: request(app) };
|
|
56
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
|
|
2
|
+
export interface Authenik8Instance {
|
|
3
|
+
signToken: (payload: any) => string;
|
|
4
|
+
verifyToken: (token: string) => any;
|
|
5
|
+
guestToken: () => string;
|
|
6
|
+
|
|
7
|
+
refreshToken: (token: string) => Promise<any>;
|
|
8
|
+
generateRefreshToken: (payload: any) => Promise<string>;
|
|
9
|
+
|
|
10
|
+
rateLimit: any;
|
|
11
|
+
ipWhitelist: any;
|
|
12
|
+
helmet: any;
|
|
13
|
+
|
|
14
|
+
addIP: (ip: string) => Promise<void>;
|
|
15
|
+
removeIP: (ip: string) => Promise<void>;
|
|
16
|
+
listIPs: () => Promise<string[]>;
|
|
17
|
+
|
|
18
|
+
requireAdmin: any;
|
|
19
|
+
incognito: any;
|
|
20
|
+
|
|
21
|
+
redis?: any;
|
|
22
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface User{
|
|
2
|
+
id:string;
|
|
3
|
+
email:string;
|
|
4
|
+
password:string;
|
|
5
|
+
role?:string;
|
|
6
|
+
type?:string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface UserStore{
|
|
10
|
+
findByEmail(email:string):Promise<User | null>;
|
|
11
|
+
findById(id:string):Promise<User | null>;
|
|
12
|
+
create(user: Partial<User>):
|
|
13
|
+
Promise<User>;
|
|
14
|
+
update(id:string, data:Partial<User>):Promise<User>;
|
|
15
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
// Visit https://aka.ms/tsconfig to read more about this file
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
// File Layout
|
|
5
|
+
"rootDir": "./src",
|
|
6
|
+
"outDir": "./dist",
|
|
7
|
+
"strict": true,
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
|
|
10
|
+
"declaration": true,
|
|
11
|
+
"sourceMap": true,
|
|
12
|
+
|
|
13
|
+
"skipLibCheck": true,
|
|
14
|
+
"forceConsistentCasingInFileNames": true,
|
|
15
|
+
// Environment Settings
|
|
16
|
+
// See also https://aka.ms/tsconfig/module
|
|
17
|
+
"module": "CommonJS",
|
|
18
|
+
"target": "ES2019",
|
|
19
|
+
"types": [],
|
|
20
|
+
// For nodejs:
|
|
21
|
+
// "lib": ["esnext"],
|
|
22
|
+
"types": ["node","jest"],
|
|
23
|
+
// and npm install -D @types/node
|
|
24
|
+
|
|
25
|
+
// Other Outputs
|
|
26
|
+
"sourceMap": true,
|
|
27
|
+
"declaration": true,
|
|
28
|
+
"declarationMap": true,
|
|
29
|
+
|
|
30
|
+
// Stricter Typechecking Options
|
|
31
|
+
"noUncheckedIndexedAccess": true,
|
|
32
|
+
//"exactOptionalPropertyTypes": true,
|
|
33
|
+
|
|
34
|
+
// Style Options
|
|
35
|
+
// "noImplicitReturns": true,
|
|
36
|
+
// "noImplicitOverride": true,
|
|
37
|
+
// "noUnusedLocals": true,
|
|
38
|
+
// "noUnusedParameters": true,
|
|
39
|
+
// "noFallthroughCasesInSwitch": true,
|
|
40
|
+
// "noPropertyAccessFromIndexSignature": true,
|
|
41
|
+
|
|
42
|
+
// Recommended Options
|
|
43
|
+
"strict": true,
|
|
44
|
+
"jsx": "react-jsx",
|
|
45
|
+
//"verbatimModuleSyntax": true,
|
|
46
|
+
"isolatedModules": true,
|
|
47
|
+
"noUncheckedSideEffectImports": true,
|
|
48
|
+
"moduleDetection": "force",
|
|
49
|
+
"skipLibCheck": true,
|
|
50
|
+
}
|
|
51
|
+
}
|