@meridianjs/auth 0.1.3 → 0.1.4
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/dist/index.d.mts +3 -4
- package/dist/index.d.ts +3 -4
- package/dist/index.js +48 -23
- package/dist/index.mjs +48 -23
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -28,6 +28,7 @@ interface JwtPayload {
|
|
|
28
28
|
workspaceId: string | null;
|
|
29
29
|
roles: string[];
|
|
30
30
|
permissions: string[];
|
|
31
|
+
jti?: string;
|
|
31
32
|
iat?: number;
|
|
32
33
|
exp?: number;
|
|
33
34
|
}
|
|
@@ -49,11 +50,9 @@ declare class AuthModuleService extends AuthModuleService_base {
|
|
|
49
50
|
/**
|
|
50
51
|
* Express middleware that validates a Bearer JWT on every request.
|
|
51
52
|
*
|
|
52
|
-
* On success, populates req.user = { id, workspaceId, roles } and calls next().
|
|
53
|
+
* On success, populates req.user = { id, workspaceId, roles, permissions, jti } and calls next().
|
|
54
|
+
* Also validates the session against the DB (stateful revocation support).
|
|
53
55
|
* On failure, responds 401 Unauthorized.
|
|
54
|
-
*
|
|
55
|
-
* Reads jwtSecret from req.scope (the request-scoped DI container that is
|
|
56
|
-
* attached by the framework before any middleware runs).
|
|
57
56
|
*/
|
|
58
57
|
declare function authenticateJWT(req: any, res: Response, next: NextFunction): void;
|
|
59
58
|
|
package/dist/index.d.ts
CHANGED
|
@@ -28,6 +28,7 @@ interface JwtPayload {
|
|
|
28
28
|
workspaceId: string | null;
|
|
29
29
|
roles: string[];
|
|
30
30
|
permissions: string[];
|
|
31
|
+
jti?: string;
|
|
31
32
|
iat?: number;
|
|
32
33
|
exp?: number;
|
|
33
34
|
}
|
|
@@ -49,11 +50,9 @@ declare class AuthModuleService extends AuthModuleService_base {
|
|
|
49
50
|
/**
|
|
50
51
|
* Express middleware that validates a Bearer JWT on every request.
|
|
51
52
|
*
|
|
52
|
-
* On success, populates req.user = { id, workspaceId, roles } and calls next().
|
|
53
|
+
* On success, populates req.user = { id, workspaceId, roles, permissions, jti } and calls next().
|
|
54
|
+
* Also validates the session against the DB (stateful revocation support).
|
|
53
55
|
* On failure, responds 401 Unauthorized.
|
|
54
|
-
*
|
|
55
|
-
* Reads jwtSecret from req.scope (the request-scoped DI container that is
|
|
56
|
-
* attached by the framework before any middleware runs).
|
|
57
56
|
*/
|
|
58
57
|
declare function authenticateJWT(req: any, res: Response, next: NextFunction): void;
|
|
59
58
|
|
package/dist/index.js
CHANGED
|
@@ -45,8 +45,10 @@ var import_framework_utils2 = require("@meridianjs/framework-utils");
|
|
|
45
45
|
var import_framework_utils = require("@meridianjs/framework-utils");
|
|
46
46
|
var import_bcrypt = __toESM(require("bcrypt"));
|
|
47
47
|
var import_jsonwebtoken = __toESM(require("jsonwebtoken"));
|
|
48
|
+
var import_crypto = require("crypto");
|
|
48
49
|
var BCRYPT_ROUNDS = 12;
|
|
49
50
|
var JWT_EXPIRES_IN = "7d";
|
|
51
|
+
var JWT_EXPIRES_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
50
52
|
var AuthModuleService = class extends (0, import_framework_utils.MeridianService)({}) {
|
|
51
53
|
container;
|
|
52
54
|
constructor(container) {
|
|
@@ -76,7 +78,9 @@ var AuthModuleService = class extends (0, import_framework_utils.MeridianService
|
|
|
76
78
|
is_active: true
|
|
77
79
|
});
|
|
78
80
|
const permissions = await this.resolvePermissions(user.app_role_id);
|
|
79
|
-
const token = this.signToken(user.id, null, [user.role], permissions, config.projectConfig.jwtSecret);
|
|
81
|
+
const { token, jti, expiresAt } = this.signToken(user.id, null, [user.role], permissions, config.projectConfig.jwtSecret);
|
|
82
|
+
await userService.createSession(jti, user.id, expiresAt).catch(() => {
|
|
83
|
+
});
|
|
80
84
|
return {
|
|
81
85
|
user: {
|
|
82
86
|
id: user.id,
|
|
@@ -105,7 +109,9 @@ var AuthModuleService = class extends (0, import_framework_utils.MeridianService
|
|
|
105
109
|
await userService.recordLogin(user.id).catch(() => {
|
|
106
110
|
});
|
|
107
111
|
const permissions = await this.resolvePermissions(user.app_role_id);
|
|
108
|
-
const token = this.signToken(user.id, null, [user.role ?? "member"], permissions, config.projectConfig.jwtSecret);
|
|
112
|
+
const { token, jti, expiresAt } = this.signToken(user.id, null, [user.role ?? "member"], permissions, config.projectConfig.jwtSecret);
|
|
113
|
+
await userService.createSession(jti, user.id, expiresAt).catch(() => {
|
|
114
|
+
});
|
|
109
115
|
return {
|
|
110
116
|
user: {
|
|
111
117
|
id: user.id,
|
|
@@ -131,9 +137,12 @@ var AuthModuleService = class extends (0, import_framework_utils.MeridianService
|
|
|
131
137
|
}
|
|
132
138
|
}
|
|
133
139
|
signToken(userId, workspaceId, roles, permissions, secret) {
|
|
134
|
-
|
|
140
|
+
const jti = (0, import_crypto.randomUUID)();
|
|
141
|
+
const expiresAt = new Date(Date.now() + JWT_EXPIRES_MS);
|
|
142
|
+
const token = import_jsonwebtoken.default.sign({ sub: userId, workspaceId, roles, permissions, jti }, secret, {
|
|
135
143
|
expiresIn: JWT_EXPIRES_IN
|
|
136
144
|
});
|
|
145
|
+
return { token, jti, expiresAt };
|
|
137
146
|
}
|
|
138
147
|
};
|
|
139
148
|
|
|
@@ -146,26 +155,42 @@ function authenticateJWT(req, res, next) {
|
|
|
146
155
|
res.status(401).json({ error: { message: "Unauthorized \u2014 Bearer token required" } });
|
|
147
156
|
return;
|
|
148
157
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
158
|
+
;
|
|
159
|
+
(async () => {
|
|
160
|
+
let config;
|
|
161
|
+
try {
|
|
162
|
+
const scope = req.scope;
|
|
163
|
+
config = scope.resolve("config");
|
|
164
|
+
} catch {
|
|
165
|
+
res.status(500).json({ error: { message: "Server misconfiguration" } });
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
try {
|
|
169
|
+
const payload = import_jsonwebtoken2.default.verify(token, config.projectConfig.jwtSecret);
|
|
170
|
+
if (payload.jti) {
|
|
171
|
+
try {
|
|
172
|
+
const scope = req.scope;
|
|
173
|
+
const userService = scope.resolve("userModuleService");
|
|
174
|
+
const valid = await userService.isSessionValid(payload.jti);
|
|
175
|
+
if (!valid) {
|
|
176
|
+
res.status(401).json({ error: { message: "Session revoked or expired" } });
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
} catch {
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
req.user = {
|
|
183
|
+
id: payload.sub,
|
|
184
|
+
workspaceId: payload.workspaceId ?? null,
|
|
185
|
+
roles: Array.isArray(payload.roles) ? payload.roles : [],
|
|
186
|
+
permissions: Array.isArray(payload.permissions) ? payload.permissions : [],
|
|
187
|
+
jti: payload.jti ?? null
|
|
188
|
+
};
|
|
189
|
+
next();
|
|
190
|
+
} catch {
|
|
191
|
+
res.status(401).json({ error: { message: "Invalid or expired token" } });
|
|
192
|
+
}
|
|
193
|
+
})();
|
|
169
194
|
}
|
|
170
195
|
|
|
171
196
|
// src/guards.ts
|
package/dist/index.mjs
CHANGED
|
@@ -5,8 +5,10 @@ import { Module } from "@meridianjs/framework-utils";
|
|
|
5
5
|
import { MeridianService } from "@meridianjs/framework-utils";
|
|
6
6
|
import bcrypt from "bcrypt";
|
|
7
7
|
import jwt from "jsonwebtoken";
|
|
8
|
+
import { randomUUID } from "crypto";
|
|
8
9
|
var BCRYPT_ROUNDS = 12;
|
|
9
10
|
var JWT_EXPIRES_IN = "7d";
|
|
11
|
+
var JWT_EXPIRES_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
10
12
|
var AuthModuleService = class extends MeridianService({}) {
|
|
11
13
|
container;
|
|
12
14
|
constructor(container) {
|
|
@@ -36,7 +38,9 @@ var AuthModuleService = class extends MeridianService({}) {
|
|
|
36
38
|
is_active: true
|
|
37
39
|
});
|
|
38
40
|
const permissions = await this.resolvePermissions(user.app_role_id);
|
|
39
|
-
const token = this.signToken(user.id, null, [user.role], permissions, config.projectConfig.jwtSecret);
|
|
41
|
+
const { token, jti, expiresAt } = this.signToken(user.id, null, [user.role], permissions, config.projectConfig.jwtSecret);
|
|
42
|
+
await userService.createSession(jti, user.id, expiresAt).catch(() => {
|
|
43
|
+
});
|
|
40
44
|
return {
|
|
41
45
|
user: {
|
|
42
46
|
id: user.id,
|
|
@@ -65,7 +69,9 @@ var AuthModuleService = class extends MeridianService({}) {
|
|
|
65
69
|
await userService.recordLogin(user.id).catch(() => {
|
|
66
70
|
});
|
|
67
71
|
const permissions = await this.resolvePermissions(user.app_role_id);
|
|
68
|
-
const token = this.signToken(user.id, null, [user.role ?? "member"], permissions, config.projectConfig.jwtSecret);
|
|
72
|
+
const { token, jti, expiresAt } = this.signToken(user.id, null, [user.role ?? "member"], permissions, config.projectConfig.jwtSecret);
|
|
73
|
+
await userService.createSession(jti, user.id, expiresAt).catch(() => {
|
|
74
|
+
});
|
|
69
75
|
return {
|
|
70
76
|
user: {
|
|
71
77
|
id: user.id,
|
|
@@ -91,9 +97,12 @@ var AuthModuleService = class extends MeridianService({}) {
|
|
|
91
97
|
}
|
|
92
98
|
}
|
|
93
99
|
signToken(userId, workspaceId, roles, permissions, secret) {
|
|
94
|
-
|
|
100
|
+
const jti = randomUUID();
|
|
101
|
+
const expiresAt = new Date(Date.now() + JWT_EXPIRES_MS);
|
|
102
|
+
const token = jwt.sign({ sub: userId, workspaceId, roles, permissions, jti }, secret, {
|
|
95
103
|
expiresIn: JWT_EXPIRES_IN
|
|
96
104
|
});
|
|
105
|
+
return { token, jti, expiresAt };
|
|
97
106
|
}
|
|
98
107
|
};
|
|
99
108
|
|
|
@@ -106,26 +115,42 @@ function authenticateJWT(req, res, next) {
|
|
|
106
115
|
res.status(401).json({ error: { message: "Unauthorized \u2014 Bearer token required" } });
|
|
107
116
|
return;
|
|
108
117
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
118
|
+
;
|
|
119
|
+
(async () => {
|
|
120
|
+
let config;
|
|
121
|
+
try {
|
|
122
|
+
const scope = req.scope;
|
|
123
|
+
config = scope.resolve("config");
|
|
124
|
+
} catch {
|
|
125
|
+
res.status(500).json({ error: { message: "Server misconfiguration" } });
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
try {
|
|
129
|
+
const payload = jwt2.verify(token, config.projectConfig.jwtSecret);
|
|
130
|
+
if (payload.jti) {
|
|
131
|
+
try {
|
|
132
|
+
const scope = req.scope;
|
|
133
|
+
const userService = scope.resolve("userModuleService");
|
|
134
|
+
const valid = await userService.isSessionValid(payload.jti);
|
|
135
|
+
if (!valid) {
|
|
136
|
+
res.status(401).json({ error: { message: "Session revoked or expired" } });
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
} catch {
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
req.user = {
|
|
143
|
+
id: payload.sub,
|
|
144
|
+
workspaceId: payload.workspaceId ?? null,
|
|
145
|
+
roles: Array.isArray(payload.roles) ? payload.roles : [],
|
|
146
|
+
permissions: Array.isArray(payload.permissions) ? payload.permissions : [],
|
|
147
|
+
jti: payload.jti ?? null
|
|
148
|
+
};
|
|
149
|
+
next();
|
|
150
|
+
} catch {
|
|
151
|
+
res.status(401).json({ error: { message: "Invalid or expired token" } });
|
|
152
|
+
}
|
|
153
|
+
})();
|
|
129
154
|
}
|
|
130
155
|
|
|
131
156
|
// src/guards.ts
|