@dwtechs/toker-express 0.1.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/LICENSE +21 -0
- package/README.md +268 -0
- package/dist/toker-express.d.ts +51 -0
- package/dist/toker-express.js +118 -0
- package/package.json +51 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 DWTechs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
|
|
2
|
+
[](https://opensource.org/licenses/MIT)
|
|
3
|
+
[](https://www.npmjs.com/package/@dwtechs/toker-express)
|
|
4
|
+
[](https://www.npmjs.com/package/@dwtechs/toker-express)
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
- [Synopsis](#synopsis)
|
|
8
|
+
- [Support](#support)
|
|
9
|
+
- [Installation](#installation)
|
|
10
|
+
- [Usage](#usage)
|
|
11
|
+
- [Environment variables](#environment-variables)
|
|
12
|
+
- [API Reference](#api-reference)
|
|
13
|
+
- [Logs](#logs)
|
|
14
|
+
- [Contributors](#contributors)
|
|
15
|
+
- [Stack](#stack)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
## Synopsis
|
|
19
|
+
|
|
20
|
+
**[Toker-express.js](https://github.com/DWTechs/Toker-express.js)** is an open source JWT management library for Express.js to refresh and decode tokens safely.
|
|
21
|
+
It includes @dwtechs/toker library and adds Express middlewares to be used in a node.js service.
|
|
22
|
+
|
|
23
|
+
- ๐ชถ Very lightweight
|
|
24
|
+
- ๐งช Thoroughly tested
|
|
25
|
+
- ๐ Shipped as EcmaScrypt Express module
|
|
26
|
+
- ๐ Written in Typescript
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
## Support
|
|
30
|
+
|
|
31
|
+
- node: 22
|
|
32
|
+
|
|
33
|
+
This is the oldest targeted versions.
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
## Installation
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
$ npm i @dwtechs/toker-express
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
## Usage
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
```javascript
|
|
47
|
+
|
|
48
|
+
// @ts-check
|
|
49
|
+
import * as tk from "@dwtechs/Toker-express";
|
|
50
|
+
import express from "express";
|
|
51
|
+
const router = express.Router();
|
|
52
|
+
|
|
53
|
+
import cEntity from "../entities/consumer.js";
|
|
54
|
+
import uEntity from "../entities/user.js";
|
|
55
|
+
import checkToken from "../middlewares/validators/check-token.js";
|
|
56
|
+
import login from "../middlewares/login.js";
|
|
57
|
+
|
|
58
|
+
const add = [
|
|
59
|
+
uEntity.normalize,
|
|
60
|
+
uEntity.validate,
|
|
61
|
+
login,
|
|
62
|
+
tk.refresh,
|
|
63
|
+
cEntity.add,
|
|
64
|
+
];
|
|
65
|
+
|
|
66
|
+
const refresh = [
|
|
67
|
+
cEntity.validate,
|
|
68
|
+
tk.decodeAccess,
|
|
69
|
+
tk.decodeRefresh,
|
|
70
|
+
checkToken,
|
|
71
|
+
tk.refresh,
|
|
72
|
+
cEntity.update,
|
|
73
|
+
];
|
|
74
|
+
|
|
75
|
+
const del = [
|
|
76
|
+
checkToken,
|
|
77
|
+
tk.decodeAccess,
|
|
78
|
+
cEntity.delete,
|
|
79
|
+
];
|
|
80
|
+
|
|
81
|
+
// Routes
|
|
82
|
+
|
|
83
|
+
// add a consumer. Log a user
|
|
84
|
+
router.post("/", add);
|
|
85
|
+
|
|
86
|
+
// Update a consumer with new tokens
|
|
87
|
+
// Used for login and refresh tokens
|
|
88
|
+
router.put("/", refresh);
|
|
89
|
+
|
|
90
|
+
// delete a consumer. Used when logging out
|
|
91
|
+
router.delete("/", del);
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
### Environment variables
|
|
98
|
+
|
|
99
|
+
You can intialise the library using the following environment variables:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
ACCESS_TOKEN_DURATION,
|
|
103
|
+
REFRESH_TOKEN_DURATION
|
|
104
|
+
TOKEN_SECRET,
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
These environment variables will update the default values of the lib at start up.
|
|
108
|
+
So you do not need to init the library in the code.
|
|
109
|
+
|
|
110
|
+
Note that **TOKEN_SECRET** is mandatory.
|
|
111
|
+
|
|
112
|
+
Default values :
|
|
113
|
+
|
|
114
|
+
```javascript
|
|
115
|
+
const accessDuration = isNumber(ACCESS_TOKEN_DURATION, false) ? ACCESS_TOKEN_DURATION : 600; // #10 * 60 => 10 mins
|
|
116
|
+
const refreshDuration = isNumber(REFRESH_TOKEN_DURATION, false) ? REFRESH_TOKEN_DURATION : 86400; // #24 * 60 * 60 => 1 day
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## API Reference
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Refreshes the JWT tokens for a user.
|
|
126
|
+
*
|
|
127
|
+
* This function generates new access and refresh tokens for a user based on the provided
|
|
128
|
+
* decoded access token or user ID in the request body. It validates the issuer (iss) and
|
|
129
|
+
* creates new tokens if the validation is successful. The new tokens are then added to the
|
|
130
|
+
* response object.
|
|
131
|
+
*
|
|
132
|
+
* @param {Request} req - The request object containing the decoded access token or user ID.
|
|
133
|
+
* @param {MyResponse} res - The response object where the new tokens will be added.
|
|
134
|
+
* @param {NextFunction} next - The next middleware function in the Express.js request-response cycle.
|
|
135
|
+
*
|
|
136
|
+
* @returns {Promise<void>} Calls the next middleware function with an error if the issuer is invalid,
|
|
137
|
+
* otherwise proceeds to the next middleware function.
|
|
138
|
+
*
|
|
139
|
+
* @throws {InvalidIssuerError} If the issuer (iss) is not a string or number (HTTP 400)
|
|
140
|
+
* @throws {InvalidSecretsError} If the secrets array is empty or invalid (HTTP 500)
|
|
141
|
+
* @throws {InvalidDurationError} If the duration is not a positive number (HTTP 400)
|
|
142
|
+
* @throws {InvalidBase64Secret} If the secret cannot be decoded from base64 (HTTP 500)
|
|
143
|
+
* @throws {Object} Will call next() with error object containing:
|
|
144
|
+
* - statusCode: 400 - When iss (issuer) is missing or invalid
|
|
145
|
+
* - statusCode: 400 - When iss is not a valid number between 1 and 999999999
|
|
146
|
+
*/
|
|
147
|
+
function refresh(req: Request, res: MyResponse, next: NextFunction): void {}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Express middleware function to decode and verify an access token from the Authorization header.
|
|
151
|
+
*
|
|
152
|
+
* This middleware extracts the JWT access token from the Authorization header, validates its format,
|
|
153
|
+
* verifies its signature, and attaches the decoded token to the request object for use by subsequent
|
|
154
|
+
* middleware. It only processes requests that have `req.isProtected` set to true.
|
|
155
|
+
*
|
|
156
|
+
* @param {Request} req - The Express request object containing the Authorization header
|
|
157
|
+
* @param {Response} _res - The Express response object (not used in this function)
|
|
158
|
+
* @param {NextFunction} next - The next middleware function to be called
|
|
159
|
+
*
|
|
160
|
+
* @returns {void} Calls the next middleware function, either with an error or successfully
|
|
161
|
+
*
|
|
162
|
+
* @throws {MissingAuthorizationError} If the Authorization header is missing (HTTP 401)
|
|
163
|
+
* @throws {InvalidBearerFormatError} If the Authorization header format is invalid (HTTP 401)
|
|
164
|
+
* @throws {InvalidTokenError} If the token is malformed or has invalid structure (HTTP 401)
|
|
165
|
+
* @throws {ExpiredTokenError} If the token has expired (exp claim) (HTTP 401)
|
|
166
|
+
* @throws {InactiveTokenError} If the token cannot be used yet (nbf claim) (HTTP 401)
|
|
167
|
+
* @throws {InvalidSignatureError} If the token signature is invalid (HTTP 401)
|
|
168
|
+
* @throws {InvalidSecretsError} If the secrets configuration is invalid (HTTP 500)
|
|
169
|
+
* @throws {InvalidBase64Secret} If the secret cannot be decoded from base64 (HTTP 500)
|
|
170
|
+
* @throws {Object} Will call next() with error object containing:
|
|
171
|
+
* - statusCode: 401 - When token is not a valid JWT format
|
|
172
|
+
* - statusCode: 400 - When decoded token is missing required 'iss' claim
|
|
173
|
+
*
|
|
174
|
+
* @example
|
|
175
|
+
* ```typescript
|
|
176
|
+
* // Usage in Express route with protection middleware
|
|
177
|
+
* const protect = (req: Request, res: Response, next: NextFunction) => {
|
|
178
|
+
* req.isProtected = true;
|
|
179
|
+
* next();
|
|
180
|
+
* };
|
|
181
|
+
*
|
|
182
|
+
*/
|
|
183
|
+
function decodeAccess(req: Request, _res: Response, next: NextFunction): void {}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Middleware function to decode and verify a refresh token from the request body.
|
|
187
|
+
*
|
|
188
|
+
* @param {Request} req - The request object containing the refresh token in the body.
|
|
189
|
+
* @param {Response} _res - The response object (not used in this function).
|
|
190
|
+
* @param {NextFunction} next - The next middleware function to be called.
|
|
191
|
+
*
|
|
192
|
+
* @returns {Promise<void>} Calls the next middleware function with an error object if the token is invalid or missing required fields.
|
|
193
|
+
*
|
|
194
|
+
* @throws {InvalidTokenError} If the token is malformed or has invalid structure (HTTP 401)
|
|
195
|
+
* @throws {InvalidSecretsError} If the secrets configuration is invalid (HTTP 500)
|
|
196
|
+
* @throws {ExpiredTokenError} If the refresh token has expired (exp claim) (HTTP 401)
|
|
197
|
+
* @throws {InactiveTokenError} If the token cannot be used yet (nbf claim) (HTTP 401)
|
|
198
|
+
* @throws {InvalidSignatureError} If the token signature is invalid (HTTP 401)
|
|
199
|
+
* @throws {InvalidBase64Secret} If the secret cannot be decoded from base64 (HTTP 500)
|
|
200
|
+
* @throws {Object} Will call next() with error object containing:
|
|
201
|
+
* - statusCode: 401 - When refresh token is not a valid JWT format
|
|
202
|
+
* - statusCode: 400 - When decoded token is missing required 'iss' claim
|
|
203
|
+
*/
|
|
204
|
+
function decodeRefresh(req: Request, _res: Response, next: NextFunction): void {}
|
|
205
|
+
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### JWT Refresh
|
|
209
|
+
|
|
210
|
+
This function will look for an ISS in the client request body :
|
|
211
|
+
|
|
212
|
+
```Javascript
|
|
213
|
+
const iss = req.body.decodedAccessToken?.iss || req.body?.id?.toString();
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
It will then send both new refresh and access tokens in the res object.
|
|
217
|
+
|
|
218
|
+
```Javascript
|
|
219
|
+
res.rows = [{ accessToken, refreshToken }];
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### JWT Decoding
|
|
223
|
+
|
|
224
|
+
decodeAccess() functions will look for a bearer in authorization headers.
|
|
225
|
+
|
|
226
|
+
```Javascript
|
|
227
|
+
const bearer = req.headers.authorization;
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
It will then send the decoded token in the res object.
|
|
231
|
+
|
|
232
|
+
```Javascript
|
|
233
|
+
req.decodedAccessToken = decodedToken;
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
decodeRefresh() functions will look for a token in the client request body.
|
|
237
|
+
|
|
238
|
+
```Javascript
|
|
239
|
+
const token = req.body.refreshToken;
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
It will then send the decoded token in the res object.
|
|
243
|
+
|
|
244
|
+
```Javascript
|
|
245
|
+
req.decodedRefreshToken = decodedToken;
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
## Logs
|
|
250
|
+
|
|
251
|
+
**Token-express.js** uses **[@dwtechs/Winstan](https://www.npmjs.com/package/@dwtechs/winstan)** library for logging.
|
|
252
|
+
All logs are in debug mode. Meaning they should not appear in production mode.
|
|
253
|
+
|
|
254
|
+
## Contributors
|
|
255
|
+
|
|
256
|
+
**Token-express.js** is still in development and we would be glad to get all the help you can provide.
|
|
257
|
+
To contribute please read **[contributor.md](https://github.com/DWTechs/Token-express.js/blob/main/contributor.md)** for detailed installation guide.
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
## Stack
|
|
261
|
+
|
|
262
|
+
| Purpose | Choice | Motivation |
|
|
263
|
+
| :-------------- | :------------------------------------------: | -------------------------------------------------------------: |
|
|
264
|
+
| repository | [Github](https://github.com/) | hosting for software development version control using Git |
|
|
265
|
+
| package manager | [npm](https://www.npmjs.com/get-npm) | default node.js package manager |
|
|
266
|
+
| language | [TypeScript](https://www.typescriptlang.org) | static type checking along with the latest ECMAScript features |
|
|
267
|
+
| module bundler | [Rollup](https://rollupjs.org) | advanced module bundler for ES6 modules |
|
|
268
|
+
| unit testing | [Jest](https://jestjs.io/) | delightful testing with a focus on simplicity |
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/*
|
|
2
|
+
MIT License
|
|
3
|
+
|
|
4
|
+
Copyright (c) 2025 DWTechs
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
|
23
|
+
|
|
24
|
+
https://github.com/DWTechs/Toker-express.js
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import type { Request, Response, NextFunction } from 'express';
|
|
28
|
+
import type { MyResponse } from './interfaces';
|
|
29
|
+
|
|
30
|
+
// Extend Express Request interface globally
|
|
31
|
+
declare global {
|
|
32
|
+
namespace Express {
|
|
33
|
+
interface Request {
|
|
34
|
+
isProtected?: boolean;
|
|
35
|
+
decodedAccessToken?: any;
|
|
36
|
+
decodedRefreshToken?: any;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
declare function refresh(req: Request, res: MyResponse, next: NextFunction): Promise<void>;
|
|
42
|
+
declare function decodeAccess(req: Request, _res: Response, next: NextFunction): void;
|
|
43
|
+
declare function decodeRefresh(req: Request, _res: Response, next: NextFunction): Promise<void>;
|
|
44
|
+
|
|
45
|
+
export {
|
|
46
|
+
refresh,
|
|
47
|
+
decodeAccess,
|
|
48
|
+
decodeRefresh,
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/*
|
|
2
|
+
MIT License
|
|
3
|
+
|
|
4
|
+
Copyright (c) 2025 DWTechs
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
|
23
|
+
|
|
24
|
+
https://github.com/DWTechs/Toker-express.js
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import { sign, parseBearer, verify } from '@dwtechs/toker';
|
|
28
|
+
import { isString, isNumber, isValidNumber, isJWT } from '@dwtechs/checkard';
|
|
29
|
+
import { log } from '@dwtechs/winstan';
|
|
30
|
+
|
|
31
|
+
var __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
32
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
33
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
34
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
35
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
36
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
37
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
const { TOKEN_SECRET, ACCESS_TOKEN_DURATION, REFRESH_TOKEN_DURATION } = process.env;
|
|
41
|
+
const TE_PREFIX = "Toker-express: ";
|
|
42
|
+
if (!TOKEN_SECRET)
|
|
43
|
+
throw new Error(`${TE_PREFIX} Missing TOKEN_SECRET environment variable`);
|
|
44
|
+
if (!isString(TOKEN_SECRET, "!0"))
|
|
45
|
+
throw new Error(`${TE_PREFIX} Invalid TOKEN_SECRET environment variable`);
|
|
46
|
+
const secrets = [TOKEN_SECRET];
|
|
47
|
+
const accessDuration = isNumber(ACCESS_TOKEN_DURATION, false) ? ACCESS_TOKEN_DURATION : 600;
|
|
48
|
+
const refreshDuration = isNumber(REFRESH_TOKEN_DURATION, false) ? REFRESH_TOKEN_DURATION : 86400;
|
|
49
|
+
function refresh(req, res, next) {
|
|
50
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
51
|
+
var _a, _b, _c;
|
|
52
|
+
const iss = ((_a = req.decodedAccessToken) === null || _a === void 0 ? void 0 : _a.iss) || ((_c = (_b = req.body) === null || _b === void 0 ? void 0 : _b.id) === null || _c === void 0 ? void 0 : _c.toString());
|
|
53
|
+
if (!isValidNumber(iss, 1, 999999999, false))
|
|
54
|
+
return next({ statusCode: 400, message: `${TE_PREFIX} Missing iss` });
|
|
55
|
+
log.debug(`Create tokens for user ${iss}`);
|
|
56
|
+
let accessToken;
|
|
57
|
+
let refreshToken;
|
|
58
|
+
try {
|
|
59
|
+
accessToken = sign(iss, accessDuration, "access", secrets);
|
|
60
|
+
refreshToken = sign(iss, refreshDuration, "refresh", secrets);
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
return next(err);
|
|
64
|
+
}
|
|
65
|
+
log.debug(`refreshToken='${refreshToken}', accessToken='${accessToken}'`);
|
|
66
|
+
res.rows = [{ accessToken, refreshToken }];
|
|
67
|
+
next();
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
function decodeAccess(req, _res, next) {
|
|
71
|
+
log.debug(`decode access token`);
|
|
72
|
+
if (!req.isProtected)
|
|
73
|
+
return next();
|
|
74
|
+
let t;
|
|
75
|
+
try {
|
|
76
|
+
t = parseBearer(req.headers.authorization);
|
|
77
|
+
}
|
|
78
|
+
catch (e) {
|
|
79
|
+
return next(e);
|
|
80
|
+
}
|
|
81
|
+
log.debug(`accessToken : ${t}`);
|
|
82
|
+
if (!isJWT(t))
|
|
83
|
+
return next({ statusCode: 401, message: `${TE_PREFIX} Invalid access token` });
|
|
84
|
+
let decodedToken = null;
|
|
85
|
+
try {
|
|
86
|
+
decodedToken = verify(t, secrets, true);
|
|
87
|
+
}
|
|
88
|
+
catch (e) {
|
|
89
|
+
return next(e);
|
|
90
|
+
}
|
|
91
|
+
if (!isValidNumber(decodedToken.iss, 1, 999999999, false))
|
|
92
|
+
return next({ statusCode: 400, message: `${TE_PREFIX} Missing iss` });
|
|
93
|
+
log.debug(`Decoded access token : ${JSON.stringify(decodedToken)}`);
|
|
94
|
+
req.decodedAccessToken = decodedToken;
|
|
95
|
+
next();
|
|
96
|
+
}
|
|
97
|
+
function decodeRefresh(req, _res, next) {
|
|
98
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
99
|
+
const token = req.body.refreshToken;
|
|
100
|
+
log.debug(`decodeRefresh(token=${token})`);
|
|
101
|
+
if (!isJWT(token))
|
|
102
|
+
return next({ statusCode: 401, message: `${TE_PREFIX} Invalid refresh token` });
|
|
103
|
+
let decodedToken = null;
|
|
104
|
+
try {
|
|
105
|
+
decodedToken = verify(token, secrets, false);
|
|
106
|
+
}
|
|
107
|
+
catch (e) {
|
|
108
|
+
return next(e);
|
|
109
|
+
}
|
|
110
|
+
if (!isValidNumber(decodedToken.iss, 1, 999999999, false))
|
|
111
|
+
return next({ statusCode: 400, message: `${TE_PREFIX} Missing iss` });
|
|
112
|
+
log.debug(`Decoded refresh token : ${JSON.stringify(req.decodedRefreshToken)}`);
|
|
113
|
+
req.decodedRefreshToken = decodedToken;
|
|
114
|
+
next();
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export { decodeAccess, decodeRefresh, refresh };
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dwtechs/toker-express",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Open source JWT management library for Express.js to refresh and decode tokens safely.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"JWT",
|
|
7
|
+
"Express"
|
|
8
|
+
],
|
|
9
|
+
"homepage": "https://github.com/DWTechs/Toker-express.js",
|
|
10
|
+
"main": "dist/toker-express",
|
|
11
|
+
"types": "dist/toker-express",
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "https://github.com/DWTechs/Toker-express.js"
|
|
15
|
+
},
|
|
16
|
+
"bugs": {
|
|
17
|
+
"url": "https://github.com/DWTechs/Toker-express.js/issues",
|
|
18
|
+
"email": ""
|
|
19
|
+
},
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"author": {
|
|
22
|
+
"name": "Ludovic Cluber",
|
|
23
|
+
"email": "http://www.lcluber.com/contact",
|
|
24
|
+
"url": "http://www.lcluber.com"
|
|
25
|
+
},
|
|
26
|
+
"contributors": [],
|
|
27
|
+
"scripts": {
|
|
28
|
+
"start": "",
|
|
29
|
+
"prebuild": "npm install",
|
|
30
|
+
"build": "node ./scripts/clear && tsc && npm run rollup && node ./scripts/copy && npm run test",
|
|
31
|
+
"rollup:mjs": "rollup --config rollup.config.mjs",
|
|
32
|
+
"rollup:cjs": "rollup --config rollup.config.cjs.mjs",
|
|
33
|
+
"rollup": "npm run rollup:mjs",
|
|
34
|
+
"test": ""
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"dist/"
|
|
38
|
+
],
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@dwtechs/checkard": "3.2.3",
|
|
41
|
+
"@dwtechs/toker": "0.1.0",
|
|
42
|
+
"@dwtechs/winstan": "0.3.0"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/express": "5.0.0",
|
|
46
|
+
"@rollup/plugin-node-resolve": "15.3.0",
|
|
47
|
+
"core-js": "3.38.1",
|
|
48
|
+
"rollup": "4.24.0",
|
|
49
|
+
"typescript": "5.6.3"
|
|
50
|
+
}
|
|
51
|
+
}
|