@dwtechs/toker-express 0.5.2 → 0.6.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
@@ -2,7 +2,7 @@
2
2
  [![License: MIT](https://img.shields.io/npm/l/@dwtechs/toker-express.svg?color=brightgreen)](https://opensource.org/licenses/MIT)
3
3
  [![npm version](https://badge.fury.io/js/%40dwtechs%2Ftoker-express.svg)](https://www.npmjs.com/package/@dwtechs/toker-express)
4
4
  [![last version release date](https://img.shields.io/github/release-date/DWTechs/Toker-express.js)](https://www.npmjs.com/package/@dwtechs/toker-express)
5
- ![Jest:coverage](https://img.shields.io/badge/Jest:coverage-93%25-brightgreen.svg)
5
+ ![Jest:coverage](https://img.shields.io/badge/Jest:coverage-94%25-brightgreen.svg)
6
6
 
7
7
 
8
8
  - [Synopsis](#synopsis)
@@ -47,7 +47,7 @@ $ npm i @dwtechs/toker-express
47
47
  ```javascript
48
48
 
49
49
  // @ts-check
50
- import * as tk from "@dwtechs/toker-express";
50
+ import { parseBearer, createTokens, refreshTokens, decodeAccess, decodeRefresh, } from "@dwtechs/toker-express";
51
51
  import express from "express";
52
52
  const router = express.Router();
53
53
 
@@ -60,24 +60,24 @@ const add = [
60
60
  uEntity.normalize,
61
61
  uEntity.validate,
62
62
  login,
63
- tk.refresh,
63
+ createTokens,
64
64
  cEntity.add,
65
65
  ];
66
66
 
67
67
  const refresh = [
68
68
  cEntity.validate,
69
- tk.parseBearerToken,
70
- tk.decodeAccess,
71
- tk.decodeRefresh,
69
+ parseBearer,
70
+ decodeAccess,
71
+ decodeRefresh,
72
72
  checkToken,
73
- tk.refresh,
73
+ refreshTokens,
74
74
  cEntity.update,
75
75
  ];
76
76
 
77
77
  const del = [
78
78
  checkToken,
79
- tk.parseBearerToken,
80
- tk.decodeAccess,
79
+ parseBearer,
80
+ decodeAccess,
81
81
  cEntity.delete,
82
82
  ];
83
83
 
@@ -125,22 +125,49 @@ const refreshDuration = isNumber(REFRESH_TOKEN_DURATION, false) ? REFRESH_TOKEN_
125
125
  ```typescript
126
126
 
127
127
  /**
128
- * Express middleware to generate new access and refresh JWT tokens for a user.
128
+ * Express middleware to create new access and refresh JWT tokens for a user.
129
129
  *
130
- * This middleware creates new access and refresh tokens based on:
131
- * 1. The issuer (iss) from `res.locals.decodedAccessToken.iss` if available, OR
132
- * 2. The user ID from `res.locals.id` if no decoded token is present
130
+ * This middleware generates new access and refresh tokens using the user ID
131
+ * from `res.locals.user.id` and stores them in `req.body.rows[0]` for
132
+ * subsequent processing (e.g., database insertion).
133
+ * Note that this middleware assumes that `req.body.rows[0]` already exists
134
+ * with some user data like nickname and roles.
133
135
  *
134
- * The generated tokens are stored in:
135
- * - `res.locals.accessToken` and `res.locals.refreshToken`
136
- * - `req.body.rows[0].accessToken` and `req.body.rows[0].refreshToken` (if rows array exists)
136
+ * @param {Request} req - The Express request object. Should contain:
137
+ * - `req.body.rows`: Array where tokens will be added to the first element
138
+ * @param {Response} res - The Express response object. Should contain:
139
+ * - `res.locals.user.id`: User ID to use as issuer (iss) in the tokens
140
+ * @param {NextFunction} next - Express next middleware function
141
+ *
142
+ * @returns {void}
143
+ *
144
+ * @throws Will call next() with error object containing:
145
+ * - statusCode: 400 - When user ID (iss) is missing or invalid (not a number between 1-999999999)
146
+ * - statusCode: 500 - When token signing fails (invalid secrets, duration, or base64 secret)
147
+ *
148
+ * @example
149
+ * // After user creation/registration, call createTokens to generate tokens
150
+ * app.post('/login', validateUser, createTokens, saveConsumer, ...);
151
+ */
152
+ function createTokens(req: Request, res: Response, next: NextFunction): void {}
153
+
154
+ /**
155
+ * Express middleware to refresh and generate new access and refresh JWT tokens.
137
156
  *
138
- * @param {Request} req - The Express request object. May contain:
139
- * - `req.body.rows`: Optional array where tokens will be added to first element
157
+ * This middleware creates new access and refresh tokens using the user ID (iss)
158
+ * from a previously decoded access token stored by decodeAccess middleware
159
+ * in `res.locals.tokens.decodedAccess.iss`.
160
+ * The generated tokens are stored in `req.body.rows[0]` for subsequent processing.
161
+ * This is typically used in token refresh flows where an existing access token
162
+ * has been decoded and validated.
163
+ * Note that req.body.rows[0] must already exist at this stage because with consumer id
164
+ * because consumer id has already been found at this stage and will be used top update
165
+ * the consumer in the database.
166
+ *
167
+ * @param {Request} req - The Express request object. Should contain:
168
+ * - `req.body.rows`: Array where tokens will be added to the first element
140
169
  * @param {Response} res - The Express response object. Should contain:
141
- * - `res.locals.decodedAccessToken.iss`: User ID from decoded access token (checked first), OR
142
- * - `res.locals.id`: User ID (used if decodedAccessToken is not available)
143
- * Tokens will be added to `res.locals.accessToken` and `res.locals.refreshToken`
170
+ * - `res.locals.tokens.decodedAccess.iss`: User ID from the decoded access token
144
171
  * @param {NextFunction} next - Express next middleware function
145
172
  *
146
173
  * @returns {void}
@@ -150,142 +177,177 @@ const refreshDuration = isNumber(REFRESH_TOKEN_DURATION, false) ? REFRESH_TOKEN_
150
177
  * - statusCode: 500 - When token signing fails (invalid secrets, duration, or base64 secret)
151
178
  *
152
179
  * @example
153
- * // After successful authentication, call refresh to generate tokens
154
- * app.post('/login', authenticate, refresh, (req, res) => {
155
- * res.json({
156
- * accessToken: res.locals.accessToken,
157
- * refreshToken: res.locals.refreshToken
158
- * });
159
- * });
180
+ * // Token refresh flow with decoded access token
181
+ * app.post('/refresh', decodeAccess, refreshTokens, updateDatabase, ...);
160
182
  */
161
- function refresh(req: Request, res: Response, next: NextFunction): void {}
183
+ function refreshTokens(req: Request, res: Response, next: NextFunction): void {}
162
184
 
163
185
  /**
164
- * Express middleware function to parse the bearer token from the Authorization header.
186
+ * Express middleware to extract the JWT bearer token from the Authorization header.
165
187
  *
166
188
  * This middleware extracts the JWT token from the Authorization header (Bearer scheme)
167
- * and stores it in res.locals.accessToken for use by subsequent middleware.
168
- * It only processes requests that have `res.locals.isProtected` set to true.
189
+ * and stores it in `res.locals.tokens.access` for use by subsequent middleware (typically decodeAccess).
190
+ * It only processes requests that have `res.locals.route.isProtected` set to true.
191
+ * For non-protected routes, it simply passes control to the next middleware.
169
192
  *
170
- * @param {Request} req - The Express request object containing the Authorization header
193
+ * @param {Request} req - The Express request object. Should contain:
194
+ * - `req.headers.authorization`: Authorization header with Bearer token format
171
195
  * @param {Response} res - The Express response object. Should contain:
172
- * - `res.locals.isProtected`: Boolean flag to determine if route requires JWT protection
173
- * Parsed token will be added to `res.locals.accessToken`
196
+ * - `res.locals.route.isProtected`: Boolean flag to determine if route requires JWT protection
197
+ * Parsed token will be added to `res.locals.tokens.access`
174
198
  * @param {NextFunction} next - The next middleware function to be called
175
199
  *
176
- * @returns {void} Calls the next middleware function with an error object if parsing fails.
200
+ * @returns {void}
177
201
  *
178
- * @throws {MissingAuthorizationError} If the Authorization header is missing (HTTP 401)
179
- * @throws {InvalidBearerFormatError} If the Authorization header format is invalid (HTTP 401)
202
+ * @throws Will call next() with error when:
203
+ * - Authorization header is missing (HTTP 401)
204
+ * - Authorization header format is invalid or not Bearer scheme (HTTP 401)
180
205
  *
206
+ * @example
207
+ * // Use in protected route chain
208
+ * app.get('/profile', parseBearer, decodeAccess, ...);
181
209
  */
182
- function parseBearerToken(req: Request, res: Response, next: NextFunction): void {}
210
+ function parseBearer(req: Request, res: Response, next: NextFunction): void {}
183
211
 
184
212
  /**
185
- * Express middleware function to decode and verify an access token.
213
+ * Express middleware to decode and verify an access token.
214
+ *
215
+ * This middleware validates the JWT access token from `res.locals.tokens.access`,
216
+ * verifies its signature and structure, validates the issuer (iss) claim,
217
+ * and stores the decoded token in `res.locals.tokens.decodedAccess` for use by
218
+ * subsequent middleware. It only processes requests that have `res.locals.route.isProtected`
219
+ * set to true. For non-protected routes, it simply passes control to the next middleware.
186
220
  *
187
- * This middleware validates the JWT access token from res.locals.accessToken,
188
- * verifies its signature, and attaches the decoded token to res.locals.decodedAccessToken
189
- * for use by subsequent middleware. It only processes requests that have `res.locals.isProtected` set to true.
221
+ * Note: This middleware IGNORES token expiration (exp claim) by design, allowing
222
+ * expired access tokens to be decoded. This is useful for token refresh flows where
223
+ * you need to identify the user even after their access token has expired.
190
224
  *
191
- * @param {Request} req - The Express request object
225
+ * @param {Request} _req - The Express request object (unused)
192
226
  * @param {Response} res - The Express response object. Should contain:
193
- * - `res.locals.isProtected`: Boolean flag to determine if route requires JWT protection
194
- * - `res.locals.accessToken`: The JWT token to decode
195
- * Decoded token will be added to `res.locals.decodedAccessToken`
227
+ * - `res.locals.route.isProtected`: Boolean flag to determine if route requires JWT protection
228
+ * - `res.locals.tokens.access`: The JWT token to decode (from parseBearer middleware)
229
+ * Decoded token will be added to `res.locals.tokens.decodedAccess`
196
230
  * @param {NextFunction} next - The next middleware function to be called
197
231
  *
198
- * @returns {void} Calls the next middleware function with an error object if the token is invalid or iss is missing.
232
+ * @returns {void}
199
233
  *
200
- * @throws {InvalidTokenError} If the token is malformed or has invalid structure (HTTP 401)
201
- * @throws {ExpiredTokenError} If the token has expired (exp claim) (HTTP 401)
202
- * @throws {InactiveTokenError} If the token cannot be used yet (nbf claim) (HTTP 401)
203
- * @throws {InvalidSignatureError} If the token signature is invalid (HTTP 401)
204
- * @throws {InvalidSecretsError} If the secrets configuration is invalid (HTTP 500)
205
- * @throws {InvalidBase64Secret} If the secret cannot be decoded from base64 (HTTP 500)
206
- * @throws {Object} Will call next() with error object containing:
207
- * - statusCode: 401 - When token is not a valid JWT format
208
- * - statusCode: 400 - When decoded token is missing required 'iss' claim
234
+ * @throws Will call next() with error when:
235
+ * - Token is not a valid JWT format (HTTP 401)
236
+ * - Token is malformed or has invalid structure (HTTP 401)
237
+ * - Token cannot be used yet (nbf claim) (HTTP 401)
238
+ * - Token signature is invalid (HTTP 401)
239
+ * - Issuer (iss) is missing or invalid - not a number between 1-999999999 (HTTP 400)
240
+ * - Secrets configuration is invalid (HTTP 500)
241
+ * - Secret cannot be decoded from base64 (HTTP 500)
209
242
  *
243
+ * @example
244
+ * // Use in protected route chain for token refresh
245
+ * app.post('/refresh', parseBearer, decodeAccess, refreshTokens, ...);
210
246
  */
211
- function decodeAccess(req: Request, res: Response, next: NextFunction): void {}
247
+ function decodeAccess(_req: Request, res: Response, next: NextFunction): void {}
212
248
 
213
249
  /**
214
- * Middleware function to decode and verify a refresh token from the request body.
250
+ * Express middleware to decode and verify a refresh token from the request body.
215
251
  *
216
- * @param {Request} req - The request object containing the refresh token in `req.body.refreshToken`
217
- * @param {Response} res - The response object. Decoded token will be added to `res.locals.decodedRefreshToken`
218
- * @param {NextFunction} next - The next middleware function to be called.
252
+ * This middleware validates the JWT refresh token from `req.body.refreshToken`,
253
+ * verifies its signature, structure, expiration, and the issuer (iss) claim,
254
+ * then stores the decoded token in `res.locals.tokens.decodedRefresh` for use
255
+ * by subsequent middleware.
219
256
  *
220
- * @returns {void} Calls the next middleware function with an error object if the token is invalid or iss is missing.
257
+ * Note: Unlike decodeAccess, this middleware DOES check token expiration (exp claim).
258
+ * Refresh tokens must be valid and not expired.
259
+ *
260
+ * @param {Request} req - The Express request object. Should contain:
261
+ * - `req.body.refreshToken`: The JWT refresh token to decode and verify
262
+ * @param {Response} res - The Express response object.
263
+ * Decoded token will be added to `res.locals.tokens.decodedRefresh`
264
+ * @param {NextFunction} next - The next middleware function to be called
265
+ *
266
+ * @returns {void}
221
267
  *
222
- * @throws {InvalidTokenError} If the token is malformed or has invalid structure (HTTP 401)
223
- * @throws {InvalidSecretsError} If the secrets configuration is invalid (HTTP 500)
224
- * @throws {ExpiredTokenError} If the refresh token has expired (exp claim) (HTTP 401)
225
- * @throws {InactiveTokenError} If the token cannot be used yet (nbf claim) (HTTP 401)
226
- * @throws {InvalidSignatureError} If the token signature is invalid (HTTP 401)
227
- * @throws {InvalidBase64Secret} If the secret cannot be decoded from base64 (HTTP 500)
228
- * @throws {Object} Will call next() with error object containing:
229
- * - statusCode: 401 - When refresh token is not a valid JWT format
230
- * - statusCode: 400 - When decoded token is missing required 'iss' claim
268
+ * @throws Will call next() with error when:
269
+ * - Token is not a valid JWT format (HTTP 401)
270
+ * - Token is malformed or has invalid structure (HTTP 401)
271
+ * - Token has expired (exp claim) (HTTP 401)
272
+ * - Token cannot be used yet (nbf claim) (HTTP 401)
273
+ * - Token signature is invalid (HTTP 401)
274
+ * - Issuer (iss) is missing or invalid - not a number between 1-999999999 (HTTP 400)
275
+ * - Secrets configuration is invalid (HTTP 500)
276
+ * - Secret cannot be decoded from base64 (HTTP 500)
277
+ *
278
+ * @example
279
+ * // Use in refresh token flow
280
+ * app.post('/refresh', parseBearer, decodeAccess, decodeRefresh, refreshTokens, ...);
231
281
  */
232
- function decodeRefresh(req: Request, _res: Response, next: NextFunction): void {}
282
+ function decodeRefresh(req: Request, res: Response, next: NextFunction): void {}
233
283
 
234
284
  ```
235
285
 
236
- ### JWT Refresh
286
+ ### JWT Token Generation
287
+
288
+ #### createTokens
237
289
 
238
- This function will look for an ISS (user ID) from two possible sources:
290
+ This function creates new tokens for a new user or during initial login. It looks for the user ID from:
239
291
 
240
292
  ```Javascript
241
- let iss = res.locals?.decodedAccessToken?.iss;
293
+ const iss = res.locals.user.id;
294
+ ```
295
+
296
+ It stores both new refresh and access tokens in `req.body.rows[0]`:
242
297
 
243
- if (!iss)
244
- iss = res.locals.id ?? null;
298
+ ```Javascript
299
+ req.body.rows[0].accessToken = at;
300
+ req.body.rows[0].refreshToken = rt;
245
301
  ```
246
302
 
247
- It will then send both new refresh and access tokens in the res.locals object and in req.body.rows[0].
303
+ **Note:** This function assumes that `req.body.rows[0]` already exists with user data like nickname and roles.
304
+
305
+ #### refreshTokens
248
306
 
249
- **Note:** If `req.body.rows` doesn't exist or is not an array, it will be automatically created as `[{}]`. If `req.body.rows[0]` is not an object, it will be replaced with `{}`.
307
+ This function refreshes tokens for existing users. It looks for the user ID (iss) from a decoded access token:
250
308
 
251
309
  ```Javascript
252
- res.locals.accessToken = accessToken;
253
- res.locals.refreshToken = refreshToken;
310
+ let iss = res.locals?.tokens?.decodedAccess?.iss;
311
+ ```
312
+
313
+ It stores both new refresh and access tokens in `req.body.rows[0]`:
254
314
 
255
- // req.body.rows is automatically created if needed
256
- req.body.rows[0].accessToken = accessToken;
257
- req.body.rows[0].refreshToken = refreshToken;
315
+ ```Javascript
316
+ req.body.rows[0].accessToken = at;
317
+ req.body.rows[0].refreshToken = rt;
258
318
  ```
259
319
 
320
+ **Note:** This function assumes that `req.body.rows[0]` already exists with consumer data that will be updated in the database.
321
+
260
322
  ### JWT Decoding
261
323
 
262
324
  #### Route Protection with isProtected
263
325
 
264
- The `parseBearerToken()` and `decodeAccess()` middlewares only process requests when `res.locals.isProtected` is set to `true`. This allows you to selectively protect routes that require authentication.
326
+ The `parseBearer()` and `decodeAccess()` middlewares only process requests when `res.locals.route.isProtected` is set to `true`. This allows you to selectively protect routes that require authentication.
265
327
 
266
328
  You should set this flag in a middleware before calling these functions:
267
329
 
268
330
  ```Javascript
269
331
  // Example middleware to mark route as protected
270
332
  function protectRoute(req, res, next) {
271
- res.locals.isProtected = true;
333
+ res.locals.route = { isProtected: true };
272
334
  next();
273
335
  }
274
336
 
275
337
  // Usage
276
- router.get('/protected-route', protectRoute, tk.parseBearerToken, tk.decodeAccess, yourHandler);
338
+ router.get('/protected-route', protectRoute, tk.parseBearer, tk.decodeAccess, yourHandler);
277
339
  ```
278
340
 
279
- If `res.locals.isProtected` is `false`, `undefined`, or `null`, these middlewares will simply call `next()` without processing the token, allowing the request to continue to the next middleware.
341
+ If `res.locals.route.isProtected` is `false`, `undefined`, or `null`, these middlewares will simply call `next()` without processing the token, allowing the request to continue to the next middleware.
280
342
 
281
343
  #### Access Token Processing
282
344
 
283
- The access token processing is now split into two separate middlewares for better flexibility:
345
+ The access token processing is split into two separate middlewares for better flexibility:
284
346
 
285
- 1. **parseBearerToken()** - Extracts the bearer token from the Authorization header
347
+ 1. **parseBearer()** - Extracts the bearer token from the Authorization header
286
348
  2. **decodeAccess()** - Validates and decodes the JWT token
287
349
 
288
- ##### parseBearerToken()
350
+ ##### parseBearer()
289
351
 
290
352
  This middleware extracts the JWT token from the Authorization header using the Bearer scheme.
291
353
 
@@ -293,31 +355,33 @@ This middleware extracts the JWT token from the Authorization header using the B
293
355
  const bearer = req.headers.authorization; // "Bearer <token>"
294
356
  ```
295
357
 
296
- The parsed token is then stored in `res.locals.accessToken`:
358
+ The parsed token is then stored in `res.locals.tokens.access`:
297
359
 
298
360
  ```Javascript
299
- res.locals.accessToken = token;
361
+ res.locals.tokens.access = token;
300
362
  ```
301
363
 
302
364
  ##### decodeAccess()
303
365
 
304
- This middleware takes the token from `res.locals.accessToken`, validates it, and decodes it.
366
+ This middleware takes the token from `res.locals.tokens.access`, validates it, and decodes it.
305
367
 
306
368
  ```Javascript
307
- const token = res.locals.accessToken;
369
+ const token = res.locals.tokens.access;
308
370
  ```
309
371
 
310
- The decoded token is then stored in `res.locals.decodedAccessToken`:
372
+ The decoded token is then stored in `res.locals.tokens.decodedAccess`:
311
373
 
312
374
  ```Javascript
313
- res.locals.decodedAccessToken = decodedToken;
375
+ res.locals.tokens.decodedAccess = decodedToken;
314
376
  ```
315
377
 
316
- **Note:** You should use both middlewares in sequence for full access token processing, or you can use just `parseBearerToken()` if you only need to extract the token without decoding it.
378
+ **Important:** This middleware **ignores token expiration** by design. This allows expired access tokens to be decoded, which is useful for token refresh flows where you need to identify the user even after their access token has expired.
379
+
380
+ **Note:** You should use both middlewares in sequence for full access token processing, or you can use just `parseBearer()` if you only need to extract the token without decoding it.
317
381
 
318
382
  #### Refresh Token Decoding
319
383
 
320
- decodeRefresh() functions will look for a token in the client request body.
384
+ decodeRefresh() function will look for a token in the client request body.
321
385
 
322
386
  ```Javascript
323
387
  const token = req.body.refreshToken;
@@ -326,9 +390,11 @@ const token = req.body.refreshToken;
326
390
  It will then send the decoded token in the res object.
327
391
 
328
392
  ```Javascript
329
- res.locals.decodedRefreshToken = decodedToken;
393
+ res.locals.tokens.decodedRefresh = decodedToken;
330
394
  ```
331
395
 
396
+ **Important:** Unlike `decodeAccess()`, this middleware **does check token expiration**. Refresh tokens must be valid and not expired.
397
+
332
398
 
333
399
  ## Logs
334
400
 
@@ -26,14 +26,16 @@ https://github.com/DWTechs/Toker-express.js
26
26
 
27
27
  import type { Request, Response, NextFunction } from 'express';
28
28
 
29
- declare function refresh(req: Request, res: Response, next: NextFunction): void;
30
- declare function parseBearerToken(req: Request, res: Response, next: NextFunction): void;
29
+ declare function createTokens(req: Request, res: Response, next: NextFunction): void;
30
+ declare function refreshTokens(req: Request, res: Response, next: NextFunction): void;
31
+ declare function parseBearer(req: Request, res: Response, next: NextFunction): void;
31
32
  declare function decodeAccess(_req: Request, res: Response, next: NextFunction): void;
32
33
  declare function decodeRefresh(req: Request, res: Response, next: NextFunction): void;
33
34
 
34
35
  export {
35
- refresh,
36
- parseBearerToken,
36
+ createTokens,
37
+ refreshTokens,
38
+ parseBearer,
37
39
  decodeAccess,
38
40
  decodeRefresh,
39
41
  };
@@ -24,8 +24,8 @@ SOFTWARE.
24
24
  https://github.com/DWTechs/Toker-express.js
25
25
  */
26
26
 
27
- import { sign, parseBearer, verify } from '@dwtechs/toker';
28
- import { isString, isNumber, isValidNumber, isArray, isObject, isJWT } from '@dwtechs/checkard';
27
+ import { sign, parseBearer as parseBearer$1, verify } from '@dwtechs/toker';
28
+ import { isString, isNumber, isValidInteger, 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;
@@ -37,12 +37,10 @@ if (!isString(TOKEN_SECRET, "!0"))
37
37
  const secrets = [TOKEN_SECRET];
38
38
  const accessDuration = isNumber(ACCESS_TOKEN_DURATION, false) ? Number(ACCESS_TOKEN_DURATION) : 600;
39
39
  const refreshDuration = isNumber(REFRESH_TOKEN_DURATION, false) ? Number(REFRESH_TOKEN_DURATION) : 86400;
40
- function refresh(req, res, next) {
41
- var _a, _b, _c, _d;
42
- let iss = (_b = (_a = res.locals) === null || _a === void 0 ? void 0 : _a.decodedAccessToken) === null || _b === void 0 ? void 0 : _b.iss;
43
- if (!iss)
44
- iss = (_c = res.locals.id) !== null && _c !== void 0 ? _c : null;
45
- if (!isValidNumber(iss, 1, 999999999, false))
40
+ function createTokens(req, res, next) {
41
+ var _a, _b;
42
+ const iss = (_b = (_a = res.locals) === null || _a === void 0 ? void 0 : _a.user) === null || _b === void 0 ? void 0 : _b.id;
43
+ if (!isValidInteger(iss, 1, 999999999, false))
46
44
  return next({ statusCode: 400, message: `${LOGS_PREFIX}Missing iss` });
47
45
  log.debug(`${LOGS_PREFIX}Create tokens for user ${iss}`);
48
46
  let at;
@@ -55,22 +53,36 @@ function refresh(req, res, next) {
55
53
  return next(err);
56
54
  }
57
55
  log.debug(`refreshToken='${rt}', accessToken='${at}'`);
58
- res.locals.accessToken = at;
59
- res.locals.refreshToken = rt;
60
- if (!isArray((_d = req.body) === null || _d === void 0 ? void 0 : _d.rows, ">=", 1))
61
- req.body.rows = [{}];
62
- else if (!isObject(req.body.rows[0]))
63
- req.body.rows[0] = {};
64
56
  req.body.rows[0].accessToken = at;
65
57
  req.body.rows[0].refreshToken = rt;
66
58
  next();
67
59
  }
68
- function parseBearerToken(req, res, next) {
69
- if (!res.locals.isProtected)
60
+ function refreshTokens(req, res, next) {
61
+ var _a, _b, _c;
62
+ let iss = (_c = (_b = (_a = res.locals) === null || _a === void 0 ? void 0 : _a.tokens) === null || _b === void 0 ? void 0 : _b.decodedAccess) === null || _c === void 0 ? void 0 : _c.iss;
63
+ if (!isValidInteger(iss, 1, 999999999, false))
64
+ return next({ statusCode: 400, message: `${LOGS_PREFIX}Missing iss` });
65
+ log.debug(`${LOGS_PREFIX}Create tokens for user ${iss}`);
66
+ let at;
67
+ let rt;
68
+ try {
69
+ at = sign(iss, accessDuration, "access", secrets);
70
+ rt = sign(iss, refreshDuration, "refresh", secrets);
71
+ }
72
+ catch (err) {
73
+ return next(err);
74
+ }
75
+ log.debug(`refreshToken='${rt}', accessToken='${at}'`);
76
+ req.body.rows[0].accessToken = at;
77
+ req.body.rows[0].refreshToken = rt;
78
+ next();
79
+ }
80
+ function parseBearer(req, res, next) {
81
+ if (!res.locals.route.isProtected)
70
82
  return next();
71
- log.debug(`${LOGS_PREFIX}parse bearer token`);
83
+ log.debug(`${LOGS_PREFIX}parse bearer to get access token`);
72
84
  try {
73
- res.locals.accessToken = parseBearer(req.headers.authorization);
85
+ res.locals.tokens.access = parseBearer$1(req.headers.authorization);
74
86
  }
75
87
  catch (e) {
76
88
  return next(e);
@@ -79,9 +91,9 @@ function parseBearerToken(req, res, next) {
79
91
  }
80
92
  function decodeAccess(_req, res, next) {
81
93
  log.debug(`${LOGS_PREFIX}decode access token`);
82
- if (!res.locals.isProtected)
94
+ if (!res.locals.route.isProtected)
83
95
  return next();
84
- const t = res.locals.accessToken;
96
+ const t = res.locals.tokens.access;
85
97
  if (!isJWT(t))
86
98
  return next({ statusCode: 401, message: `${LOGS_PREFIX}Invalid access token` });
87
99
  let dt = null;
@@ -91,30 +103,30 @@ function decodeAccess(_req, res, next) {
91
103
  catch (e) {
92
104
  return next(e);
93
105
  }
94
- if (!isValidNumber(dt.iss, 1, 999999999, false))
106
+ if (!isValidInteger(dt.iss, 1, 999999999, false))
95
107
  return next({ statusCode: 400, message: `${LOGS_PREFIX}Missing iss` });
96
108
  log.debug(`${LOGS_PREFIX}Decoded access token : ${JSON.stringify(dt)}`);
97
- res.locals.decodedAccessToken = dt;
109
+ res.locals.tokens.decodedAccess = dt;
98
110
  next();
99
111
  }
100
112
  function decodeRefresh(req, res, next) {
101
113
  var _a;
102
- const token = (_a = req.body) === null || _a === void 0 ? void 0 : _a.refreshToken;
103
- log.debug(`${LOGS_PREFIX}decodeRefresh(token=${token})`);
104
- if (!isJWT(token))
114
+ const t = (_a = req.body) === null || _a === void 0 ? void 0 : _a.refreshToken;
115
+ log.debug(`${LOGS_PREFIX}decodeRefresh(token=${t})`);
116
+ if (!isJWT(t))
105
117
  return next({ statusCode: 401, message: `${LOGS_PREFIX}Invalid refresh token` });
106
118
  let dt = null;
107
119
  try {
108
- dt = verify(token, secrets, false);
120
+ dt = verify(t, secrets, false);
109
121
  }
110
122
  catch (e) {
111
123
  return next(e);
112
124
  }
113
- if (!isValidNumber(dt.iss, 1, 999999999, false))
125
+ if (!isValidInteger(dt.iss, 1, 999999999, false))
114
126
  return next({ statusCode: 400, message: `${LOGS_PREFIX}Missing iss` });
115
127
  log.debug(`${LOGS_PREFIX}Decoded refresh token : ${JSON.stringify(dt)}`);
116
- res.locals.decodedRefreshToken = dt;
128
+ res.locals.tokens.decodedRefresh = dt;
117
129
  next();
118
130
  }
119
131
 
120
- export { decodeAccess, decodeRefresh, parseBearerToken, refresh };
132
+ export { createTokens, decodeAccess, decodeRefresh, parseBearer, refreshTokens };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dwtechs/toker-express",
3
- "version": "0.5.2",
3
+ "version": "0.6.0",
4
4
  "description": "Open source JWT management library for Express.js to refresh and decode tokens safely.",
5
5
  "keywords": [
6
6
  "JWT",