@meridianjs/auth 0.1.2 → 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 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 token = this.signToken(user.id, null, [user.role], config.projectConfig.jwtSecret);
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 token = this.signToken(user.id, null, [user.role ?? "member"], config.projectConfig.jwtSecret);
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
- signToken(userId, workspaceId, roles, secret) {
121
- return import_jsonwebtoken.default.sign({ sub: userId, workspaceId, roles }, secret, {
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
  }
@@ -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 token = this.signToken(user.id, null, [user.role], config.projectConfig.jwtSecret);
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 token = this.signToken(user.id, null, [user.role ?? "member"], config.projectConfig.jwtSecret);
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
- signToken(userId, workspaceId, roles, secret) {
82
- return jwt.sign({ sub: userId, workspaceId, roles }, secret, {
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
  }
@@ -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
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meridianjs/auth",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Meridian auth module — JWT authentication and middleware",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",