@meridianjs/auth 0.1.1 → 0.1.3
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 +17 -1
- package/dist/index.d.ts +17 -1
- package/dist/index.js +31 -7
- package/dist/index.mjs +30 -7
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -27,6 +27,7 @@ interface JwtPayload {
|
|
|
27
27
|
sub: string;
|
|
28
28
|
workspaceId: string | null;
|
|
29
29
|
roles: string[];
|
|
30
|
+
permissions: string[];
|
|
30
31
|
iat?: number;
|
|
31
32
|
exp?: number;
|
|
32
33
|
}
|
|
@@ -40,6 +41,8 @@ declare class AuthModuleService extends AuthModuleService_base {
|
|
|
40
41
|
login(input: LoginInput): Promise<AuthResult>;
|
|
41
42
|
/** Verify a JWT and return its decoded payload. Throws if invalid or expired. */
|
|
42
43
|
verifyToken(token: string, secret: string): JwtPayload;
|
|
44
|
+
/** Resolve permissions for a given app_role_id — gracefully degrades if module not loaded. */
|
|
45
|
+
private resolvePermissions;
|
|
43
46
|
private signToken;
|
|
44
47
|
}
|
|
45
48
|
|
|
@@ -64,6 +67,19 @@ declare function authenticateJWT(req: any, res: Response, next: NextFunction): v
|
|
|
64
67
|
* { matcher: "/admin/settings", middlewares: [authenticateJWT, requireRoles("admin")] }
|
|
65
68
|
*/
|
|
66
69
|
declare function requireRoles(...roles: string[]): (req: any, res: Response, next: NextFunction) => void;
|
|
70
|
+
/**
|
|
71
|
+
* Permission guard — allows the request if `req.user.roles` includes "super-admin"
|
|
72
|
+
* (full bypass) or if `req.user.permissions` contains at least one of the listed
|
|
73
|
+
* permissions.
|
|
74
|
+
*
|
|
75
|
+
* Must be used after `authenticateJWT` so that `req.user` is populated.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* export const POST = async (req, res) => {
|
|
79
|
+
* requirePermission("project:create")(req, res, async () => { ... })
|
|
80
|
+
* }
|
|
81
|
+
*/
|
|
82
|
+
declare function requirePermission(...permissions: string[]): (req: any, res: Response, next: NextFunction) => void;
|
|
67
83
|
/**
|
|
68
84
|
* Workspace isolation guard — rejects requests where the `workspace_id` query
|
|
69
85
|
* param or body field does not match the authenticated user's workspace.
|
|
@@ -78,4 +94,4 @@ declare function requireWorkspace(req: any, res: Response, next: NextFunction):
|
|
|
78
94
|
declare const AUTH_MODULE = "authModuleService";
|
|
79
95
|
declare const _default: _meridianjs_types.ModuleDefinition;
|
|
80
96
|
|
|
81
|
-
export { AUTH_MODULE, AuthModuleService, type AuthResult, type JwtPayload, type LoginInput, type RegisterInput, authenticateJWT, _default as default, requireRoles, requireWorkspace };
|
|
97
|
+
export { AUTH_MODULE, AuthModuleService, type AuthResult, type JwtPayload, type LoginInput, type RegisterInput, authenticateJWT, _default as default, requirePermission, requireRoles, requireWorkspace };
|
package/dist/index.d.ts
CHANGED
|
@@ -27,6 +27,7 @@ interface JwtPayload {
|
|
|
27
27
|
sub: string;
|
|
28
28
|
workspaceId: string | null;
|
|
29
29
|
roles: string[];
|
|
30
|
+
permissions: string[];
|
|
30
31
|
iat?: number;
|
|
31
32
|
exp?: number;
|
|
32
33
|
}
|
|
@@ -40,6 +41,8 @@ declare class AuthModuleService extends AuthModuleService_base {
|
|
|
40
41
|
login(input: LoginInput): Promise<AuthResult>;
|
|
41
42
|
/** Verify a JWT and return its decoded payload. Throws if invalid or expired. */
|
|
42
43
|
verifyToken(token: string, secret: string): JwtPayload;
|
|
44
|
+
/** Resolve permissions for a given app_role_id — gracefully degrades if module not loaded. */
|
|
45
|
+
private resolvePermissions;
|
|
43
46
|
private signToken;
|
|
44
47
|
}
|
|
45
48
|
|
|
@@ -64,6 +67,19 @@ declare function authenticateJWT(req: any, res: Response, next: NextFunction): v
|
|
|
64
67
|
* { matcher: "/admin/settings", middlewares: [authenticateJWT, requireRoles("admin")] }
|
|
65
68
|
*/
|
|
66
69
|
declare function requireRoles(...roles: string[]): (req: any, res: Response, next: NextFunction) => void;
|
|
70
|
+
/**
|
|
71
|
+
* Permission guard — allows the request if `req.user.roles` includes "super-admin"
|
|
72
|
+
* (full bypass) or if `req.user.permissions` contains at least one of the listed
|
|
73
|
+
* permissions.
|
|
74
|
+
*
|
|
75
|
+
* Must be used after `authenticateJWT` so that `req.user` is populated.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* export const POST = async (req, res) => {
|
|
79
|
+
* requirePermission("project:create")(req, res, async () => { ... })
|
|
80
|
+
* }
|
|
81
|
+
*/
|
|
82
|
+
declare function requirePermission(...permissions: string[]): (req: any, res: Response, next: NextFunction) => void;
|
|
67
83
|
/**
|
|
68
84
|
* Workspace isolation guard — rejects requests where the `workspace_id` query
|
|
69
85
|
* param or body field does not match the authenticated user's workspace.
|
|
@@ -78,4 +94,4 @@ declare function requireWorkspace(req: any, res: Response, next: NextFunction):
|
|
|
78
94
|
declare const AUTH_MODULE = "authModuleService";
|
|
79
95
|
declare const _default: _meridianjs_types.ModuleDefinition;
|
|
80
96
|
|
|
81
|
-
export { AUTH_MODULE, AuthModuleService, type AuthResult, type JwtPayload, type LoginInput, type RegisterInput, authenticateJWT, _default as default, requireRoles, requireWorkspace };
|
|
97
|
+
export { AUTH_MODULE, AuthModuleService, type AuthResult, type JwtPayload, type LoginInput, type RegisterInput, authenticateJWT, _default as default, requirePermission, requireRoles, requireWorkspace };
|
package/dist/index.js
CHANGED
|
@@ -34,6 +34,7 @@ __export(index_exports, {
|
|
|
34
34
|
AuthModuleService: () => AuthModuleService,
|
|
35
35
|
authenticateJWT: () => authenticateJWT,
|
|
36
36
|
default: () => index_default,
|
|
37
|
+
requirePermission: () => requirePermission,
|
|
37
38
|
requireRoles: () => requireRoles,
|
|
38
39
|
requireWorkspace: () => requireWorkspace
|
|
39
40
|
});
|
|
@@ -74,7 +75,8 @@ var AuthModuleService = class extends (0, import_framework_utils.MeridianService
|
|
|
74
75
|
role,
|
|
75
76
|
is_active: true
|
|
76
77
|
});
|
|
77
|
-
const
|
|
78
|
+
const permissions = await this.resolvePermissions(user.app_role_id);
|
|
79
|
+
const token = this.signToken(user.id, null, [user.role], permissions, config.projectConfig.jwtSecret);
|
|
78
80
|
return {
|
|
79
81
|
user: {
|
|
80
82
|
id: user.id,
|
|
@@ -102,7 +104,8 @@ var AuthModuleService = class extends (0, import_framework_utils.MeridianService
|
|
|
102
104
|
}
|
|
103
105
|
await userService.recordLogin(user.id).catch(() => {
|
|
104
106
|
});
|
|
105
|
-
const
|
|
107
|
+
const permissions = await this.resolvePermissions(user.app_role_id);
|
|
108
|
+
const token = this.signToken(user.id, null, [user.role ?? "member"], permissions, config.projectConfig.jwtSecret);
|
|
106
109
|
return {
|
|
107
110
|
user: {
|
|
108
111
|
id: user.id,
|
|
@@ -117,8 +120,18 @@ var AuthModuleService = class extends (0, import_framework_utils.MeridianService
|
|
|
117
120
|
verifyToken(token, secret) {
|
|
118
121
|
return import_jsonwebtoken.default.verify(token, secret);
|
|
119
122
|
}
|
|
120
|
-
|
|
121
|
-
|
|
123
|
+
/** Resolve permissions for a given app_role_id — gracefully degrades if module not loaded. */
|
|
124
|
+
async resolvePermissions(appRoleId) {
|
|
125
|
+
if (!appRoleId) return [];
|
|
126
|
+
try {
|
|
127
|
+
const appRoleService = this.container.resolve("appRoleModuleService");
|
|
128
|
+
return await appRoleService.getPermissionsForRole(appRoleId);
|
|
129
|
+
} catch {
|
|
130
|
+
return [];
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
signToken(userId, workspaceId, roles, permissions, secret) {
|
|
134
|
+
return import_jsonwebtoken.default.sign({ sub: userId, workspaceId, roles, permissions }, secret, {
|
|
122
135
|
expiresIn: JWT_EXPIRES_IN
|
|
123
136
|
});
|
|
124
137
|
}
|
|
@@ -128,11 +141,11 @@ var AuthModuleService = class extends (0, import_framework_utils.MeridianService
|
|
|
128
141
|
var import_jsonwebtoken2 = __toESM(require("jsonwebtoken"));
|
|
129
142
|
function authenticateJWT(req, res, next) {
|
|
130
143
|
const authHeader = req.headers.authorization;
|
|
131
|
-
|
|
144
|
+
const token = authHeader?.startsWith("Bearer ") ? authHeader.substring(7) : req.query?.token;
|
|
145
|
+
if (!token) {
|
|
132
146
|
res.status(401).json({ error: { message: "Unauthorized \u2014 Bearer token required" } });
|
|
133
147
|
return;
|
|
134
148
|
}
|
|
135
|
-
const token = authHeader.substring(7);
|
|
136
149
|
let config;
|
|
137
150
|
try {
|
|
138
151
|
const scope = req.scope;
|
|
@@ -146,7 +159,8 @@ function authenticateJWT(req, res, next) {
|
|
|
146
159
|
req.user = {
|
|
147
160
|
id: payload.sub,
|
|
148
161
|
workspaceId: payload.workspaceId ?? null,
|
|
149
|
-
roles: Array.isArray(payload.roles) ? payload.roles : []
|
|
162
|
+
roles: Array.isArray(payload.roles) ? payload.roles : [],
|
|
163
|
+
permissions: Array.isArray(payload.permissions) ? payload.permissions : []
|
|
150
164
|
};
|
|
151
165
|
next();
|
|
152
166
|
} catch {
|
|
@@ -162,6 +176,15 @@ function requireRoles(...roles) {
|
|
|
162
176
|
res.status(403).json({ error: { message: "Forbidden" } });
|
|
163
177
|
};
|
|
164
178
|
}
|
|
179
|
+
function requirePermission(...permissions) {
|
|
180
|
+
return (req, res, next) => {
|
|
181
|
+
const userRoles = req.user?.roles ?? [];
|
|
182
|
+
if (userRoles.includes("super-admin")) return next();
|
|
183
|
+
const userPermissions = req.user?.permissions ?? [];
|
|
184
|
+
if (permissions.some((p) => userPermissions.includes(p))) return next();
|
|
185
|
+
res.status(403).json({ error: { message: "Forbidden \u2014 insufficient permissions" } });
|
|
186
|
+
};
|
|
187
|
+
}
|
|
165
188
|
function requireWorkspace(req, res, next) {
|
|
166
189
|
const workspaceId = req.query?.workspace_id ?? req.body?.workspace_id;
|
|
167
190
|
if (workspaceId && req.user?.workspaceId && req.user.workspaceId !== workspaceId) {
|
|
@@ -180,6 +203,7 @@ var index_default = (0, import_framework_utils2.Module)(AUTH_MODULE, {
|
|
|
180
203
|
AUTH_MODULE,
|
|
181
204
|
AuthModuleService,
|
|
182
205
|
authenticateJWT,
|
|
206
|
+
requirePermission,
|
|
183
207
|
requireRoles,
|
|
184
208
|
requireWorkspace
|
|
185
209
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -35,7 +35,8 @@ var AuthModuleService = class extends MeridianService({}) {
|
|
|
35
35
|
role,
|
|
36
36
|
is_active: true
|
|
37
37
|
});
|
|
38
|
-
const
|
|
38
|
+
const permissions = await this.resolvePermissions(user.app_role_id);
|
|
39
|
+
const token = this.signToken(user.id, null, [user.role], permissions, config.projectConfig.jwtSecret);
|
|
39
40
|
return {
|
|
40
41
|
user: {
|
|
41
42
|
id: user.id,
|
|
@@ -63,7 +64,8 @@ var AuthModuleService = class extends MeridianService({}) {
|
|
|
63
64
|
}
|
|
64
65
|
await userService.recordLogin(user.id).catch(() => {
|
|
65
66
|
});
|
|
66
|
-
const
|
|
67
|
+
const permissions = await this.resolvePermissions(user.app_role_id);
|
|
68
|
+
const token = this.signToken(user.id, null, [user.role ?? "member"], permissions, config.projectConfig.jwtSecret);
|
|
67
69
|
return {
|
|
68
70
|
user: {
|
|
69
71
|
id: user.id,
|
|
@@ -78,8 +80,18 @@ var AuthModuleService = class extends MeridianService({}) {
|
|
|
78
80
|
verifyToken(token, secret) {
|
|
79
81
|
return jwt.verify(token, secret);
|
|
80
82
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
+
/** Resolve permissions for a given app_role_id — gracefully degrades if module not loaded. */
|
|
84
|
+
async resolvePermissions(appRoleId) {
|
|
85
|
+
if (!appRoleId) return [];
|
|
86
|
+
try {
|
|
87
|
+
const appRoleService = this.container.resolve("appRoleModuleService");
|
|
88
|
+
return await appRoleService.getPermissionsForRole(appRoleId);
|
|
89
|
+
} catch {
|
|
90
|
+
return [];
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
signToken(userId, workspaceId, roles, permissions, secret) {
|
|
94
|
+
return jwt.sign({ sub: userId, workspaceId, roles, permissions }, secret, {
|
|
83
95
|
expiresIn: JWT_EXPIRES_IN
|
|
84
96
|
});
|
|
85
97
|
}
|
|
@@ -89,11 +101,11 @@ var AuthModuleService = class extends MeridianService({}) {
|
|
|
89
101
|
import jwt2 from "jsonwebtoken";
|
|
90
102
|
function authenticateJWT(req, res, next) {
|
|
91
103
|
const authHeader = req.headers.authorization;
|
|
92
|
-
|
|
104
|
+
const token = authHeader?.startsWith("Bearer ") ? authHeader.substring(7) : req.query?.token;
|
|
105
|
+
if (!token) {
|
|
93
106
|
res.status(401).json({ error: { message: "Unauthorized \u2014 Bearer token required" } });
|
|
94
107
|
return;
|
|
95
108
|
}
|
|
96
|
-
const token = authHeader.substring(7);
|
|
97
109
|
let config;
|
|
98
110
|
try {
|
|
99
111
|
const scope = req.scope;
|
|
@@ -107,7 +119,8 @@ function authenticateJWT(req, res, next) {
|
|
|
107
119
|
req.user = {
|
|
108
120
|
id: payload.sub,
|
|
109
121
|
workspaceId: payload.workspaceId ?? null,
|
|
110
|
-
roles: Array.isArray(payload.roles) ? payload.roles : []
|
|
122
|
+
roles: Array.isArray(payload.roles) ? payload.roles : [],
|
|
123
|
+
permissions: Array.isArray(payload.permissions) ? payload.permissions : []
|
|
111
124
|
};
|
|
112
125
|
next();
|
|
113
126
|
} catch {
|
|
@@ -123,6 +136,15 @@ function requireRoles(...roles) {
|
|
|
123
136
|
res.status(403).json({ error: { message: "Forbidden" } });
|
|
124
137
|
};
|
|
125
138
|
}
|
|
139
|
+
function requirePermission(...permissions) {
|
|
140
|
+
return (req, res, next) => {
|
|
141
|
+
const userRoles = req.user?.roles ?? [];
|
|
142
|
+
if (userRoles.includes("super-admin")) return next();
|
|
143
|
+
const userPermissions = req.user?.permissions ?? [];
|
|
144
|
+
if (permissions.some((p) => userPermissions.includes(p))) return next();
|
|
145
|
+
res.status(403).json({ error: { message: "Forbidden \u2014 insufficient permissions" } });
|
|
146
|
+
};
|
|
147
|
+
}
|
|
126
148
|
function requireWorkspace(req, res, next) {
|
|
127
149
|
const workspaceId = req.query?.workspace_id ?? req.body?.workspace_id;
|
|
128
150
|
if (workspaceId && req.user?.workspaceId && req.user.workspaceId !== workspaceId) {
|
|
@@ -141,6 +163,7 @@ export {
|
|
|
141
163
|
AuthModuleService,
|
|
142
164
|
authenticateJWT,
|
|
143
165
|
index_default as default,
|
|
166
|
+
requirePermission,
|
|
144
167
|
requireRoles,
|
|
145
168
|
requireWorkspace
|
|
146
169
|
};
|