@dwtechs/toker-express 0.2.0 → 0.3.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/README.md CHANGED
@@ -123,26 +123,38 @@ const refreshDuration = isNumber(REFRESH_TOKEN_DURATION, false) ? REFRESH_TOKEN_
123
123
  ```typescript
124
124
 
125
125
  /**
126
- * Refreshes the JWT tokens for a user.
126
+ * Express middleware to generate new access and refresh JWT tokens for a user.
127
127
  *
128
- * This function generates new access and refresh tokens for a consumer based on the provided
129
- * decoded access token from req.decodedAccessToken or user ID from req.body.rows[0].id. It validates the issuer (iss) and
130
- * creates new tokens if the validation is successful. The new tokens are then added to the
131
- * response locals object and optionally to req.body.rows[0] if rows is an array with at least one element.
128
+ * This middleware creates new access and refresh tokens based on:
129
+ * 1. The issuer (iss) from `req.decodedAccessToken.iss` if available, OR
130
+ * 2. The user ID from `res.locals.id` if no decoded token is present
132
131
  *
133
- * @param {Request} req - The request object containing req.decodedAccessToken or req.body.rows[0].id.
134
- * @param {Response} res - The response object where the new tokens will be added in res.locals.
135
- * @param {NextFunction} next - The next middleware function in the Express.js request-response cycle.
132
+ * The generated tokens are stored in:
133
+ * - `res.locals.accessToken` and `res.locals.refreshToken`
134
+ * - `req.body.rows[0].accessToken` and `req.body.rows[0].refreshToken` (if rows array exists)
136
135
  *
137
- * @returns {void} Calls the next middleware function with an error if the issuer is invalid,
138
- * otherwise proceeds to the next middleware function.
139
- *
140
- * @throws {InvalidIssuerError} If the issuer (iss) is not a string or number (HTTP 400)
141
- * @throws {InvalidSecretsError} If the secrets array is empty or invalid (HTTP 500)
142
- * @throws {InvalidDurationError} If the duration is not a positive number (HTTP 400)
143
- * @throws {InvalidBase64Secret} If the secret cannot be decoded from base64 (HTTP 500)
144
- * @throws {Object} Will call next() with error object containing:
145
- * - statusCode: 400 - When iss (issuer) is missing or invalid
136
+ * @param {Request} req - The Express request object. May contain:
137
+ * - `req.decodedAccessToken.iss`: User ID from decoded access token
138
+ * - `req.body.rows`: Optional array where tokens will be added to first element
139
+ * @param {Response} res - The Express response object. Should contain:
140
+ * - `res.locals.id`: User ID (used if decodedAccessToken is not available)
141
+ * Tokens will be added to `res.locals.accessToken` and `res.locals.refreshToken`
142
+ * @param {NextFunction} next - Express next middleware function
143
+ *
144
+ * @returns {void}
145
+ *
146
+ * @throws Will call next() with error object containing:
147
+ * - statusCode: 400 - When issuer (iss) is missing or invalid (not a number between 1-999999999)
148
+ * - statusCode: 500 - When token signing fails (invalid secrets, duration, or base64 secret)
149
+ *
150
+ * @example
151
+ * // After successful authentication, call refresh to generate tokens
152
+ * app.post('/login', authenticate, refresh, (req, res) => {
153
+ * res.json({
154
+ * accessToken: res.locals.accessToken,
155
+ * refreshToken: res.locals.refreshToken
156
+ * });
157
+ * });
146
158
  */
147
159
  function refresh(req: Request, res: Response, next: NextFunction): void {}
148
160
 
@@ -199,21 +211,25 @@ function decodeRefresh(req: Request, _res: Response, next: NextFunction): void {
199
211
 
200
212
  ### JWT Refresh
201
213
 
202
- This function will look for an ISS in the client request body :
214
+ This function will look for an ISS (user ID) from two possible sources:
203
215
 
204
216
  ```Javascript
205
- const iss = req.decodedAccessToken?.iss || (isArray(req.body.rows, null, 1) ? req.body.rows[0]?.id?.toString() : null);
217
+ let iss = req.decodedAccessToken?.iss;
218
+
219
+ if (!iss)
220
+ iss = res.locals.id ?? null;
206
221
  ```
207
222
 
208
- It will then send both new refresh and access tokens in the res.locals and req.body objects.
223
+ It will then send both new refresh and access tokens in the res.locals object and optionally in req.body.rows[0] if the rows array exists.
209
224
 
210
225
  ```Javascript
211
226
  res.locals.accessToken = accessToken;
212
227
  res.locals.refreshToken = refreshToken;
213
228
 
214
- if (isArray(req.body.rows)) {
215
- req.body.rows[0].accessToken = accessToken;
216
- req.body.rows[0].refreshToken = refreshToken;
229
+ const rbr = req.body?.rows;
230
+ if (isArray(rbr, ">=", 1) && isObject(rbr[0])) {
231
+ rbr[0].accessToken = accessToken;
232
+ rbr[0].refreshToken = refreshToken;
217
233
  }
218
234
  ```
219
235
 
@@ -26,7 +26,12 @@ https://github.com/DWTechs/Toker-express.js
26
26
 
27
27
  import type { Request, Response, NextFunction } from 'express';
28
28
 
29
- // Extend Express Request interface globally
29
+ export interface RowWithTokens {
30
+ accessToken?: string;
31
+ refreshToken?: string;
32
+ [key: string]: any;
33
+ }
34
+
30
35
  declare global {
31
36
  namespace Express {
32
37
  interface Request {
@@ -25,7 +25,7 @@ https://github.com/DWTechs/Toker-express.js
25
25
  */
26
26
 
27
27
  import { sign, parseBearer, verify } from '@dwtechs/toker';
28
- import { isString, isNumber, isArray, isValidNumber, isJWT } from '@dwtechs/checkard';
28
+ import { isString, isNumber, isValidNumber, isArray, isObject, isJWT } from '@dwtechs/checkard';
29
29
  import { log } from '@dwtechs/winstan';
30
30
 
31
31
  const { TOKEN_SECRET, ACCESS_TOKEN_DURATION, REFRESH_TOKEN_DURATION } = process.env;
@@ -40,12 +40,8 @@ const refreshDuration = isNumber(REFRESH_TOKEN_DURATION, false) ? Number(REFRESH
40
40
  function refresh(req, res, next) {
41
41
  var _a, _b, _c;
42
42
  let iss = (_a = req.decodedAccessToken) === null || _a === void 0 ? void 0 : _a.iss;
43
- const rbr = req.body.rows;
44
- let rbrIsArray = false;
45
- if (!iss) {
46
- rbrIsArray = isArray(rbr, null, 1);
47
- iss = rbrIsArray ? (_c = (_b = rbr[0]) === null || _b === void 0 ? void 0 : _b.id) === null || _c === void 0 ? void 0 : _c.toString() : null;
48
- }
43
+ if (!iss)
44
+ iss = (_b = res.locals.id) !== null && _b !== void 0 ? _b : null;
49
45
  if (!isValidNumber(iss, 1, 999999999, false))
50
46
  return next({ statusCode: 400, message: `${LOGS_PREFIX}Missing iss` });
51
47
  log.debug(`${LOGS_PREFIX}Create tokens for user ${iss}`);
@@ -61,7 +57,8 @@ function refresh(req, res, next) {
61
57
  log.debug(`refreshToken='${rt}', accessToken='${at}'`);
62
58
  res.locals.accessToken = at;
63
59
  res.locals.refreshToken = rt;
64
- if (rbrIsArray) {
60
+ const rbr = (_c = req.body) === null || _c === void 0 ? void 0 : _c.rows;
61
+ if (isArray(rbr, ">=", 1) && isObject(rbr[0])) {
65
62
  rbr[0].accessToken = at;
66
63
  rbr[0].refreshToken = rt;
67
64
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dwtechs/toker-express",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Open source JWT management library for Express.js to refresh and decode tokens safely.",
5
5
  "keywords": [
6
6
  "JWT",