@carecard/jwt-read 3.0.11 → 3.1.13

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/index.d.ts CHANGED
@@ -1,25 +1,56 @@
1
1
  /**
2
- * Utility functions for reading and verifying JWTs.
2
+ * Utility functions for authentication and authorization in the CareCard ecosystem.
3
3
  */
4
4
 
5
5
  import { Request, Response, NextFunction } from 'express';
6
6
 
7
7
  /**
8
- * Basic structure of a JWT payload as used in this package.
8
+ * Represents the standard JWT header structure.
9
+ */
10
+ export interface JwtHeader {
11
+ /** The cryptographic algorithm used to secure the JWT. */
12
+ alg?: string;
13
+ /** The media type of the JWT. Defaults to 'JWT'. */
14
+ typ?: string;
15
+ /** Any other custom header fields. */
16
+ [key: string]: any;
17
+ }
18
+
19
+ /**
20
+ * Represents the standard JWT payload (claims) structure.
9
21
  */
10
22
  export interface JwtPayload {
11
- sub?: string;
12
- exp?: number;
13
- iat?: number;
14
- roles?: string[];
15
- [key: string]: any;
23
+ /** Issued at time, in seconds since the epoch. */
24
+ iat?: number;
25
+ /** Expiration time, in seconds since the epoch. */
26
+ exp?: number;
27
+ /** Not before time, in seconds since the epoch. */
28
+ nbf?: number;
29
+ /** Authentication time, in seconds since the epoch. */
30
+ auth_time?: number;
31
+ /** Subject (usually the client ID). */
32
+ sub?: string;
33
+ /** Roles assigned to the user. */
34
+ roles?: string[];
35
+ /** Any other custom payload fields. */
36
+ [key: string]: any;
37
+ }
38
+
39
+ /**
40
+ * Container for the decoded header and payload of a JWT.
41
+ */
42
+ export interface JwtParts {
43
+ /** Decoded JWT header. */
44
+ header: JwtHeader;
45
+ /** Decoded JWT payload. */
46
+ payload: JwtPayload;
16
47
  }
17
48
 
18
49
  /**
19
50
  * Structure of the JWT object attached to the request.
20
51
  */
21
52
  export interface JwtRequestObject {
22
- header: any;
53
+ header: JwtHeader;
23
54
  payload: JwtPayload;
24
55
  age?: number;
25
56
  jwtClientId: (req?: any) => string | undefined;
@@ -32,7 +63,7 @@ export interface JwtRequestObject {
32
63
  * Structure of the visitor object attached to the request.
33
64
  */
34
65
  export interface VisitorRequestObject {
35
- header: any;
66
+ header: JwtHeader;
36
67
  payload: JwtPayload;
37
68
  visitorClientId: (req?: any) => string | undefined;
38
69
  }
@@ -45,78 +76,194 @@ export interface AuthenticatedRequest extends Request {
45
76
  visitor?: VisitorRequestObject | null;
46
77
  }
47
78
 
79
+
48
80
  /**
49
81
  * Returns a middleware that verifies a JWT from the 'Authorization: Bearer <token>' header
50
82
  * and extracts it into req.jwt. Throws an error if invalid.
51
83
  */
84
+ export function jwtVerify(publicKey: string, customErrorFunction?: () => void): (req: AuthenticatedRequest, res: Response, next: NextFunction) => void;
85
+
86
+ /**
87
+ * Returns a middleware that verifies a JWT from a custom header and extracts it into req.jwt.
88
+ * Throws an error if invalid.
89
+ */
90
+ export function jwtVerifyWebToken(publicKey: string, headerName: string, customErrorFunction?: () => void): (req: AuthenticatedRequest, res: Response, next: NextFunction) => void;
91
+
92
+ /**
93
+ * Returns a middleware that verifies a JWT from the 'Authorization: Bearer <token>' header
94
+ * and extracts it into req.jwt. Returns false instead of throwing if invalid.
95
+ */
96
+ export function jwtVerifyNoThrow(publicKey: string): (req: AuthenticatedRequest, res: Response, next: NextFunction) => void;
97
+
98
+ /**
99
+ * Returns a middleware that verifies a JWT from a custom header and extracts it into req.jwt.
100
+ * Returns false instead of throwing if invalid.
101
+ */
102
+ export function jwtVerifyWebTokenNoThrow(publicKey: string, headerName: string): (req: AuthenticatedRequest, res: Response, next: NextFunction) => void;
103
+
104
+ /**
105
+ * Returns a middleware that verifies a visitor token from the 'Visitor' header
106
+ * and extracts it into req.visitor. Returns false instead of throwing if invalid.
107
+ */
108
+ export function jwtVerifyVisitorNoThrow(publicKey: string): (req: AuthenticatedRequest, res: Response, next: NextFunction) => void;
109
+
110
+ /**
111
+ * Returns the sub from the extracted JWT in req.jwt.
112
+ */
113
+ export function jwtGetClientId(req?: any): string | undefined;
114
+
115
+ /**
116
+ * Returns the sub from the extracted visitor token in req.visitor.
117
+ */
118
+ export function jwtGetVisitorClientId(req?: any): string | undefined;
119
+
120
+ /**
121
+ * Checks if the extracted JWT in req.jwt has expired.
122
+ */
123
+ export function jwtIsExpired(req: any, jwtValiditySeconds?: number): boolean;
124
+ export function jwtIsExpired(jwtValiditySeconds: number): boolean;
125
+ export function jwtIsExpired(): boolean;
126
+
127
+ /**
128
+ * Returns the age of the extracted JWT in seconds.
129
+ */
130
+ export function jwtGetAgeInSeconds(req?: any): number;
131
+
132
+ /**
133
+ * Returns a middleware that verifies the JWT and checks if the user has the required role.
134
+ */
135
+ export function jwtVerifyAndHasRole(userRole: string, publicKey: string, customErrorFunction?: () => void): (req: AuthenticatedRequest, res: Response, next: NextFunction) => void;
136
+
137
+ /**
138
+ * Gets the full name of a role from its code (e.g., 'ad' -> 'admin').
139
+ */
140
+ export function jwtGetRoleName(roleCode: string): string;
141
+
142
+ /**
143
+ * Gets the code of a role from its name (e.g., 'admin' -> 'ad').
144
+ */
145
+ export function jwtGetRoleCode(roleName: string): string;
146
+
147
+ /**
148
+ * Validates the JWT from the Authorization header and extracts it into req.jwt.
149
+ */
150
+ export function jwtValidateAndExtract(req: AuthenticatedRequest, publicKey: string, customErrorFunction?: () => void): void;
151
+
152
+ /**
153
+ * Validates the JWT from a custom header and extracts it into req.jwt.
154
+ */
155
+ export function jwtValidateAndExtractWebToken(req: AuthenticatedRequest, publicKey: string, headerName: string, customErrorFunction?: () => void): void;
156
+
157
+ /**
158
+ * Validates the JWT from the Authorization header and extracts it into req.jwt (no-throw).
159
+ */
160
+ export function jwtValidateAndExtractNoThrow(req: AuthenticatedRequest, publicKey: string): void;
161
+
162
+ /**
163
+ * Validates the JWT from a custom header and extracts it into req.jwt (no-throw).
164
+ */
165
+ export function jwtValidateAndExtractWebTokenNoThrow(req: AuthenticatedRequest, publicKey: string, headerName: string): void;
166
+
167
+ /**
168
+ * Validates the visitor token from the 'Visitor' header and extracts it into req.visitor (no-throw).
169
+ */
170
+ export function jwtValidateAndExtractVisitorNoThrow(req: AuthenticatedRequest, publicKey: string): void;
171
+
172
+
173
+ /**
174
+ * Returns a middleware that verifies a JWT from the 'Authorization: Bearer <token>' header
175
+ * and extracts it into req.jwt. Throws an error if invalid.
176
+ * @deprecated use jwtVerify
177
+ */
52
178
  export function verifyJwt(publicKey: string, customErrorFunction?: () => void): (req: AuthenticatedRequest, res: Response, next: NextFunction) => void;
53
179
 
54
180
  /**
55
181
  * Returns a middleware that verifies a JWT from a custom header and extracts it into req.jwt.
56
182
  * Throws an error if invalid.
183
+ * @deprecated use jwtVerifyWebToken
57
184
  */
58
185
  export function verifyWebToken(publicKey: string, headerName: string, customErrorFunction?: () => void): (req: AuthenticatedRequest, res: Response, next: NextFunction) => void;
59
186
 
60
187
  /**
61
188
  * Returns a middleware that verifies a JWT from the 'Authorization: Bearer <token>' header
62
189
  * and extracts it into req.jwt. Returns false instead of throwing if invalid.
190
+ * @deprecated use jwtVerifyNoThrow
63
191
  */
64
192
  export function verifyJwtNoThrow(publicKey: string): (req: AuthenticatedRequest, res: Response, next: NextFunction) => void;
65
193
 
66
194
  /**
67
195
  * Returns a middleware that verifies a JWT from a custom header and extracts it into req.jwt.
68
196
  * Returns false instead of throwing if invalid.
197
+ * @deprecated use jwtVerifyWebTokenNoThrow
69
198
  */
70
199
  export function verifyWebTokenNoThrow(publicKey: string, headerName: string): (req: AuthenticatedRequest, res: Response, next: NextFunction) => void;
71
200
 
72
201
  /**
73
202
  * Returns a middleware that verifies a visitor token from the 'Visitor' header
74
203
  * and extracts it into req.visitor. Returns false instead of throwing if invalid.
204
+ * @deprecated use jwtVerifyVisitorNoThrow
75
205
  */
76
206
  export function verifyVisitorNoThrow(publicKey: string): (req: AuthenticatedRequest, res: Response, next: NextFunction) => void;
77
207
 
78
208
  /**
79
209
  * Returns the sub from the extracted JWT in req.jwt.
210
+ * @deprecated use jwtGetClientId
80
211
  */
81
212
  export function jwtClientId(req?: any): string | undefined;
82
213
 
83
214
  /**
84
215
  * Returns the sub from the extracted visitor token in req.visitor.
216
+ * @deprecated use jwtGetVisitorClientId
85
217
  */
86
218
  export function visitorClientId(req?: any): string | undefined;
87
219
 
88
220
  /**
89
221
  * Checks if the extracted JWT in req.jwt has expired.
222
+ * @deprecated use jwtIsExpired
90
223
  */
91
- export function isJwtExpired(req?: any, jwtValiditySeconds?: number): boolean;
224
+ export function isJwtExpired(req: any, jwtValiditySeconds?: number): boolean;
225
+ /** @deprecated use jwtIsExpired */
226
+ export function isJwtExpired(jwtValiditySeconds: number): boolean;
227
+ /** @deprecated use jwtIsExpired */
228
+ export function isJwtExpired(): boolean;
92
229
 
93
230
  /**
94
231
  * Returns the age of the extracted JWT in seconds.
232
+ * @deprecated use jwtGetAgeInSeconds
95
233
  */
96
234
  export function jwtAgeInSeconds(req?: any): number;
97
235
 
98
236
  /**
99
237
  * Returns a middleware that verifies the JWT and checks if the user has the required role.
238
+ * @deprecated use jwtVerifyAndHasRole
100
239
  */
101
240
  export function verifyJwtAndRole(userRole: string, publicKey: string, customErrorFunction?: () => void): (req: AuthenticatedRequest, res: Response, next: NextFunction) => void;
102
241
 
103
242
  /**
104
243
  * Throws a Used_Token error.
244
+ * @deprecated use jwtThrowUsedTokenError
105
245
  */
106
246
  export function throwUsedTokenError(): never;
107
247
 
248
+
108
249
  /**
109
250
  * Checks if the user in the extracted JWT has the specified role.
251
+ * @deprecated use jwtDoesJwtUserHasRole
110
252
  */
111
253
  export function doesJwtUserHasRole(req: any, userRole: string): boolean;
254
+ /** @deprecated use jwtDoesJwtUserHasRole */
112
255
  export function doesJwtUserHasRole(userRole: string): boolean;
113
256
 
114
257
  /**
115
258
  * Gets the full name of a role from its code (e.g., 'ad' -> 'admin').
259
+ * @deprecated use jwtGetRoleName
116
260
  */
117
261
  export function getNameOfRole(roleCode: string): string;
118
262
 
263
+
119
264
  /**
120
265
  * Gets the code of a role from its name (e.g., 'admin' -> 'ad').
266
+ * @deprecated use jwtGetRoleCode
121
267
  */
122
268
  export function getCodeOfRole(roleName: string): string;
269
+
package/index.js CHANGED
@@ -1,21 +1,51 @@
1
- const jwtLib = require( './lib/jwtLib' );
2
- const jwtRoles = require( './lib/jwtRoles' );
3
-
1
+ const jwtLib = require('./lib/jwtLib');
2
+ const jwtRoles = require('./lib/jwtRoles');
4
3
 
5
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,
22
+
23
+ /** @deprecated use jwtVerify */
6
24
  verifyJwt: jwtLib.verifyJwt,
25
+ /** @deprecated use jwtVerifyWebToken */
7
26
  verifyWebToken: jwtLib.verifyWebToken,
27
+ /** @deprecated use jwtVerifyNoThrow */
8
28
  verifyJwtNoThrow: jwtLib.verifyJwtNoThrow,
29
+ /** @deprecated use jwtVerifyWebTokenNoThrow */
9
30
  verifyWebTokenNoThrow: jwtLib.verifyWebTokenNoThrow,
31
+ /** @deprecated use jwtVerifyVisitorNoThrow */
10
32
  verifyVisitorNoThrow: jwtLib.verifyVisitorNoThrow,
33
+ /** @deprecated use jwtGetClientId */
11
34
  jwtClientId: jwtLib.jwtClientId,
35
+ /** @deprecated use jwtGetVisitorClientId */
12
36
  visitorClientId: jwtLib.visitorClientId,
37
+ /** @deprecated use jwtIsExpired */
13
38
  isJwtExpired: jwtLib.isJwtExpired,
39
+ /** @deprecated use jwtGetAgeInSeconds */
14
40
  jwtAgeInSeconds: jwtLib.jwtAgeInSeconds,
41
+ /** @deprecated use jwtVerifyAndHasRole */
15
42
  verifyJwtAndRole: jwtLib.verifyJwtAndRole,
43
+ /** @deprecated use jwtThrowUsedTokenError */
16
44
  throwUsedTokenError: jwtLib.throwUsedTokenError,
45
+ /** @deprecated use jwtDoesJwtUserHasRole */
17
46
  doesJwtUserHasRole: jwtLib.doesJwtUserHasRole,
47
+ /** @deprecated use jwtGetRoleName */
18
48
  getNameOfRole: jwtRoles.getNameOfRoleFromCode,
49
+ /** @deprecated use jwtGetRoleCode */
19
50
  getCodeOfRole: jwtRoles.getCodeFromNameOfRole
20
51
  };
21
-
package/lib/jwtLib.js CHANGED
@@ -1,5 +1,6 @@
1
1
  const {isJwtString} = require('@carecard/validate').validate;
2
- const {jwtUtilAuth} = require('@carecard/auth-util');
2
+ const {jwtVerifySignedToken, jwtGetHeaderPayload} = require('@carecard/auth-util');
3
+
3
4
  const {
4
5
  throwLoginRequiredError,
5
6
  throwNotAuthorizedError
@@ -24,11 +25,11 @@ function doesJwtUserHasRole(req, userRole) {
24
25
 
25
26
  const jwtObj = req?.jwt || this;
26
27
 
27
- if (userRole && typeof userRole === "string") {
28
- return jwtObj?.payload?.roles?.includes(userRole);
29
- } else {
28
+ if (!userRole || typeof userRole !== "string" || !jwtObj?.payload?.roles || !Array.isArray(jwtObj.payload.roles)) {
30
29
  throwNotAuthorizedError();
31
30
  }
31
+
32
+ return jwtObj.payload.roles.includes(userRole);
32
33
  }
33
34
 
34
35
  function throwError(customErrorFunction) {
@@ -83,7 +84,7 @@ function validateAndExtractJwtObject(req, publicKey, customErrorFunction) {
83
84
 
84
85
  const jwtString = _validateJwt(req, customErrorFunction);
85
86
 
86
- const isJwtSignatureValid = jwtUtilAuth.verifyJwtSignature(jwtString, publicKey);
87
+ const isJwtSignatureValid = jwtVerifySignedToken(jwtString, publicKey);
87
88
 
88
89
  if (jwtString && isJwtSignatureValid) {
89
90
  _extractJwtObject(req, jwtString, customErrorFunction);
@@ -99,7 +100,7 @@ function validateAndExtractWebToken(req, publicKey, headerName, customErrorFunct
99
100
 
100
101
  const webTokenString = _validateWebToken(req, headerName, customErrorFunction);
101
102
 
102
- const isJwtSignatureValid = jwtUtilAuth.verifyJwtSignature(webTokenString, publicKey);
103
+ const isJwtSignatureValid = jwtVerifySignedToken(webTokenString, publicKey);
103
104
 
104
105
  if (webTokenString && isJwtSignatureValid) {
105
106
  _extractJwtObject(req, webTokenString, customErrorFunction);
@@ -112,72 +113,15 @@ function validateAndExtractWebToken(req, publicKey, headerName, customErrorFunct
112
113
  }
113
114
 
114
115
  function validateAndExtractJwtObjectNoThrow(req, publicKey) {
115
-
116
- try {
117
-
118
- const jwtString = _validateJwtNoThrow(req);
119
-
120
- const isJwtSignatureValid = jwtUtilAuth.verifyJwtSignature(jwtString, publicKey);
121
-
122
- if (jwtString && isJwtSignatureValid) {
123
- _extractJwtObjectNoThrow(req, jwtString);
124
- } else {
125
- req["jwt"] = null;
126
- }
127
-
128
- } catch (err) {
129
-
130
- req["jwt"] = null;
131
-
132
- }
133
-
134
- return req;
116
+ return _validateAndExtractGenericNoThrow(req, publicKey, _validateJwtNoThrow, _extractJwtObjectNoThrow, "jwt");
135
117
  }
136
118
 
137
119
  function validateAndExtractWebTokenObjectNoThrow(req, publicKey, headerName) {
138
-
139
- try {
140
-
141
- const jwtString = _validateWebTokenNoThrow(req, headerName);
142
-
143
- const isJwtSignatureValid = jwtUtilAuth.verifyJwtSignature(jwtString, publicKey);
144
-
145
- if (jwtString && isJwtSignatureValid) {
146
- _extractJwtObjectNoThrow(req, jwtString);
147
- } else {
148
- req["jwt"] = null;
149
- }
150
-
151
- } catch (err) {
152
-
153
- req["jwt"] = null;
154
-
155
- }
156
-
157
- return req;
120
+ return _validateAndExtractGenericNoThrow(req, publicKey, (r) => _validateWebTokenNoThrow(r, headerName), _extractJwtObjectNoThrow, "jwt");
158
121
  }
159
122
 
160
123
  function validateAndExtractVisitorObjectNoThrow(req, publicKey) {
161
-
162
- try {
163
-
164
- const jwtString = _validateVisitorNoThrow(req);
165
-
166
- const isJwtSignatureValid = jwtUtilAuth.verifyJwtSignature(jwtString, publicKey);
167
-
168
- if (jwtString && isJwtSignatureValid) {
169
- _extractVisitorObjectNoThrow(req, jwtString);
170
- } else {
171
- req["visitor"] = null;
172
- }
173
-
174
- } catch (err) {
175
-
176
- req["visitor"] = null;
177
-
178
- }
179
-
180
- return req;
124
+ return _validateAndExtractGenericNoThrow(req, publicKey, _validateVisitorNoThrow, _extractVisitorObjectNoThrow, "visitor");
181
125
  }
182
126
 
183
127
  function verifyJwtAndRole(role, publicKey, customErrorFunction) {
@@ -263,34 +207,62 @@ function _isLoginRequired(hasRequiredRole, customErrorFunction) {
263
207
 
264
208
  }
265
209
 
266
- function _extractJwtObject(req, jwt, customErrorFunction) {
210
+ 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;
215
+ }
216
+
217
+ 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;
223
+ }
224
+
225
+ 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;
238
+ }
239
+ return req;
240
+ }
241
+
242
+ function _extractGenericObjectNoThrow(req, jwt, attacher, propertyName) {
267
243
  if (jwt && typeof jwt === "string") {
268
- const jwtObj = jwtUtilAuth.getHeaderPayloadFromJwt(jwt);
269
- _attachJwtMethods(jwtObj);
270
- req["jwt"] = jwtObj;
244
+ const obj = jwtGetHeaderPayload(jwt);
245
+ attacher(obj);
246
+ req[propertyName] = obj;
271
247
  } else {
248
+ if (req) req[propertyName] = null;
249
+ }
250
+ }
251
+
252
+ function _extractJwtObject(req, jwt, customErrorFunction) {
253
+ _extractJwtObjectNoThrow(req, jwt);
254
+
255
+ if (!req["jwt"]) {
272
256
  throwError(customErrorFunction);
273
257
  }
274
258
  }
275
259
 
276
260
  function _extractJwtObjectNoThrow(req, jwt) {
277
- if (jwt && typeof jwt === "string") {
278
- const jwtObj = jwtUtilAuth.getHeaderPayloadFromJwt(jwt);
279
- _attachJwtMethods(jwtObj);
280
- req["jwt"] = jwtObj;
281
- } else {
282
- req["jwt"] = null;
283
- }
261
+ _extractGenericObjectNoThrow(req, jwt, _attachJwtMethods, "jwt");
284
262
  }
285
263
 
286
264
  function _extractVisitorObjectNoThrow(req, jwt) {
287
- if (jwt && typeof jwt === "string") {
288
- const visitorObj = jwtUtilAuth.getHeaderPayloadFromJwt(jwt);
289
- _attachVisitorMethods(visitorObj);
290
- req["visitor"] = visitorObj;
291
- } else {
292
- req["visitor"] = null;
293
- }
265
+ _extractGenericObjectNoThrow(req, jwt, _attachVisitorMethods, "visitor");
294
266
  }
295
267
 
296
268
  function _attachJwtMethods(jwtObj) {
@@ -314,8 +286,10 @@ function _attachVisitorMethods(visitorObj) {
314
286
 
315
287
  async function _isJwtSignatureValid(jwt, publicKey, customErrorFunction) {
316
288
 
317
- if (jwt && typeof jwt === "string") {
318
- return jwtUtilAuth.verifyJwtSignature(jwt, publicKey)
289
+ const isValid = await _isJwtSignatureValidNoThrow(jwt, publicKey);
290
+
291
+ if (isValid) {
292
+ return isValid;
319
293
  } else {
320
294
  throwError(customErrorFunction);
321
295
  }
@@ -324,115 +298,37 @@ async function _isJwtSignatureValid(jwt, publicKey, customErrorFunction) {
324
298
  async function _isJwtSignatureValidNoThrow(jwt, publicKey) {
325
299
 
326
300
  if (jwt && typeof jwt === "string") {
327
- return jwtUtilAuth.verifyJwtSignature(jwt, publicKey)
301
+ return jwtVerifySignedToken(jwt, publicKey)
328
302
  } else {
329
303
  return false;
330
304
  }
331
305
  }
332
306
 
333
307
  function _validateJwt(req, customErrorFunction) {
334
-
335
- // Get from http header.
336
- let jwtRaw = req.get("Authorization");
337
-
338
- // Extract jwt from bearer schema.
339
- let jwt = _extractJwt(jwtRaw, customErrorFunction);
340
-
341
- // Validate characters string of jwt.
342
- if (isJwtString(jwt)) {
343
- return jwt;
344
- } else {
345
- throwError(customErrorFunction);
346
- }
308
+ return _validateGeneric(req, "Authorization", _extractJwt, customErrorFunction);
347
309
  }
348
310
 
349
311
  function _validateWebToken(req, headerName, customErrorFunction) {
350
-
351
- // Get from http header.
352
- let jwtRaw = req.get(headerName);
353
-
354
- // Extract jwt from bearer schema.
355
- let webToken = _extractWebToken(jwtRaw, customErrorFunction);
356
-
357
- // Validate characters string of jwt.
358
- if (isJwtString(webToken)) {
359
- return webToken;
360
- } else {
361
- throwError(customErrorFunction);
362
- }
312
+ return _validateGeneric(req, headerName, _extractWebToken, customErrorFunction);
363
313
  }
364
314
 
365
315
  function _validateJwtNoThrow(req) {
366
-
367
- // Get from http header.
368
- let jwtRaw = req.get("Authorization");
369
-
370
- if (!jwtRaw) {
371
- return null;
372
- }
373
-
374
- // Extract jwt from bearer schema.
375
- let jwt = _extractJwtNoThrow(jwtRaw);
376
-
377
- // Validate characters string of jwt.
378
- if (isJwtString(jwt)) {
379
- return jwt;
380
- }
381
-
382
- return null;
316
+ return _validateGenericNoThrow(req, "Authorization", _extractJwtNoThrow);
383
317
  }
384
318
 
385
319
  function _validateWebTokenNoThrow(req, headerName) {
386
-
387
- // Get from http header.
388
- let jwtRaw = req.get(headerName);
389
-
390
- if (!jwtRaw) {
391
- return null;
392
- }
393
-
394
- // Extract jwt from bearer schema.
395
- let webToken = _extractWebTokenNoThrow(jwtRaw);
396
-
397
- // Validate characters string of jwt.
398
- if (isJwtString(webToken)) {
399
- return webToken;
400
- }
401
-
402
- return null;
320
+ return _validateGenericNoThrow(req, headerName, _extractWebTokenNoThrow);
403
321
  }
404
322
 
405
323
  function _validateVisitorNoThrow(req) {
406
-
407
- // Get from http header.
408
- let jwtRaw = req.get("Visitor");
409
-
410
- if (!jwtRaw) {
411
- return null;
412
- }
413
-
414
- // Extract jwt from bearer schema.
415
- let jwt = _extractJwtNoThrow(jwtRaw);
416
-
417
- // Validate characters string of jwt.
418
- if (isJwtString(jwt)) {
419
- return jwt;
420
- }
421
-
422
- return null;
324
+ return _validateGenericNoThrow(req, "Visitor", _extractJwtNoThrow);
423
325
  }
424
326
 
425
327
  function _extractJwt(jwtRaw, customErrorFunction) {
426
- let jwtSplit = null;
427
-
428
- if (jwtRaw && typeof jwtRaw === "string") {
429
- jwtSplit = jwtRaw.split(" ");
430
- } else {
431
- throwError(customErrorFunction);
432
- }
328
+ const jwt = _extractJwtNoThrow(jwtRaw);
433
329
 
434
- if (jwtSplit[0]?.toLowerCase() === "bearer") {
435
- return jwtSplit[1];
330
+ if (jwt !== null) {
331
+ return jwt;
436
332
  } else {
437
333
  throwError(customErrorFunction);
438
334
  }
@@ -441,9 +337,10 @@ function _extractJwt(jwtRaw, customErrorFunction) {
441
337
  }
442
338
 
443
339
  function _extractWebToken(jwtRaw, customErrorFunction) {
340
+ const webToken = _extractWebTokenNoThrow(jwtRaw);
444
341
 
445
- if (jwtRaw && typeof jwtRaw === "string") {
446
- return jwtRaw;
342
+ if (webToken !== null) {
343
+ return webToken;
447
344
  } else {
448
345
  throwError(customErrorFunction);
449
346
  }
@@ -481,8 +378,8 @@ module.exports = {
481
378
  _isJwtSignatureValid,
482
379
  _isJwtSignatureValidNoThrow,
483
380
  _extractJwtObject,
484
- _extractJwtObjectNoThrow,
485
381
  validateAndExtractJwtObject,
382
+ validateAndExtractWebToken,
486
383
  jwtAgeInSeconds,
487
384
  isJwtExpired,
488
385
  doesJwtUserHasRole,
@@ -495,5 +392,20 @@ module.exports = {
495
392
  verifyJwtNoThrow,
496
393
  throwUsedTokenError,
497
394
  throwError,
498
- verifyVisitorNoThrow
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
499
411
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@carecard/jwt-read",
3
- "version": "3.0.11",
3
+ "version": "3.1.13",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/CareCard-ca/pkg-jwt-read.git"
@@ -10,12 +10,15 @@
10
10
  "types": "index.d.ts",
11
11
  "scripts": {
12
12
  "test": "export NODE_ENV=test && mocha --recursive",
13
- "test:types": "tsc --noEmit && mocha -r ts-node/register test/types.test.ts"
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
16
  },
15
17
  "keywords": [
16
18
  "auth",
17
19
  "utility",
18
- "cryptology"
20
+ "cryptology",
21
+ "jwt"
19
22
  ],
20
23
  "author": "CareCard team",
21
24
  "license": "ISC",
@@ -23,13 +26,15 @@
23
26
  "@types/express": "5.0.6",
24
27
  "@types/mocha": "10.0.10",
25
28
  "@types/node": "25.5.0",
29
+ "husky": "^9.1.7",
26
30
  "mocha": "11.7.5",
31
+ "nyc": "^18.0.0",
27
32
  "ts-node": "10.9.2",
28
33
  "typescript": "5.9.3"
29
34
  },
30
35
  "dependencies": {
31
- "@carecard/auth-util": "3.0.10",
32
- "@carecard/common-util": "3.0.10",
36
+ "@carecard/common-util": "3.1.11",
37
+ "@carecard/auth-util": "3.1.12",
33
38
  "@carecard/validate": "3.0.10"
34
39
  }
35
40
  }
package/readme.md CHANGED
@@ -1,32 +1,88 @@
1
- # Jwt read utility
1
+ # @carecard/jwt-read
2
2
 
3
- ## Main Functionality
3
+ ![Tests Passing](https://github.com/CareCard-ca/pkg-jwt-read/actions/workflows/ci.yml/badge.svg)
4
+ ![Coverage](https://img.shields.io/badge/Coverage-80%25-orange)
4
5
 
5
- This is a collection of jwt reading functions.
6
+ Utility package for reading, parsing, and verifying JWTs in the CareCard ecosystem.
6
7
 
7
- ### Main functions
8
+ ## Features
8
9
 
9
- ```js
10
- const jwtReader = require( '@chatpta/jwt-read' );
10
+ - **JWT Verification**: Middleware-like utilities for signature and role verification.
11
+ - **Express Integration**: Designed to work seamlessly with Express `req` objects.
12
+ - **Role Mapping**: Simple utility for translating internal role codes to human-readable names.
13
+ - **Claims Extraction**: Easy extraction of `sub` (clientId) and other JWT payload claims.
14
+ - **Expiration Management**: Helpers to check if a JWT is expired and calculate its remaining TTL.
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install @carecard/jwt-read
11
20
  ```
12
21
 
13
- Read jwt
22
+ ## Usage
23
+
24
+ ### Middleware-like Verification (`verifyJwtAndRole`)
25
+
26
+ ```javascript
27
+ const { verifyJwtAndRole, throwUsedTokenError } = require('@carecard/jwt-read');
14
28
 
15
- ```js
16
- const jwtMiddleware = jwtReader.verifyJwtAndRole( "admin", publicKey, jwtReader.throwUsedTokenError );
17
- await jwtMiddleware( req, res, next );
29
+ // Create a verification function for 'admin' role
30
+ const verifyAdmin = verifyJwtAndRole('admin', publicKey, throwUsedTokenError);
31
+
32
+ // In an Express controller/middleware
33
+ try {
34
+ await verifyAdmin(req, res, next);
35
+ // If successful, req.jwt contains { header, payload }
36
+ console.log(req.jwt.payload.sub);
37
+ } catch (error) {
38
+ // Handle verification error
39
+ }
18
40
  ```
19
41
 
20
- Following the above ```req.jwt``` contains
21
-
22
- ```js
23
- {
24
- header: {
25
- alg:...
26
- }
27
- ,
28
- payload: {
29
- ...
30
- }
42
+ ### Direct JWT Reading
43
+
44
+ ```javascript
45
+ const { verifyJwt, isJwtExpired } = require('@carecard/jwt-read');
46
+
47
+ const result = verifyJwt(rawJwt, publicKey);
48
+ if (result && !isJwtExpired(result)) {
49
+ console.log('JWT is valid and not expired:', result.payload);
31
50
  }
32
51
  ```
52
+
53
+ ### Role Utilities
54
+
55
+ ```javascript
56
+ const { getNameOfRole, getCodeOfRole } = require('@carecard/jwt-read');
57
+
58
+ console.log(getNameOfRole('ad')); // Result: 'admin'
59
+ console.log(getCodeOfRole('super_admin')); // Result: 'su'
60
+ ```
61
+
62
+ ## Testing
63
+
64
+ Run tests using:
65
+
66
+ ```bash
67
+ npm test
68
+ ```
69
+
70
+ To run tests with coverage:
71
+
72
+ ```bash
73
+ npm run test:coverage
74
+ ```
75
+
76
+ To run type tests:
77
+
78
+ ```bash
79
+ npm run test:types
80
+ ```
81
+
82
+ ## Architecture
83
+
84
+ The package is organized into several modules:
85
+ - `jwtLib`: Main logic for JWT verification, extraction, and Express integration.
86
+ - `jwtRoles`: Role mapping between internal codes and names.
87
+
88
+ All modules are exported through the main `index.js`.