@flink-app/jwt-auth-plugin 0.12.1-alpha.4 → 0.12.1-alpha.41

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.
@@ -1,14 +1,57 @@
1
- import { FlinkAuthPlugin, FlinkAuthUser } from "@flink-app/flink";
1
+ import { FlinkAuthPlugin, FlinkAuthUser, FlinkRequest } from "@flink-app/flink";
2
2
  import jwtSimple from "jwt-simple";
3
+ /**
4
+ * Custom token extraction callback.
5
+ *
6
+ * Return values:
7
+ * - `string`: Token found, use this token
8
+ * - `null`: No token found, authentication should fail
9
+ * - `undefined`: Skip custom extraction, use default Bearer token extraction
10
+ */
11
+ export type TokenExtractor = (req: FlinkRequest) => string | null | undefined;
12
+ /**
13
+ * Custom permission validation callback.
14
+ *
15
+ * Called after getUser to validate if the user has required permissions.
16
+ * Useful for dynamic permissions stored in database.
17
+ *
18
+ * @param user - The authenticated user object returned from getUser
19
+ * @param routePermissions - Array of permissions required by the route
20
+ * @returns true if user has required permissions, false otherwise
21
+ */
22
+ export type PermissionChecker = (user: FlinkAuthUser, routePermissions: string[]) => Promise<boolean> | boolean;
3
23
  export interface JwtAuthPluginOptions {
4
24
  secret: string;
5
25
  algo?: jwtSimple.TAlgorithm;
6
- getUser: (tokenData: any) => Promise<FlinkAuthUser>;
26
+ getUser: (tokenData: any) => Promise<FlinkAuthUser | null | undefined>;
7
27
  passwordPolicy?: RegExp;
8
28
  tokenTTL?: number;
9
29
  rolePermissions: {
10
30
  [role: string]: string[];
11
31
  };
32
+ /**
33
+ * Optional custom token extraction callback.
34
+ *
35
+ * Allows conditional token extraction based on request properties (path, method, headers, etc.).
36
+ * Return `undefined` to fall back to default Bearer token extraction.
37
+ */
38
+ tokenExtractor?: TokenExtractor;
39
+ /**
40
+ * Optional custom permission checker for dynamic permissions.
41
+ *
42
+ * When provided, replaces static rolePermissions checking.
43
+ * Called after getUser with the full user object.
44
+ *
45
+ * Example:
46
+ * ```typescript
47
+ * checkPermissions: async (user, routePermissions) => {
48
+ * return routePermissions.every(perm =>
49
+ * user.permissions?.includes(perm)
50
+ * );
51
+ * }
52
+ * ```
53
+ */
54
+ checkPermissions?: PermissionChecker;
12
55
  }
13
56
  export interface JwtAuthPlugin extends FlinkAuthPlugin {
14
57
  /**
@@ -38,4 +81,5 @@ export interface JwtAuthPlugin extends FlinkAuthPlugin {
38
81
  /**
39
82
  * Configures and creates authentication plugin.
40
83
  */
41
- export declare function jwtAuthPlugin({ secret, getUser, rolePermissions, algo, passwordPolicy, tokenTTL, }: JwtAuthPluginOptions): JwtAuthPlugin;
84
+ export declare function jwtAuthPlugin({ secret, getUser, rolePermissions, algo, passwordPolicy, tokenTTL, //Defaults to hundred year
85
+ tokenExtractor, checkPermissions, }: JwtAuthPluginOptions): JwtAuthPlugin;
@@ -65,7 +65,8 @@ var defaultPasswordPolicy = /^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$/;
65
65
  */
66
66
  function jwtAuthPlugin(_a) {
67
67
  var _this = this;
68
- var secret = _a.secret, getUser = _a.getUser, rolePermissions = _a.rolePermissions, _b = _a.algo, algo = _b === void 0 ? "HS256" : _b, _c = _a.passwordPolicy, passwordPolicy = _c === void 0 ? defaultPasswordPolicy : _c, _d = _a.tokenTTL, tokenTTL = _d === void 0 ? 1000 * 60 * 60 * 24 * 365 * 100 : _d;
68
+ var secret = _a.secret, getUser = _a.getUser, rolePermissions = _a.rolePermissions, _b = _a.algo, algo = _b === void 0 ? "HS256" : _b, _c = _a.passwordPolicy, passwordPolicy = _c === void 0 ? defaultPasswordPolicy : _c, _d = _a.tokenTTL, tokenTTL = _d === void 0 ? 1000 * 60 * 60 * 24 * 365 * 100 : _d, //Defaults to hundred year
69
+ tokenExtractor = _a.tokenExtractor, checkPermissions = _a.checkPermissions;
69
70
  return {
70
71
  authenticateRequest: function (req, permissions) { return __awaiter(_this, void 0, void 0, function () {
71
72
  return __generator(this, function (_a) {
@@ -73,41 +74,50 @@ function jwtAuthPlugin(_a) {
73
74
  algo: algo,
74
75
  secret: secret,
75
76
  getUser: getUser,
77
+ tokenExtractor: tokenExtractor,
78
+ checkPermissions: checkPermissions,
76
79
  })];
77
80
  });
78
81
  }); },
79
- createToken: function (payload, roles) {
80
- return createToken(__assign(__assign({}, payload), { roles: roles }), { algo: algo, secret: secret, tokenTTL: tokenTTL });
81
- },
82
- createPasswordHashAndSalt: function (password) {
83
- return createPasswordHashAndSalt(password, passwordPolicy);
84
- },
82
+ createToken: function (payload, roles) { return createToken(__assign(__assign({}, payload), { roles: roles }), { algo: algo, secret: secret, tokenTTL: tokenTTL }); },
83
+ createPasswordHashAndSalt: function (password) { return createPasswordHashAndSalt(password, passwordPolicy); },
85
84
  validatePassword: validatePassword,
86
85
  };
87
86
  }
88
87
  exports.jwtAuthPlugin = jwtAuthPlugin;
89
88
  function authenticateRequest(req_1, routePermissions_1, rolePermissions_1, _a) {
90
89
  return __awaiter(this, arguments, void 0, function (req, routePermissions, rolePermissions, _b) {
91
- var token, decodedToken, permissionsArr, validPerms, user;
92
- var secret = _b.secret, algo = _b.algo, getUser = _b.getUser;
90
+ var token, decodedToken, permissionsArr, validPerms, user, hasPermission;
91
+ var secret = _b.secret, algo = _b.algo, getUser = _b.getUser, tokenExtractor = _b.tokenExtractor, checkPermissions = _b.checkPermissions;
93
92
  return __generator(this, function (_c) {
94
93
  switch (_c.label) {
95
94
  case 0:
96
- token = getTokenFromReq(req);
97
- if (!token) return [3 /*break*/, 2];
95
+ if (tokenExtractor) {
96
+ token = tokenExtractor(req);
97
+ // If tokenExtractor returns undefined, fall back to default
98
+ if (token === undefined) {
99
+ token = getTokenFromReq(req);
100
+ }
101
+ // If it returns null, token stays null (no default fallback)
102
+ // If it returns string, token is the string
103
+ }
104
+ else {
105
+ // No custom extractor, use default
106
+ token = getTokenFromReq(req);
107
+ }
108
+ if (!token) return [3 /*break*/, 4];
98
109
  decodedToken = void 0;
99
110
  try {
100
111
  decodedToken = jwt_simple_1.default.decode(token, secret, false, algo);
101
112
  }
102
113
  catch (err) {
103
- flink_1.log.debug("Failed to decode token: ".concat(err));
114
+ flink_1.log.debug("[JWT AUTH PLUGIN] Failed to decode token: ".concat(err));
104
115
  decodedToken = null;
105
116
  }
106
- if (!decodedToken) return [3 /*break*/, 2];
107
- permissionsArr = Array.isArray(routePermissions)
108
- ? routePermissions
109
- : [routePermissions];
110
- if (permissionsArr && permissionsArr.length > 0) {
117
+ if (!decodedToken) return [3 /*break*/, 4];
118
+ permissionsArr = Array.isArray(routePermissions) ? routePermissions : [routePermissions];
119
+ // Static permission check - only if custom checker NOT provided
120
+ if (!checkPermissions && permissionsArr && permissionsArr.length > 0) {
111
121
  validPerms = (0, PermissionValidator_1.hasValidPermissions)(decodedToken.roles || [], rolePermissions, permissionsArr);
112
122
  if (!validPerms) {
113
123
  return [2 /*return*/, false];
@@ -116,9 +126,23 @@ function authenticateRequest(req_1, routePermissions_1, rolePermissions_1, _a) {
116
126
  return [4 /*yield*/, getUser(decodedToken)];
117
127
  case 1:
118
128
  user = _c.sent();
129
+ if (!user) {
130
+ flink_1.log.debug("[JWT AUTH PLUGIN] User not returned from getUser callback");
131
+ return [2 /*return*/, false];
132
+ }
133
+ if (!(checkPermissions && permissionsArr && permissionsArr.length > 0)) return [3 /*break*/, 3];
134
+ return [4 /*yield*/, checkPermissions(user, permissionsArr)];
135
+ case 2:
136
+ hasPermission = _c.sent();
137
+ if (!hasPermission) {
138
+ flink_1.log.debug("[JWT AUTH PLUGIN] Custom permission check failed");
139
+ return [2 /*return*/, false];
140
+ }
141
+ _c.label = 3;
142
+ case 3:
119
143
  req.user = user;
120
144
  return [2 /*return*/, true];
121
- case 2: return [2 /*return*/, false];
145
+ case 4: return [2 /*return*/, false];
122
146
  }
123
147
  });
124
148
  });
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@flink-app/jwt-auth-plugin",
3
- "version": "0.12.1-alpha.4",
3
+ "version": "0.12.1-alpha.41",
4
4
  "description": "Flink plugin for JWT auth",
5
5
  "scripts": {
6
6
  "test": "node --preserve-symlinks -r ts-node/register -- node_modules/jasmine/bin/jasmine --config=./spec/support/jasmine.json",
7
7
  "test:watch": "nodemon --ext ts --exec 'jasmine-ts --config=./spec/support/jasmine.json'",
8
- "prepublish": "tsc --project tsconfig.dist.json",
8
+ "prepare": "tsc --project tsconfig.dist.json",
9
9
  "watch": "tsc-watch --project tsconfig.dist.json"
10
10
  },
11
11
  "author": "joel@frost.se",
@@ -20,7 +20,7 @@
20
20
  "jwt-simple": "^0.5.6"
21
21
  },
22
22
  "devDependencies": {
23
- "@flink-app/flink": "^0.12.1-alpha.4",
23
+ "@flink-app/flink": "^0.12.1-alpha.40",
24
24
  "@types/bcrypt": "^5.0.0",
25
25
  "@types/jasmine": "^3.7.1",
26
26
  "@types/node": "22.13.10",
@@ -31,5 +31,5 @@
31
31
  "tsc-watch": "^4.2.9",
32
32
  "typescript": "5.4.5"
33
33
  },
34
- "gitHead": "8f06a4ab98e7179322d36546756d4305fd196f5a"
34
+ "gitHead": "76b54ee31f2c10c8c8f18af91facf5322b14ebf5"
35
35
  }