@carecard/jwt-read 3.1.13 → 3.1.14

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/.prettierrc.js ADDED
@@ -0,0 +1,12 @@
1
+ module.exports = {
2
+ arrowParens: 'avoid',
3
+ bracketSameLine: true,
4
+ bracketSpacing: true,
5
+ singleQuote: true,
6
+ trailingComma: 'all',
7
+ printWidth: 140,
8
+ useTabs: false,
9
+ endOfLine: 'auto',
10
+ importOrderSeparation: true,
11
+ importOrderSortSpecifiers: true,
12
+ };
@@ -0,0 +1,14 @@
1
+ import { defineConfig, globalIgnores } from 'eslint/config';
2
+
3
+ const eslintConfig = defineConfig([
4
+ globalIgnores([
5
+ // Default ignores of eslint-config-next:
6
+ '.next/**',
7
+ 'out/**',
8
+ 'build/**',
9
+ 'next-env.d.ts',
10
+ 'node_modules/**',
11
+ ]),
12
+ ]);
13
+
14
+ export default eslintConfig;
package/index.d.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  * Utility functions for authentication and authorization in the CareCard ecosystem.
3
3
  */
4
4
 
5
- import { Request, Response, NextFunction } from 'express';
5
+ import {NextFunction, Request, Response} from 'express';
6
6
 
7
7
  /**
8
8
  * Represents the standard JWT header structure.
@@ -50,44 +50,50 @@ export interface JwtParts {
50
50
  * Structure of the JWT object attached to the request.
51
51
  */
52
52
  export interface JwtRequestObject {
53
- header: JwtHeader;
54
- payload: JwtPayload;
55
- age?: number;
56
- jwtClientId: (req?: any) => string | undefined;
57
- doesJwtUserHasRole: (role: string) => boolean;
58
- isJwtExpired: (jwtValiditySeconds?: number) => boolean;
59
- jwtAgeInSeconds: (req?: any) => number;
53
+ header: JwtHeader;
54
+ payload: JwtPayload;
55
+ age?: number;
56
+ jwtClientId: (req?: any) => string | undefined;
57
+ doesJwtUserHasRole: (role: string) => boolean;
58
+ isJwtExpired: (jwtValiditySeconds?: number) => boolean;
59
+ jwtAgeInSeconds: (req?: any) => number;
60
60
  }
61
61
 
62
62
  /**
63
63
  * Structure of the visitor object attached to the request.
64
64
  */
65
65
  export interface VisitorRequestObject {
66
- header: JwtHeader;
67
- payload: JwtPayload;
68
- visitorClientId: (req?: any) => string | undefined;
66
+ header: JwtHeader;
67
+ payload: JwtPayload;
68
+ visitorClientId: (req?: any) => string | undefined;
69
69
  }
70
70
 
71
71
  /**
72
72
  * Extended Express Request to include jwt and visitor objects.
73
73
  */
74
74
  export interface AuthenticatedRequest extends Request {
75
- jwt?: JwtRequestObject | null;
76
- visitor?: VisitorRequestObject | null;
75
+ jwt?: JwtRequestObject | null;
76
+ visitor?: VisitorRequestObject | null;
77
77
  }
78
78
 
79
-
80
79
  /**
81
80
  * Returns a middleware that verifies a JWT from the 'Authorization: Bearer <token>' header
82
81
  * and extracts it into req.jwt. Throws an error if invalid.
83
82
  */
84
- export function jwtVerify(publicKey: string, customErrorFunction?: () => void): (req: AuthenticatedRequest, res: Response, next: NextFunction) => void;
83
+ export function jwtVerify(
84
+ publicKey: string,
85
+ customErrorFunction?: () => void,
86
+ ): (req: AuthenticatedRequest, res: Response, next: NextFunction) => void;
85
87
 
86
88
  /**
87
89
  * Returns a middleware that verifies a JWT from a custom header and extracts it into req.jwt.
88
90
  * Throws an error if invalid.
89
91
  */
90
- export function jwtVerifyWebToken(publicKey: string, headerName: string, customErrorFunction?: () => void): (req: AuthenticatedRequest, res: Response, next: NextFunction) => void;
92
+ export function jwtVerifyWebToken(
93
+ publicKey: string,
94
+ headerName: string,
95
+ customErrorFunction?: () => void,
96
+ ): (req: AuthenticatedRequest, res: Response, next: NextFunction) => void;
91
97
 
92
98
  /**
93
99
  * Returns a middleware that verifies a JWT from the 'Authorization: Bearer <token>' header
@@ -99,7 +105,10 @@ export function jwtVerifyNoThrow(publicKey: string): (req: AuthenticatedRequest,
99
105
  * Returns a middleware that verifies a JWT from a custom header and extracts it into req.jwt.
100
106
  * Returns false instead of throwing if invalid.
101
107
  */
102
- export function jwtVerifyWebTokenNoThrow(publicKey: string, headerName: string): (req: AuthenticatedRequest, res: Response, next: NextFunction) => void;
108
+ export function jwtVerifyWebTokenNoThrow(
109
+ publicKey: string,
110
+ headerName: string,
111
+ ): (req: AuthenticatedRequest, res: Response, next: NextFunction) => void;
103
112
 
104
113
  /**
105
114
  * Returns a middleware that verifies a visitor token from the 'Visitor' header
@@ -132,7 +141,11 @@ export function jwtGetAgeInSeconds(req?: any): number;
132
141
  /**
133
142
  * Returns a middleware that verifies the JWT and checks if the user has the required role.
134
143
  */
135
- export function jwtVerifyAndHasRole(userRole: string, publicKey: string, customErrorFunction?: () => void): (req: AuthenticatedRequest, res: Response, next: NextFunction) => void;
144
+ export function jwtVerifyAndHasRole(
145
+ userRole: string,
146
+ publicKey: string,
147
+ customErrorFunction?: () => void,
148
+ ): (req: AuthenticatedRequest, res: Response, next: NextFunction) => void;
136
149
 
137
150
  /**
138
151
  * Gets the full name of a role from its code (e.g., 'ad' -> 'admin').
@@ -144,6 +157,22 @@ export function jwtGetRoleName(roleCode: string): string;
144
157
  */
145
158
  export function jwtGetRoleCode(roleName: string): string;
146
159
 
160
+ /**
161
+ * Represents the context derived from the JWT request.
162
+ */
163
+ export interface JwtContext {
164
+ /** The user ID (sub) from the JWT. Always returned. */
165
+ user_id: string | undefined;
166
+ /** The role of the user. Only set to 'super_admin' when roles contains 'ad'. */
167
+ role?: string;
168
+ }
169
+
170
+ /**
171
+ * Returns the context derived from the JWT in req.jwt.
172
+ * Always returns user_id. If the roles array contains 'ad', also returns role: 'super_admin'.
173
+ */
174
+ export function jwtGetContext(req: any): JwtContext;
175
+
147
176
  /**
148
177
  * Validates the JWT from the Authorization header and extracts it into req.jwt.
149
178
  */
@@ -152,7 +181,12 @@ export function jwtValidateAndExtract(req: AuthenticatedRequest, publicKey: stri
152
181
  /**
153
182
  * Validates the JWT from a custom header and extracts it into req.jwt.
154
183
  */
155
- export function jwtValidateAndExtractWebToken(req: AuthenticatedRequest, publicKey: string, headerName: string, customErrorFunction?: () => void): void;
184
+ export function jwtValidateAndExtractWebToken(
185
+ req: AuthenticatedRequest,
186
+ publicKey: string,
187
+ headerName: string,
188
+ customErrorFunction?: () => void,
189
+ ): void;
156
190
 
157
191
  /**
158
192
  * Validates the JWT from the Authorization header and extracts it into req.jwt (no-throw).
@@ -169,20 +203,26 @@ export function jwtValidateAndExtractWebTokenNoThrow(req: AuthenticatedRequest,
169
203
  */
170
204
  export function jwtValidateAndExtractVisitorNoThrow(req: AuthenticatedRequest, publicKey: string): void;
171
205
 
172
-
173
206
  /**
174
207
  * Returns a middleware that verifies a JWT from the 'Authorization: Bearer <token>' header
175
208
  * and extracts it into req.jwt. Throws an error if invalid.
176
209
  * @deprecated use jwtVerify
177
210
  */
178
- export function verifyJwt(publicKey: string, customErrorFunction?: () => void): (req: AuthenticatedRequest, res: Response, next: NextFunction) => void;
211
+ export function verifyJwt(
212
+ publicKey: string,
213
+ customErrorFunction?: () => void,
214
+ ): (req: AuthenticatedRequest, res: Response, next: NextFunction) => void;
179
215
 
180
216
  /**
181
217
  * Returns a middleware that verifies a JWT from a custom header and extracts it into req.jwt.
182
218
  * Throws an error if invalid.
183
219
  * @deprecated use jwtVerifyWebToken
184
220
  */
185
- export function verifyWebToken(publicKey: string, headerName: string, customErrorFunction?: () => void): (req: AuthenticatedRequest, res: Response, next: NextFunction) => void;
221
+ export function verifyWebToken(
222
+ publicKey: string,
223
+ headerName: string,
224
+ customErrorFunction?: () => void,
225
+ ): (req: AuthenticatedRequest, res: Response, next: NextFunction) => void;
186
226
 
187
227
  /**
188
228
  * Returns a middleware that verifies a JWT from the 'Authorization: Bearer <token>' header
@@ -196,7 +236,10 @@ export function verifyJwtNoThrow(publicKey: string): (req: AuthenticatedRequest,
196
236
  * Returns false instead of throwing if invalid.
197
237
  * @deprecated use jwtVerifyWebTokenNoThrow
198
238
  */
199
- export function verifyWebTokenNoThrow(publicKey: string, headerName: string): (req: AuthenticatedRequest, res: Response, next: NextFunction) => void;
239
+ export function verifyWebTokenNoThrow(
240
+ publicKey: string,
241
+ headerName: string,
242
+ ): (req: AuthenticatedRequest, res: Response, next: NextFunction) => void;
200
243
 
201
244
  /**
202
245
  * Returns a middleware that verifies a visitor token from the 'Visitor' header
@@ -237,7 +280,11 @@ export function jwtAgeInSeconds(req?: any): number;
237
280
  * Returns a middleware that verifies the JWT and checks if the user has the required role.
238
281
  * @deprecated use jwtVerifyAndHasRole
239
282
  */
240
- export function verifyJwtAndRole(userRole: string, publicKey: string, customErrorFunction?: () => void): (req: AuthenticatedRequest, res: Response, next: NextFunction) => void;
283
+ export function verifyJwtAndRole(
284
+ userRole: string,
285
+ publicKey: string,
286
+ customErrorFunction?: () => void,
287
+ ): (req: AuthenticatedRequest, res: Response, next: NextFunction) => void;
241
288
 
242
289
  /**
243
290
  * Throws a Used_Token error.
@@ -245,7 +292,6 @@ export function verifyJwtAndRole(userRole: string, publicKey: string, customErro
245
292
  */
246
293
  export function throwUsedTokenError(): never;
247
294
 
248
-
249
295
  /**
250
296
  * Checks if the user in the extracted JWT has the specified role.
251
297
  * @deprecated use jwtDoesJwtUserHasRole
@@ -260,10 +306,8 @@ export function doesJwtUserHasRole(userRole: string): boolean;
260
306
  */
261
307
  export function getNameOfRole(roleCode: string): string;
262
308
 
263
-
264
309
  /**
265
310
  * Gets the code of a role from its name (e.g., 'admin' -> 'ad').
266
311
  * @deprecated use jwtGetRoleCode
267
312
  */
268
313
  export function getCodeOfRole(roleName: string): string;
269
-
package/index.js CHANGED
@@ -2,50 +2,51 @@ const jwtLib = require('./lib/jwtLib');
2
2
  const jwtRoles = require('./lib/jwtRoles');
3
3
 
4
4
  module.exports = {
5
- jwtVerify: jwtLib.verifyJwt,
6
- jwtVerifyWebToken: jwtLib.verifyWebToken,
7
- jwtVerifyNoThrow: jwtLib.verifyJwtNoThrow,
8
- jwtVerifyWebTokenNoThrow: jwtLib.verifyWebTokenNoThrow,
9
- jwtVerifyVisitorNoThrow: jwtLib.verifyVisitorNoThrow,
10
- jwtGetClientId: jwtLib.jwtClientId,
11
- jwtGetVisitorClientId: jwtLib.visitorClientId,
12
- jwtIsExpired: jwtLib.isJwtExpired,
13
- jwtGetAgeInSeconds: jwtLib.jwtAgeInSeconds,
14
- jwtVerifyAndHasRole: jwtLib.verifyJwtAndRole,
15
- jwtGetRoleName: jwtRoles.getNameOfRoleFromCode,
16
- jwtGetRoleCode: jwtRoles.getCodeFromNameOfRole,
17
- jwtValidateAndExtract: jwtLib.validateAndExtractJwtObject,
18
- jwtValidateAndExtractWebToken: jwtLib.validateAndExtractWebToken,
19
- jwtValidateAndExtractNoThrow: jwtLib.validateAndExtractJwtObjectNoThrow,
20
- jwtValidateAndExtractWebTokenNoThrow: jwtLib.validateAndExtractWebTokenObjectNoThrow,
21
- jwtValidateAndExtractVisitorNoThrow: jwtLib.validateAndExtractVisitorObjectNoThrow,
5
+ jwtVerify: jwtLib.verifyJwt,
6
+ jwtVerifyWebToken: jwtLib.verifyWebToken,
7
+ jwtVerifyNoThrow: jwtLib.verifyJwtNoThrow,
8
+ jwtVerifyWebTokenNoThrow: jwtLib.verifyWebTokenNoThrow,
9
+ jwtVerifyVisitorNoThrow: jwtLib.verifyVisitorNoThrow,
10
+ jwtGetClientId: jwtLib.jwtClientId,
11
+ jwtGetVisitorClientId: jwtLib.visitorClientId,
12
+ jwtIsExpired: jwtLib.isJwtExpired,
13
+ jwtGetAgeInSeconds: jwtLib.jwtAgeInSeconds,
14
+ jwtVerifyAndHasRole: jwtLib.verifyJwtAndRole,
15
+ jwtGetRoleName: jwtRoles.getNameOfRoleFromCode,
16
+ jwtGetRoleCode: jwtRoles.getCodeFromNameOfRole,
17
+ jwtGetContext: jwtRoles.getContext,
18
+ jwtValidateAndExtract: jwtLib.validateAndExtractJwtObject,
19
+ jwtValidateAndExtractWebToken: jwtLib.validateAndExtractWebToken,
20
+ jwtValidateAndExtractNoThrow: jwtLib.validateAndExtractJwtObjectNoThrow,
21
+ jwtValidateAndExtractWebTokenNoThrow: jwtLib.validateAndExtractWebTokenObjectNoThrow,
22
+ jwtValidateAndExtractVisitorNoThrow: jwtLib.validateAndExtractVisitorObjectNoThrow,
22
23
 
23
- /** @deprecated use jwtVerify */
24
- verifyJwt: jwtLib.verifyJwt,
25
- /** @deprecated use jwtVerifyWebToken */
26
- verifyWebToken: jwtLib.verifyWebToken,
27
- /** @deprecated use jwtVerifyNoThrow */
28
- verifyJwtNoThrow: jwtLib.verifyJwtNoThrow,
29
- /** @deprecated use jwtVerifyWebTokenNoThrow */
30
- verifyWebTokenNoThrow: jwtLib.verifyWebTokenNoThrow,
31
- /** @deprecated use jwtVerifyVisitorNoThrow */
32
- verifyVisitorNoThrow: jwtLib.verifyVisitorNoThrow,
33
- /** @deprecated use jwtGetClientId */
34
- jwtClientId: jwtLib.jwtClientId,
35
- /** @deprecated use jwtGetVisitorClientId */
36
- visitorClientId: jwtLib.visitorClientId,
37
- /** @deprecated use jwtIsExpired */
38
- isJwtExpired: jwtLib.isJwtExpired,
39
- /** @deprecated use jwtGetAgeInSeconds */
40
- jwtAgeInSeconds: jwtLib.jwtAgeInSeconds,
41
- /** @deprecated use jwtVerifyAndHasRole */
42
- verifyJwtAndRole: jwtLib.verifyJwtAndRole,
43
- /** @deprecated use jwtThrowUsedTokenError */
44
- throwUsedTokenError: jwtLib.throwUsedTokenError,
45
- /** @deprecated use jwtDoesJwtUserHasRole */
46
- doesJwtUserHasRole: jwtLib.doesJwtUserHasRole,
47
- /** @deprecated use jwtGetRoleName */
48
- getNameOfRole: jwtRoles.getNameOfRoleFromCode,
49
- /** @deprecated use jwtGetRoleCode */
50
- getCodeOfRole: jwtRoles.getCodeFromNameOfRole
24
+ /** @deprecated use jwtVerify */
25
+ verifyJwt: jwtLib.verifyJwt,
26
+ /** @deprecated use jwtVerifyWebToken */
27
+ verifyWebToken: jwtLib.verifyWebToken,
28
+ /** @deprecated use jwtVerifyNoThrow */
29
+ verifyJwtNoThrow: jwtLib.verifyJwtNoThrow,
30
+ /** @deprecated use jwtVerifyWebTokenNoThrow */
31
+ verifyWebTokenNoThrow: jwtLib.verifyWebTokenNoThrow,
32
+ /** @deprecated use jwtVerifyVisitorNoThrow */
33
+ verifyVisitorNoThrow: jwtLib.verifyVisitorNoThrow,
34
+ /** @deprecated use jwtGetClientId */
35
+ jwtClientId: jwtLib.jwtClientId,
36
+ /** @deprecated use jwtGetVisitorClientId */
37
+ visitorClientId: jwtLib.visitorClientId,
38
+ /** @deprecated use jwtIsExpired */
39
+ isJwtExpired: jwtLib.isJwtExpired,
40
+ /** @deprecated use jwtGetAgeInSeconds */
41
+ jwtAgeInSeconds: jwtLib.jwtAgeInSeconds,
42
+ /** @deprecated use jwtVerifyAndHasRole */
43
+ verifyJwtAndRole: jwtLib.verifyJwtAndRole,
44
+ /** @deprecated use jwtThrowUsedTokenError */
45
+ throwUsedTokenError: jwtLib.throwUsedTokenError,
46
+ /** @deprecated use jwtDoesJwtUserHasRole */
47
+ doesJwtUserHasRole: jwtLib.doesJwtUserHasRole,
48
+ /** @deprecated use jwtGetRoleName */
49
+ getNameOfRole: jwtRoles.getNameOfRoleFromCode,
50
+ /** @deprecated use jwtGetRoleCode */
51
+ getCodeOfRole: jwtRoles.getCodeFromNameOfRole,
51
52
  };
package/lib/jwtLib.js CHANGED
@@ -1,411 +1,394 @@
1
- const {isJwtString} = require('@carecard/validate').validate;
2
- const {jwtVerifySignedToken, jwtGetHeaderPayload} = require('@carecard/auth-util');
1
+ const { isJwtString } = require('@carecard/validate');
2
+ const { jwtVerifySignedToken, jwtGetHeaderPayload } = require('@carecard/auth-util');
3
3
 
4
- const {
5
- throwLoginRequiredError,
6
- throwNotAuthorizedError
7
- } = require("@carecard/common-util").error;
4
+ const { throwLoginRequiredError, throwNotAuthorizedError } = require('@carecard/common-util');
8
5
 
9
6
  function jwtClientId(req) {
10
- const jwtObj = req?.jwt || this;
11
- return jwtObj?.payload?.sub;
7
+ const jwtObj = req?.jwt || this;
8
+ return jwtObj?.payload?.sub;
12
9
  }
13
10
 
14
11
  function visitorClientId(req) {
15
- const visitorObj = req?.visitor || this;
16
- return visitorObj?.payload?.sub;
12
+ const visitorObj = req?.visitor || this;
13
+ return visitorObj?.payload?.sub;
17
14
  }
18
15
 
19
16
  function doesJwtUserHasRole(req, userRole) {
20
- // Check if called as req.jwt.doesJwtUserHasRole(userRole) or doesJwtUserHasRole(role)
21
- if (arguments.length === 1 && typeof req === 'string') {
22
- userRole = req;
23
- req = undefined;
24
- }
17
+ // Check if called as req.jwt.doesJwtUserHasRole(userRole) or doesJwtUserHasRole(role)
18
+ if (arguments.length === 1 && typeof req === 'string') {
19
+ userRole = req;
20
+ req = undefined;
21
+ }
25
22
 
26
- const jwtObj = req?.jwt || this;
23
+ const jwtObj = req?.jwt || this;
27
24
 
28
- if (!userRole || typeof userRole !== "string" || !jwtObj?.payload?.roles || !Array.isArray(jwtObj.payload.roles)) {
29
- throwNotAuthorizedError();
30
- }
25
+ if (!userRole || typeof userRole !== 'string' || !jwtObj?.payload?.roles || !Array.isArray(jwtObj.payload.roles)) {
26
+ throwNotAuthorizedError();
27
+ }
31
28
 
32
- return jwtObj.payload.roles.includes(userRole);
29
+ return jwtObj.payload.roles.includes(userRole);
33
30
  }
34
31
 
35
32
  function throwError(customErrorFunction) {
36
- (typeof customErrorFunction === "function") ?
37
- customErrorFunction() :
38
- throwLoginRequiredError()
33
+ typeof customErrorFunction === 'function' ? customErrorFunction() : throwLoginRequiredError();
39
34
  }
40
35
 
41
36
  function isJwtExpired(req, jwtValiditySeconds) {
42
- // Check if called as req.jwt.isJwtExpired(seconds) or isJwtExpired(seconds)
43
- if (arguments.length === 1 && typeof req === 'number') {
44
- jwtValiditySeconds = req;
45
- req = undefined;
46
- }
37
+ // Check if called as req.jwt.isJwtExpired(seconds) or isJwtExpired(seconds)
38
+ if (arguments.length === 1 && typeof req === 'number') {
39
+ jwtValiditySeconds = req;
40
+ req = undefined;
41
+ }
47
42
 
48
- const jwtObj = req?.jwt || this;
49
-
50
- if (jwtObj?.payload?.exp) {
51
- return (Math.floor(Date.now() / 1000)) >= jwtObj.payload.exp;
52
- }
43
+ const jwtObj = req?.jwt || this;
53
44
 
54
- if (jwtValiditySeconds && typeof jwtValiditySeconds === "number") {
55
- return (parseInt(jwtValiditySeconds)) < jwtAgeInSeconds.call(this, req);
56
- } else {
57
- return true;
58
- }
45
+ if (jwtObj?.payload?.exp) {
46
+ return Math.floor(Date.now() / 1000) >= jwtObj.payload.exp;
47
+ }
59
48
 
49
+ if (jwtValiditySeconds && typeof jwtValiditySeconds === 'number') {
50
+ return parseInt(jwtValiditySeconds) < jwtAgeInSeconds.call(this, req);
51
+ } else {
52
+ return true;
53
+ }
60
54
  }
61
55
 
62
56
  function jwtAgeInSeconds(req) {
63
- const jwtObj = req?.jwt || this;
64
-
65
- if (jwtObj?.payload?.iat) {
66
-
67
- let iat = jwtObj.payload.iat;
68
- if (iat > 1000000000000) {
69
- iat = Math.floor(iat / 1000);
70
- }
71
-
72
- jwtObj["age"] = Math.floor(Date.now() / 1000) - iat;
73
- return jwtObj.age;
74
-
75
- } else {
76
-
77
- jwtObj["age"] = Infinity
78
- return jwtObj.age;
57
+ const jwtObj = req?.jwt || this;
79
58
 
59
+ if (jwtObj?.payload?.iat) {
60
+ let iat = jwtObj.payload.iat;
61
+ if (iat > 1000000000000) {
62
+ iat = Math.floor(iat / 1000);
80
63
  }
64
+
65
+ jwtObj['age'] = Math.floor(Date.now() / 1000) - iat;
66
+ return jwtObj.age;
67
+ } else {
68
+ jwtObj['age'] = Infinity;
69
+ return jwtObj.age;
70
+ }
81
71
  }
82
72
 
83
73
  function validateAndExtractJwtObject(req, publicKey, customErrorFunction) {
74
+ const jwtString = _validateJwt(req, customErrorFunction);
84
75
 
85
- const jwtString = _validateJwt(req, customErrorFunction);
86
-
87
- const isJwtSignatureValid = jwtVerifySignedToken(jwtString, publicKey);
76
+ const isJwtSignatureValid = jwtVerifySignedToken(jwtString, publicKey);
88
77
 
89
- if (jwtString && isJwtSignatureValid) {
90
- _extractJwtObject(req, jwtString, customErrorFunction);
91
- } else {
92
- req["jwt"] = null;
93
- throwError(customErrorFunction);
94
- }
78
+ if (jwtString && isJwtSignatureValid) {
79
+ _extractJwtObject(req, jwtString, customErrorFunction);
80
+ } else {
81
+ req['jwt'] = null;
82
+ throwError(customErrorFunction);
83
+ }
95
84
 
96
- return req;
85
+ return req;
97
86
  }
98
87
 
99
88
  function validateAndExtractWebToken(req, publicKey, headerName, customErrorFunction) {
89
+ const webTokenString = _validateWebToken(req, headerName, customErrorFunction);
100
90
 
101
- const webTokenString = _validateWebToken(req, headerName, customErrorFunction);
91
+ const isJwtSignatureValid = jwtVerifySignedToken(webTokenString, publicKey);
102
92
 
103
- const isJwtSignatureValid = jwtVerifySignedToken(webTokenString, publicKey);
104
-
105
- if (webTokenString && isJwtSignatureValid) {
106
- _extractJwtObject(req, webTokenString, customErrorFunction);
107
- } else {
108
- req["jwt"] = null;
109
- throwError(customErrorFunction);
110
- }
93
+ if (webTokenString && isJwtSignatureValid) {
94
+ _extractJwtObject(req, webTokenString, customErrorFunction);
95
+ } else {
96
+ req['jwt'] = null;
97
+ throwError(customErrorFunction);
98
+ }
111
99
 
112
- return req;
100
+ return req;
113
101
  }
114
102
 
115
103
  function validateAndExtractJwtObjectNoThrow(req, publicKey) {
116
- return _validateAndExtractGenericNoThrow(req, publicKey, _validateJwtNoThrow, _extractJwtObjectNoThrow, "jwt");
104
+ return _validateAndExtractGenericNoThrow(req, publicKey, _validateJwtNoThrow, _extractJwtObjectNoThrow, 'jwt');
117
105
  }
118
106
 
119
107
  function validateAndExtractWebTokenObjectNoThrow(req, publicKey, headerName) {
120
- return _validateAndExtractGenericNoThrow(req, publicKey, (r) => _validateWebTokenNoThrow(r, headerName), _extractJwtObjectNoThrow, "jwt");
108
+ return _validateAndExtractGenericNoThrow(req, publicKey, r => _validateWebTokenNoThrow(r, headerName), _extractJwtObjectNoThrow, 'jwt');
121
109
  }
122
110
 
123
111
  function validateAndExtractVisitorObjectNoThrow(req, publicKey) {
124
- return _validateAndExtractGenericNoThrow(req, publicKey, _validateVisitorNoThrow, _extractVisitorObjectNoThrow, "visitor");
112
+ return _validateAndExtractGenericNoThrow(req, publicKey, _validateVisitorNoThrow, _extractVisitorObjectNoThrow, 'visitor');
125
113
  }
126
114
 
127
115
  function verifyJwtAndRole(role, publicKey, customErrorFunction) {
128
- return function (req, res, next) {
129
- try {
130
- validateAndExtractJwtObject(req, publicKey, customErrorFunction);
131
- const isRoleExist = doesJwtUserHasRole(req, role);
132
- _isLoginRequired(isRoleExist, customErrorFunction);
133
- next();
134
- } catch (err) {
135
- next(err);
136
- }
116
+ return function (req, res, next) {
117
+ try {
118
+ validateAndExtractJwtObject(req, publicKey, customErrorFunction);
119
+ const isRoleExist = doesJwtUserHasRole(req, role);
120
+ _isLoginRequired(isRoleExist, customErrorFunction);
121
+ next();
122
+ } catch (err) {
123
+ next(err);
137
124
  }
125
+ };
138
126
  }
139
127
 
140
128
  function verifyJwt(publicKey, customErrorFunction) {
141
- return function (req, res, next) {
142
- try {
143
- validateAndExtractJwtObject(req, publicKey, customErrorFunction);
144
- next();
145
- } catch (err) {
146
- next(err);
147
- }
129
+ return function (req, res, next) {
130
+ try {
131
+ validateAndExtractJwtObject(req, publicKey, customErrorFunction);
132
+ next();
133
+ } catch (err) {
134
+ next(err);
148
135
  }
136
+ };
149
137
  }
150
138
 
151
139
  function verifyWebToken(publicKey, headerName, customErrorFunction) {
152
- return function (req, res, next) {
153
- try {
154
- validateAndExtractWebToken(req, publicKey, headerName, customErrorFunction);
155
- next();
156
- } catch (err) {
157
- next(err);
158
- }
140
+ return function (req, res, next) {
141
+ try {
142
+ validateAndExtractWebToken(req, publicKey, headerName, customErrorFunction);
143
+ next();
144
+ } catch (err) {
145
+ next(err);
159
146
  }
147
+ };
160
148
  }
161
149
 
162
150
  function verifyJwtNoThrow(publicKey) {
163
- return function (req, res, next) {
164
- try {
165
- validateAndExtractJwtObjectNoThrow(req, publicKey);
166
- next();
167
- } catch (err) {
168
- next(err);
169
- }
151
+ return function (req, res, next) {
152
+ try {
153
+ validateAndExtractJwtObjectNoThrow(req, publicKey);
154
+ next();
155
+ } catch (err) {
156
+ next(err);
170
157
  }
158
+ };
171
159
  }
172
160
 
173
161
  function verifyWebTokenNoThrow(publicKey, headerName) {
174
- return function (req, res, next) {
175
- try {
176
- validateAndExtractWebTokenObjectNoThrow(req, publicKey, headerName);
177
- next();
178
- } catch (err) {
179
- next(err);
180
- }
162
+ return function (req, res, next) {
163
+ try {
164
+ validateAndExtractWebTokenObjectNoThrow(req, publicKey, headerName);
165
+ next();
166
+ } catch (err) {
167
+ next(err);
181
168
  }
169
+ };
182
170
  }
183
171
 
184
172
  function verifyVisitorNoThrow(publicKey) {
185
- return function (req, res, next) {
186
- try {
187
- validateAndExtractVisitorObjectNoThrow(req, publicKey);
188
- next();
189
- } catch (err) {
190
- next(err);
191
- }
173
+ return function (req, res, next) {
174
+ try {
175
+ validateAndExtractVisitorObjectNoThrow(req, publicKey);
176
+ next();
177
+ } catch (err) {
178
+ next(err);
192
179
  }
180
+ };
193
181
  }
194
182
 
195
183
  function throwUsedTokenError() {
196
- throw new Error("Used_Token");
184
+ throw new Error('Used_Token');
197
185
  }
198
186
 
199
187
  /*********************
200
188
  * Private functions *
201
189
  *********************/
202
190
  function _isLoginRequired(hasRequiredRole, customErrorFunction) {
203
-
204
- if (!hasRequiredRole) {
205
- throwError(customErrorFunction);
206
- }
207
-
191
+ if (!hasRequiredRole) {
192
+ throwError(customErrorFunction);
193
+ }
208
194
  }
209
195
 
210
196
  function _validateGenericNoThrow(req, headerName, extractor) {
211
- let jwtRaw = req.get(headerName);
212
- if (!jwtRaw) return null;
213
- let jwt = extractor(jwtRaw);
214
- return isJwtString(jwt) ? jwt : null;
197
+ let jwtRaw = req.get(headerName);
198
+ if (!jwtRaw) return null;
199
+ let jwt = extractor(jwtRaw);
200
+ return isJwtString(jwt) ? jwt : null;
215
201
  }
216
202
 
217
203
  function _validateGeneric(req, headerName, extractor, customErrorFunction) {
218
- let jwtRaw = req.get(headerName);
219
- let jwt = extractor(jwtRaw, customErrorFunction);
220
- if (isJwtString(jwt)) return jwt;
221
- throwError(customErrorFunction);
222
- return null;
204
+ let jwtRaw = req.get(headerName);
205
+ let jwt = extractor(jwtRaw, customErrorFunction);
206
+ if (isJwtString(jwt)) return jwt;
207
+ throwError(customErrorFunction);
208
+ return null;
223
209
  }
224
210
 
225
211
  function _validateAndExtractGenericNoThrow(req, publicKey, validator, extractor, propertyName) {
226
- try {
227
- const jwtString = validator(req);
228
- const isJwtSignatureValid = jwtVerifySignedToken(jwtString, publicKey);
229
-
230
- if (jwtString && isJwtSignatureValid) {
231
- extractor(req, jwtString);
232
- } else {
233
- req[propertyName] = null;
234
- }
235
- } catch (err) {
236
- if (req) req[propertyName] = null;
237
- throw err;
212
+ try {
213
+ const jwtString = validator(req);
214
+ const isJwtSignatureValid = jwtVerifySignedToken(jwtString, publicKey);
215
+
216
+ if (jwtString && isJwtSignatureValid) {
217
+ extractor(req, jwtString);
218
+ } else {
219
+ req[propertyName] = null;
238
220
  }
239
- return req;
221
+ } catch (err) {
222
+ if (req) req[propertyName] = null;
223
+ throw err;
224
+ }
225
+ return req;
240
226
  }
241
227
 
242
228
  function _extractGenericObjectNoThrow(req, jwt, attacher, propertyName) {
243
- if (jwt && typeof jwt === "string") {
244
- const obj = jwtGetHeaderPayload(jwt);
245
- attacher(obj);
246
- req[propertyName] = obj;
247
- } else {
248
- if (req) req[propertyName] = null;
249
- }
229
+ if (jwt && typeof jwt === 'string') {
230
+ const obj = jwtGetHeaderPayload(jwt);
231
+ attacher(obj);
232
+ req[propertyName] = obj;
233
+ } else {
234
+ if (req) req[propertyName] = null;
235
+ }
250
236
  }
251
237
 
252
238
  function _extractJwtObject(req, jwt, customErrorFunction) {
253
- _extractJwtObjectNoThrow(req, jwt);
239
+ _extractJwtObjectNoThrow(req, jwt);
254
240
 
255
- if (!req["jwt"]) {
256
- throwError(customErrorFunction);
257
- }
241
+ if (!req['jwt']) {
242
+ throwError(customErrorFunction);
243
+ }
258
244
  }
259
245
 
260
246
  function _extractJwtObjectNoThrow(req, jwt) {
261
- _extractGenericObjectNoThrow(req, jwt, _attachJwtMethods, "jwt");
247
+ _extractGenericObjectNoThrow(req, jwt, _attachJwtMethods, 'jwt');
262
248
  }
263
249
 
264
250
  function _extractVisitorObjectNoThrow(req, jwt) {
265
- _extractGenericObjectNoThrow(req, jwt, _attachVisitorMethods, "visitor");
251
+ _extractGenericObjectNoThrow(req, jwt, _attachVisitorMethods, 'visitor');
266
252
  }
267
253
 
268
254
  function _attachJwtMethods(jwtObj) {
269
- if (jwtObj) {
270
- Object.defineProperties(jwtObj, {
271
- jwtClientId: {value: jwtClientId, enumerable: false},
272
- doesJwtUserHasRole: {value: doesJwtUserHasRole, enumerable: false},
273
- isJwtExpired: {value: isJwtExpired, enumerable: false},
274
- jwtAgeInSeconds: {value: jwtAgeInSeconds, enumerable: false}
275
- });
276
- }
255
+ if (jwtObj) {
256
+ Object.defineProperties(jwtObj, {
257
+ jwtClientId: { value: jwtClientId, enumerable: false },
258
+ doesJwtUserHasRole: { value: doesJwtUserHasRole, enumerable: false },
259
+ isJwtExpired: { value: isJwtExpired, enumerable: false },
260
+ jwtAgeInSeconds: { value: jwtAgeInSeconds, enumerable: false },
261
+ });
262
+ }
277
263
  }
278
264
 
279
265
  function _attachVisitorMethods(visitorObj) {
280
- if (visitorObj) {
281
- Object.defineProperties(visitorObj, {
282
- visitorClientId: {value: visitorClientId, enumerable: false}
283
- });
284
- }
266
+ if (visitorObj) {
267
+ Object.defineProperties(visitorObj, {
268
+ visitorClientId: { value: visitorClientId, enumerable: false },
269
+ });
270
+ }
285
271
  }
286
272
 
287
273
  async function _isJwtSignatureValid(jwt, publicKey, customErrorFunction) {
274
+ const isValid = await _isJwtSignatureValidNoThrow(jwt, publicKey);
288
275
 
289
- const isValid = await _isJwtSignatureValidNoThrow(jwt, publicKey);
290
-
291
- if (isValid) {
292
- return isValid;
293
- } else {
294
- throwError(customErrorFunction);
295
- }
276
+ if (isValid) {
277
+ return isValid;
278
+ } else {
279
+ throwError(customErrorFunction);
280
+ }
296
281
  }
297
282
 
298
283
  async function _isJwtSignatureValidNoThrow(jwt, publicKey) {
299
-
300
- if (jwt && typeof jwt === "string") {
301
- return jwtVerifySignedToken(jwt, publicKey)
302
- } else {
303
- return false;
304
- }
284
+ if (jwt && typeof jwt === 'string') {
285
+ return jwtVerifySignedToken(jwt, publicKey);
286
+ } else {
287
+ return false;
288
+ }
305
289
  }
306
290
 
307
291
  function _validateJwt(req, customErrorFunction) {
308
- return _validateGeneric(req, "Authorization", _extractJwt, customErrorFunction);
292
+ return _validateGeneric(req, 'Authorization', _extractJwt, customErrorFunction);
309
293
  }
310
294
 
311
295
  function _validateWebToken(req, headerName, customErrorFunction) {
312
- return _validateGeneric(req, headerName, _extractWebToken, customErrorFunction);
296
+ return _validateGeneric(req, headerName, _extractWebToken, customErrorFunction);
313
297
  }
314
298
 
315
299
  function _validateJwtNoThrow(req) {
316
- return _validateGenericNoThrow(req, "Authorization", _extractJwtNoThrow);
300
+ return _validateGenericNoThrow(req, 'Authorization', _extractJwtNoThrow);
317
301
  }
318
302
 
319
303
  function _validateWebTokenNoThrow(req, headerName) {
320
- return _validateGenericNoThrow(req, headerName, _extractWebTokenNoThrow);
304
+ return _validateGenericNoThrow(req, headerName, _extractWebTokenNoThrow);
321
305
  }
322
306
 
323
307
  function _validateVisitorNoThrow(req) {
324
- return _validateGenericNoThrow(req, "Visitor", _extractJwtNoThrow);
308
+ return _validateGenericNoThrow(req, 'Visitor', _extractJwtNoThrow);
325
309
  }
326
310
 
327
311
  function _extractJwt(jwtRaw, customErrorFunction) {
328
- const jwt = _extractJwtNoThrow(jwtRaw);
312
+ const jwt = _extractJwtNoThrow(jwtRaw);
329
313
 
330
- if (jwt !== null) {
331
- return jwt;
332
- } else {
333
- throwError(customErrorFunction);
334
- }
314
+ if (jwt !== null) {
315
+ return jwt;
316
+ } else {
317
+ throwError(customErrorFunction);
318
+ }
335
319
 
336
- return null;
320
+ return null;
337
321
  }
338
322
 
339
323
  function _extractWebToken(jwtRaw, customErrorFunction) {
340
- const webToken = _extractWebTokenNoThrow(jwtRaw);
324
+ const webToken = _extractWebTokenNoThrow(jwtRaw);
341
325
 
342
- if (webToken !== null) {
343
- return webToken;
344
- } else {
345
- throwError(customErrorFunction);
346
- }
326
+ if (webToken !== null) {
327
+ return webToken;
328
+ } else {
329
+ throwError(customErrorFunction);
330
+ }
347
331
 
348
- return null;
332
+ return null;
349
333
  }
350
334
 
351
335
  function _extractJwtNoThrow(jwtRaw) {
352
- let jwtSplit = null;
336
+ let jwtSplit = null;
353
337
 
354
- if (jwtRaw && typeof jwtRaw === "string") {
355
- jwtSplit = jwtRaw.split(" ");
356
- } else {
357
- return null;
358
- }
338
+ if (jwtRaw && typeof jwtRaw === 'string') {
339
+ jwtSplit = jwtRaw.split(' ');
340
+ } else {
341
+ return null;
342
+ }
359
343
 
360
- if (jwtSplit[0]?.toLowerCase() === "bearer") {
361
- return jwtSplit[1];
362
- }
344
+ if (jwtSplit[0]?.toLowerCase() === 'bearer') {
345
+ return jwtSplit[1];
346
+ }
363
347
 
364
- return null;
348
+ return null;
365
349
  }
366
350
 
367
351
  function _extractWebTokenNoThrow(jwtRaw) {
368
-
369
- if (jwtRaw && typeof jwtRaw === "string") {
370
- return jwtRaw;
371
- }
372
- return null;
352
+ if (jwtRaw && typeof jwtRaw === 'string') {
353
+ return jwtRaw;
354
+ }
355
+ return null;
373
356
  }
374
357
 
375
358
  module.exports = {
376
- _validateJwt,
377
- _validateJwtNoThrow,
378
- _isJwtSignatureValid,
379
- _isJwtSignatureValidNoThrow,
380
- _extractJwtObject,
381
- validateAndExtractJwtObject,
382
- validateAndExtractWebToken,
383
- jwtAgeInSeconds,
384
- isJwtExpired,
385
- doesJwtUserHasRole,
386
- jwtClientId,
387
- visitorClientId,
388
- verifyJwtAndRole,
389
- verifyJwt,
390
- verifyWebTokenNoThrow,
391
- verifyWebToken,
392
- verifyJwtNoThrow,
393
- throwUsedTokenError,
394
- throwError,
395
- verifyVisitorNoThrow,
396
- validateAndExtractVisitorObjectNoThrow,
397
- validateAndExtractJwtObjectNoThrow,
398
- validateAndExtractWebTokenObjectNoThrow,
399
- _extractJwtNoThrow,
400
- _extractWebTokenNoThrow,
401
- _extractJwt,
402
- _validateWebTokenNoThrow,
403
- _validateVisitorNoThrow,
404
- _extractJwtObjectNoThrow,
405
- _extractVisitorObjectNoThrow,
406
- _extractWebToken,
407
- _isLoginRequired,
408
- _attachJwtMethods,
409
- _attachVisitorMethods,
410
- _validateWebToken
411
- }
359
+ _validateJwt,
360
+ _validateJwtNoThrow,
361
+ _isJwtSignatureValid,
362
+ _isJwtSignatureValidNoThrow,
363
+ _extractJwtObject,
364
+ validateAndExtractJwtObject,
365
+ validateAndExtractWebToken,
366
+ jwtAgeInSeconds,
367
+ isJwtExpired,
368
+ doesJwtUserHasRole,
369
+ jwtClientId,
370
+ visitorClientId,
371
+ verifyJwtAndRole,
372
+ verifyJwt,
373
+ verifyWebTokenNoThrow,
374
+ verifyWebToken,
375
+ verifyJwtNoThrow,
376
+ throwUsedTokenError,
377
+ throwError,
378
+ verifyVisitorNoThrow,
379
+ validateAndExtractVisitorObjectNoThrow,
380
+ validateAndExtractJwtObjectNoThrow,
381
+ validateAndExtractWebTokenObjectNoThrow,
382
+ _extractJwtNoThrow,
383
+ _extractWebTokenNoThrow,
384
+ _extractJwt,
385
+ _validateWebTokenNoThrow,
386
+ _validateVisitorNoThrow,
387
+ _extractJwtObjectNoThrow,
388
+ _extractVisitorObjectNoThrow,
389
+ _extractWebToken,
390
+ _isLoginRequired,
391
+ _attachJwtMethods,
392
+ _attachVisitorMethods,
393
+ _validateWebToken,
394
+ };
package/lib/jwtRoles.js CHANGED
@@ -1,20 +1,39 @@
1
+ const { jwtClientId } = require('./jwtLib');
2
+
1
3
  module.exports = {
2
- getNameOfRoleFromCode,
3
- getCodeFromNameOfRole,
4
+ getNameOfRoleFromCode,
5
+ getCodeFromNameOfRole,
6
+ getContext,
7
+ };
8
+
9
+ function getNameOfRoleFromCode(roleCode) {
10
+ const codesToCategory = {
11
+ ad: 'admin',
12
+ su: 'super_admin',
13
+ };
14
+ return codesToCategory[roleCode] || '';
4
15
  }
5
16
 
6
- function getNameOfRoleFromCode( roleCode ) {
7
- const codesToCategory = {
8
- "ad": "admin",
9
- "su": "super_admin",
10
- };
11
- return codesToCategory[ roleCode ] || "";
17
+ function getCodeFromNameOfRole(roleName) {
18
+ const namesToCode = {
19
+ admin: 'ad',
20
+ super_admin: 'su',
21
+ };
22
+ return namesToCode[roleName] || '';
12
23
  }
13
24
 
14
- function getCodeFromNameOfRole( roleName ) {
15
- const namesToCode = {
16
- "admin": "ad",
17
- "super_admin": "su",
25
+ function getContext(req) {
26
+ const userId = jwtClientId(req);
27
+ const roles = req.jwt?.payload?.roles;
28
+
29
+ if (Array.isArray(roles) && roles.includes('ad')) {
30
+ return {
31
+ user_id: userId,
32
+ role: 'super_admin',
18
33
  };
19
- return namesToCode[ roleName ] || "";
34
+ }
35
+
36
+ return {
37
+ user_id: userId,
38
+ };
20
39
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@carecard/jwt-read",
3
- "version": "3.1.13",
3
+ "version": "3.1.14",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/CareCard-ca/pkg-jwt-read.git"
@@ -9,10 +9,15 @@
9
9
  "main": "index.js",
10
10
  "types": "index.d.ts",
11
11
  "scripts": {
12
- "test": "export NODE_ENV=test && mocha --recursive",
12
+ "test": "mocha --recursive",
13
13
  "test:types": "tsc --noEmit && mocha -r ts-node/register test/types.test.ts",
14
- "test:coverage": "tsc --noEmit && export NODE_ENV=test && nyc mocha --recursive -r ts-node/register 'test/**/*.{js,ts}'",
15
- "prepare": "husky"
14
+ "test:coverage": "tsc --noEmit && nyc mocha --recursive -r ts-node/register 'test/**/*.{js,ts}'",
15
+ "test:All": "npm run test && npm run test:types",
16
+ "format": "prettier --write .",
17
+ "format:check": "prettier --check .",
18
+ "prepare": "husky",
19
+ "lint:fix": "eslint --fix",
20
+ "lint": "eslint"
16
21
  },
17
22
  "keywords": [
18
23
  "auth",
@@ -25,16 +30,19 @@
25
30
  "devDependencies": {
26
31
  "@types/express": "5.0.6",
27
32
  "@types/mocha": "10.0.10",
28
- "@types/node": "25.5.0",
29
- "husky": "^9.1.7",
33
+ "@types/node": "25.6.2",
34
+ "eslint": "9.39.4",
35
+ "husky": "9.1.7",
36
+ "lint-staged": "17.0.3",
30
37
  "mocha": "11.7.5",
31
- "nyc": "^18.0.0",
38
+ "nyc": "18.0.0",
39
+ "prettier": "3.8.3",
32
40
  "ts-node": "10.9.2",
33
41
  "typescript": "5.9.3"
34
42
  },
35
43
  "dependencies": {
36
- "@carecard/common-util": "3.1.11",
37
- "@carecard/auth-util": "3.1.12",
38
- "@carecard/validate": "3.0.10"
44
+ "@carecard/common-util": "3.1.13",
45
+ "@carecard/auth-util": "3.1.13",
46
+ "@carecard/validate": "3.1.16"
39
47
  }
40
48
  }
package/readme.md CHANGED
@@ -31,11 +31,11 @@ const verifyAdmin = verifyJwtAndRole('admin', publicKey, throwUsedTokenError);
31
31
 
32
32
  // In an Express controller/middleware
33
33
  try {
34
- await verifyAdmin(req, res, next);
35
- // If successful, req.jwt contains { header, payload }
36
- console.log(req.jwt.payload.sub);
34
+ await verifyAdmin(req, res, next);
35
+ // If successful, req.jwt contains { header, payload }
36
+ console.log(req.jwt.payload.sub);
37
37
  } catch (error) {
38
- // Handle verification error
38
+ // Handle verification error
39
39
  }
40
40
  ```
41
41
 
@@ -46,7 +46,7 @@ const { verifyJwt, isJwtExpired } = require('@carecard/jwt-read');
46
46
 
47
47
  const result = verifyJwt(rawJwt, publicKey);
48
48
  if (result && !isJwtExpired(result)) {
49
- console.log('JWT is valid and not expired:', result.payload);
49
+ console.log('JWT is valid and not expired:', result.payload);
50
50
  }
51
51
  ```
52
52
 
@@ -82,6 +82,7 @@ npm run test:types
82
82
  ## Architecture
83
83
 
84
84
  The package is organized into several modules:
85
+
85
86
  - `jwtLib`: Main logic for JWT verification, extraction, and Express integration.
86
87
  - `jwtRoles`: Role mapping between internal codes and names.
87
88