hi-secure 1.0.32 → 1.0.34

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.
@@ -1 +1 @@
1
- {"version":3,"file":"JWTAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/JWTAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,cAAc,CAAC;AAK/B,MAAM,WAAW,iBAAiB;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,SAAS,CAAC,EAAE,GAAG,CAAC,SAAS,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,WAAW;IACxB,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CAChC;AAED,qBAAa,UAAU;IACnB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAAC,CAAkB;IACpC,OAAO,CAAC,SAAS,CAAgB;IACjC,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAC,CAAoB;gBAEzB,OAAO,EAAE,iBAAiB;IAoBtC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW;IA6B3C,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;KAAE;CA4BnE"}
1
+ {"version":3,"file":"JWTAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/JWTAdapter.ts"],"names":[],"mappings":"AA6GA,OAAO,GAAsC,MAAM,cAAc,CAAC;AAOlE,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,SAAS,CAAC,EAAE,GAAG,CAAC,SAAS,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CAC9B;AAWD,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAAC,CAAY;IAC9B,OAAO,CAAC,SAAS,CAAgB;IACjC,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAC,CAAoB;gBAEzB,OAAO,EAAE,iBAAiB;IAoBtC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW;IA4C3C,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;KAAE;CAgCjE"}
@@ -1,13 +1,111 @@
1
1
  "use strict";
2
+ // import jwt from "jsonwebtoken";
3
+ // import { randomUUID } from "crypto";
4
+ // import { AdapterError } from "../core/errors/AdapterError";
5
+ // import { logger } from "../logging";
2
6
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
7
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
8
  };
5
9
  Object.defineProperty(exports, "__esModule", { value: true });
6
10
  exports.JWTAdapter = void 0;
11
+ // export interface JWTAdapterOptions {
12
+ // secret: string;
13
+ // expiresIn?: string | number;
14
+ // algorithm?: jwt.Algorithm;
15
+ // issuer?: string;
16
+ // audience?: string | string[];
17
+ // }
18
+ // export interface SignOptions {
19
+ // expiresIn?: string | number;
20
+ // jti?: string;
21
+ // subject?: string;
22
+ // issuer?: string;
23
+ // audience?: string | string[];
24
+ // }
25
+ // export class JWTAdapter {
26
+ // private secret: string;
27
+ // private expiresIn?: string | number;
28
+ // private algorithm: jwt.Algorithm;
29
+ // private issuer?: string;
30
+ // private audience?: string | string[];
31
+ // constructor(options: JWTAdapterOptions) {
32
+ // if (!options.secret) {
33
+ // throw new AdapterError("JWT secret is required");
34
+ // }
35
+ // if (options.secret.length < 32) {
36
+ // logger.warn("Weak JWT secret detected", {
37
+ // adapter: "jwt",
38
+ // operation: "init",
39
+ // secretLength: options.secret.length
40
+ // });
41
+ // }
42
+ // this.secret = options.secret;
43
+ // this.expiresIn = options.expiresIn;
44
+ // this.algorithm = options.algorithm || "HS256";
45
+ // this.issuer = options.issuer;
46
+ // this.audience = options.audience;
47
+ // }
48
+ // sign(payload: object, options?: SignOptions) {
49
+ // try {
50
+ // const jwtOptions: jwt.SignOptions = {
51
+ // algorithm: this.algorithm,
52
+ // issuer: options?.issuer || this.issuer,
53
+ // audience: options?.audience || this.audience,
54
+ // jwtid: options?.jti || randomUUID(),
55
+ // subject: options?.subject
56
+ // };
57
+ // if (options?.expiresIn !== undefined) {
58
+ // jwtOptions.expiresIn = options.expiresIn as any;
59
+ // } else if (this.expiresIn !== undefined) {
60
+ // jwtOptions.expiresIn = this.expiresIn as any;
61
+ // }
62
+ // return jwt.sign(payload, this.secret, jwtOptions);
63
+ // } catch (err: any) {
64
+ // logger.error("JWT signing failed", {
65
+ // adapter: "jwt",
66
+ // operation: "sign",
67
+ // reason: err?.message
68
+ // });
69
+ // throw new AdapterError("JWT sign failed");
70
+ // }
71
+ // }
72
+ // verify(token: string, options?: { audience?: string | string[] }) {
73
+ // try {
74
+ // const verifyOptions: jwt.VerifyOptions = {
75
+ // algorithms: [this.algorithm],
76
+ // issuer: this.issuer,
77
+ // audience: (options?.audience || this.audience) as string
78
+ // };
79
+ // return jwt.verify(token, this.secret, verifyOptions);
80
+ // } catch (err: any) {
81
+ // logger.error("JWT verification failed", {
82
+ // adapter: "jwt",
83
+ // operation: "verify",
84
+ // reason: err?.message
85
+ // });
86
+ // if (err?.name === "TokenExpiredError") {
87
+ // throw new AdapterError("JWT token has expired");
88
+ // }
89
+ // if (err?.name === "JsonWebTokenError") {
90
+ // throw new AdapterError("Invalid JWT token");
91
+ // }
92
+ // throw new AdapterError("JWT verification failed");
93
+ // }
94
+ // }
95
+ // }
7
96
  const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
8
97
  const crypto_1 = require("crypto");
9
98
  const AdapterError_1 = require("../core/errors/AdapterError");
10
99
  const logging_1 = require("../logging");
100
+ function normalizeAudience(aud) {
101
+ if (!aud)
102
+ return undefined;
103
+ if (typeof aud === "string")
104
+ return aud;
105
+ if (aud.length > 0)
106
+ return aud;
107
+ return undefined;
108
+ }
11
109
  class JWTAdapter {
12
110
  constructor(options) {
13
111
  if (!options.secret) {
@@ -16,30 +114,41 @@ class JWTAdapter {
16
114
  if (options.secret.length < 32) {
17
115
  logging_1.logger.warn("Weak JWT secret detected", {
18
116
  adapter: "jwt",
19
- operation: "init",
20
117
  secretLength: options.secret.length
21
118
  });
22
119
  }
23
120
  this.secret = options.secret;
24
- this.expiresIn = options.expiresIn;
25
- this.algorithm = options.algorithm || "HS256";
121
+ this.algorithm = options.algorithm ?? "HS256";
26
122
  this.issuer = options.issuer;
27
123
  this.audience = options.audience;
124
+ this.expiresIn = options.expiresIn;
28
125
  }
126
+ // ================= SIGN =================
29
127
  sign(payload, options) {
30
128
  try {
31
129
  const jwtOptions = {
32
130
  algorithm: this.algorithm,
33
- issuer: options?.issuer || this.issuer,
34
- audience: options?.audience || this.audience,
35
- jwtid: options?.jti || (0, crypto_1.randomUUID)(),
36
- subject: options?.subject
131
+ jwtid: options?.jti ?? (0, crypto_1.randomUUID)()
37
132
  };
38
- if (options?.expiresIn !== undefined) {
39
- jwtOptions.expiresIn = options.expiresIn;
133
+ // subject ONLY if string
134
+ if (typeof options?.subject === "string") {
135
+ jwtOptions.subject = options.subject;
40
136
  }
41
- else if (this.expiresIn !== undefined) {
42
- jwtOptions.expiresIn = this.expiresIn;
137
+ // issuer
138
+ const issuer = options?.issuer ?? this.issuer;
139
+ if (typeof issuer === "string") {
140
+ jwtOptions.issuer = issuer;
141
+ }
142
+ // ✅ audience
143
+ const audience = normalizeAudience(options?.audience ?? this.audience);
144
+ if (audience)
145
+ jwtOptions.audience = audience;
146
+ // ✅ expiresIn
147
+ const expires = options?.expiresIn !== undefined
148
+ ? options.expiresIn
149
+ : this.expiresIn;
150
+ if (expires !== undefined) {
151
+ jwtOptions.expiresIn = expires;
43
152
  }
44
153
  return jsonwebtoken_1.default.sign(payload, this.secret, jwtOptions);
45
154
  }
@@ -52,13 +161,18 @@ class JWTAdapter {
52
161
  throw new AdapterError_1.AdapterError("JWT sign failed");
53
162
  }
54
163
  }
164
+ // ================= VERIFY =================
55
165
  verify(token, options) {
56
166
  try {
57
167
  const verifyOptions = {
58
- algorithms: [this.algorithm],
59
- issuer: this.issuer,
60
- audience: (options?.audience || this.audience)
168
+ algorithms: [this.algorithm]
61
169
  };
170
+ if (typeof this.issuer === "string") {
171
+ verifyOptions.issuer = this.issuer;
172
+ }
173
+ const audience = normalizeAudience(options?.audience ?? this.audience);
174
+ if (audience)
175
+ verifyOptions.audience = audience;
62
176
  return jsonwebtoken_1.default.verify(token, this.secret, verifyOptions);
63
177
  }
64
178
  catch (err) {
@@ -1 +1 @@
1
- {"version":3,"file":"JWTAdapter.js","sourceRoot":"","sources":["../../src/adapters/JWTAdapter.ts"],"names":[],"mappings":"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","sourcesContent":["import jwt from \"jsonwebtoken\";\r\nimport { randomUUID } from \"crypto\";\r\nimport { AdapterError } from \"../core/errors/AdapterError\";\r\nimport { logger } from \"../logging\";\r\n\r\nexport interface JWTAdapterOptions {\r\n secret: string;\r\n expiresIn?: string | number;\r\n algorithm?: jwt.Algorithm;\r\n issuer?: string;\r\n audience?: string | string[];\r\n}\r\n\r\nexport interface SignOptions {\r\n expiresIn?: string | number;\r\n jti?: string;\r\n subject?: string;\r\n issuer?: string;\r\n audience?: string | string[];\r\n}\r\n\r\nexport class JWTAdapter {\r\n private secret: string;\r\n private expiresIn?: string | number;\r\n private algorithm: jwt.Algorithm;\r\n private issuer?: string;\r\n private audience?: string | string[];\r\n\r\n constructor(options: JWTAdapterOptions) {\r\n if (!options.secret) {\r\n throw new AdapterError(\"JWT secret is required\");\r\n }\r\n\r\n if (options.secret.length < 32) {\r\n logger.warn(\"Weak JWT secret detected\", {\r\n adapter: \"jwt\",\r\n operation: \"init\",\r\n secretLength: options.secret.length\r\n });\r\n }\r\n\r\n this.secret = options.secret;\r\n this.expiresIn = options.expiresIn;\r\n this.algorithm = options.algorithm || \"HS256\";\r\n this.issuer = options.issuer;\r\n this.audience = options.audience;\r\n }\r\n\r\n sign(payload: object, options?: SignOptions) {\r\n try {\r\n const jwtOptions: jwt.SignOptions = {\r\n algorithm: this.algorithm,\r\n issuer: options?.issuer || this.issuer,\r\n audience: options?.audience || this.audience,\r\n jwtid: options?.jti || randomUUID(),\r\n subject: options?.subject\r\n };\r\n\r\n if (options?.expiresIn !== undefined) {\r\n jwtOptions.expiresIn = options.expiresIn as any;\r\n } else if (this.expiresIn !== undefined) {\r\n jwtOptions.expiresIn = this.expiresIn as any;\r\n }\r\n\r\n return jwt.sign(payload, this.secret, jwtOptions);\r\n\r\n } catch (err: any) {\r\n logger.error(\"JWT signing failed\", {\r\n adapter: \"jwt\",\r\n operation: \"sign\",\r\n reason: err?.message\r\n });\r\n\r\n throw new AdapterError(\"JWT sign failed\");\r\n }\r\n }\r\n\r\n verify(token: string, options?: { audience?: string | string[] }) {\r\n try {\r\n const verifyOptions: jwt.VerifyOptions = {\r\n algorithms: [this.algorithm],\r\n issuer: this.issuer,\r\n audience: (options?.audience || this.audience) as string\r\n };\r\n\r\n return jwt.verify(token, this.secret, verifyOptions);\r\n\r\n } catch (err: any) {\r\n logger.error(\"JWT verification failed\", {\r\n adapter: \"jwt\",\r\n operation: \"verify\",\r\n reason: err?.message\r\n });\r\n\r\n if (err?.name === \"TokenExpiredError\") {\r\n throw new AdapterError(\"JWT token has expired\");\r\n }\r\n\r\n if (err?.name === \"JsonWebTokenError\") {\r\n throw new AdapterError(\"Invalid JWT token\");\r\n }\r\n\r\n throw new AdapterError(\"JWT verification failed\");\r\n }\r\n }\r\n}\r\n"]}
1
+ {"version":3,"file":"JWTAdapter.js","sourceRoot":"","sources":["../../src/adapters/JWTAdapter.ts"],"names":[],"mappings":"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","sourcesContent":["// import jwt from \"jsonwebtoken\";\r\n// import { randomUUID } from \"crypto\";\r\n// import { AdapterError } from \"../core/errors/AdapterError\";\r\n// import { logger } from \"../logging\";\r\n\r\n// export interface JWTAdapterOptions {\r\n// secret: string;\r\n// expiresIn?: string | number;\r\n// algorithm?: jwt.Algorithm;\r\n// issuer?: string;\r\n// audience?: string | string[];\r\n// }\r\n\r\n// export interface SignOptions {\r\n// expiresIn?: string | number;\r\n// jti?: string;\r\n// subject?: string;\r\n// issuer?: string;\r\n// audience?: string | string[];\r\n// }\r\n\r\n// export class JWTAdapter {\r\n// private secret: string;\r\n// private expiresIn?: string | number;\r\n// private algorithm: jwt.Algorithm;\r\n// private issuer?: string;\r\n// private audience?: string | string[];\r\n\r\n// constructor(options: JWTAdapterOptions) {\r\n// if (!options.secret) {\r\n// throw new AdapterError(\"JWT secret is required\");\r\n// }\r\n\r\n// if (options.secret.length < 32) {\r\n// logger.warn(\"Weak JWT secret detected\", {\r\n// adapter: \"jwt\",\r\n// operation: \"init\",\r\n// secretLength: options.secret.length\r\n// });\r\n// }\r\n\r\n// this.secret = options.secret;\r\n// this.expiresIn = options.expiresIn;\r\n// this.algorithm = options.algorithm || \"HS256\";\r\n// this.issuer = options.issuer;\r\n// this.audience = options.audience;\r\n// }\r\n\r\n// sign(payload: object, options?: SignOptions) {\r\n// try {\r\n// const jwtOptions: jwt.SignOptions = {\r\n// algorithm: this.algorithm,\r\n// issuer: options?.issuer || this.issuer,\r\n// audience: options?.audience || this.audience,\r\n// jwtid: options?.jti || randomUUID(),\r\n// subject: options?.subject\r\n// };\r\n\r\n// if (options?.expiresIn !== undefined) {\r\n// jwtOptions.expiresIn = options.expiresIn as any;\r\n// } else if (this.expiresIn !== undefined) {\r\n// jwtOptions.expiresIn = this.expiresIn as any;\r\n// }\r\n\r\n// return jwt.sign(payload, this.secret, jwtOptions);\r\n\r\n// } catch (err: any) {\r\n// logger.error(\"JWT signing failed\", {\r\n// adapter: \"jwt\",\r\n// operation: \"sign\",\r\n// reason: err?.message\r\n// });\r\n\r\n// throw new AdapterError(\"JWT sign failed\");\r\n// }\r\n// }\r\n\r\n// verify(token: string, options?: { audience?: string | string[] }) {\r\n// try {\r\n// const verifyOptions: jwt.VerifyOptions = {\r\n// algorithms: [this.algorithm],\r\n// issuer: this.issuer,\r\n// audience: (options?.audience || this.audience) as string\r\n// };\r\n\r\n// return jwt.verify(token, this.secret, verifyOptions);\r\n\r\n// } catch (err: any) {\r\n// logger.error(\"JWT verification failed\", {\r\n// adapter: \"jwt\",\r\n// operation: \"verify\",\r\n// reason: err?.message\r\n// });\r\n\r\n// if (err?.name === \"TokenExpiredError\") {\r\n// throw new AdapterError(\"JWT token has expired\");\r\n// }\r\n\r\n// if (err?.name === \"JsonWebTokenError\") {\r\n// throw new AdapterError(\"Invalid JWT token\");\r\n// }\r\n\r\n// throw new AdapterError(\"JWT verification failed\");\r\n// }\r\n// }\r\n// }\r\n\r\n\r\n\r\nimport jwt, { SignOptions as JwtSignOptions } from \"jsonwebtoken\";\r\nimport { randomUUID } from \"crypto\";\r\nimport { AdapterError } from \"../core/errors/AdapterError\";\r\nimport { logger } from \"../logging\";\r\n\r\ntype ExpiresIn = JwtSignOptions[\"expiresIn\"];\r\n\r\nexport interface JWTAdapterOptions {\r\n secret: string;\r\n expiresIn?: string | number;\r\n algorithm?: jwt.Algorithm;\r\n issuer?: string;\r\n audience?: string | string[];\r\n}\r\n\r\nexport interface SignOptions {\r\n expiresIn?: string | number;\r\n jti?: string;\r\n subject?: string;\r\n issuer?: string;\r\n audience?: string | string[];\r\n}\r\n\r\nfunction normalizeAudience(\r\n aud?: string | string[]\r\n): string | [string, ...string[]] | undefined {\r\n if (!aud) return undefined;\r\n if (typeof aud === \"string\") return aud;\r\n if (aud.length > 0) return aud as [string, ...string[]];\r\n return undefined;\r\n}\r\n\r\nexport class JWTAdapter {\r\n private secret: string;\r\n private expiresIn?: ExpiresIn;\r\n private algorithm: jwt.Algorithm;\r\n private issuer?: string;\r\n private audience?: string | string[];\r\n\r\n constructor(options: JWTAdapterOptions) {\r\n if (!options.secret) {\r\n throw new AdapterError(\"JWT secret is required\");\r\n }\r\n\r\n if (options.secret.length < 32) {\r\n logger.warn(\"Weak JWT secret detected\", {\r\n adapter: \"jwt\",\r\n secretLength: options.secret.length\r\n });\r\n }\r\n\r\n this.secret = options.secret;\r\n this.algorithm = options.algorithm ?? \"HS256\";\r\n this.issuer = options.issuer;\r\n this.audience = options.audience;\r\n this.expiresIn = options.expiresIn as ExpiresIn;\r\n }\r\n\r\n // ================= SIGN =================\r\n sign(payload: object, options?: SignOptions) {\r\n try {\r\n const jwtOptions: jwt.SignOptions = {\r\n algorithm: this.algorithm,\r\n jwtid: options?.jti ?? randomUUID()\r\n };\r\n\r\n // ✅ subject ONLY if string\r\n if (typeof options?.subject === \"string\") {\r\n jwtOptions.subject = options.subject;\r\n }\r\n\r\n // ✅ issuer\r\n const issuer = options?.issuer ?? this.issuer;\r\n if (typeof issuer === \"string\") {\r\n jwtOptions.issuer = issuer;\r\n }\r\n\r\n // ✅ audience\r\n const audience = normalizeAudience(options?.audience ?? this.audience);\r\n if (audience) jwtOptions.audience = audience;\r\n\r\n // ✅ expiresIn\r\n const expires =\r\n options?.expiresIn !== undefined\r\n ? (options.expiresIn as ExpiresIn)\r\n : this.expiresIn;\r\n\r\n if (expires !== undefined) {\r\n jwtOptions.expiresIn = expires;\r\n }\r\n\r\n return jwt.sign(payload, this.secret, jwtOptions);\r\n } catch (err: any) {\r\n logger.error(\"JWT signing failed\", {\r\n adapter: \"jwt\",\r\n operation: \"sign\",\r\n reason: err?.message\r\n });\r\n throw new AdapterError(\"JWT sign failed\");\r\n }\r\n }\r\n\r\n // ================= VERIFY =================\r\n verify(token: string, options?: { audience?: string | string[] }) {\r\n try {\r\n const verifyOptions: jwt.VerifyOptions = {\r\n algorithms: [this.algorithm]\r\n };\r\n\r\n if (typeof this.issuer === \"string\") {\r\n verifyOptions.issuer = this.issuer;\r\n }\r\n\r\n const audience = normalizeAudience(options?.audience ?? this.audience);\r\n if (audience) verifyOptions.audience = audience;\r\n\r\n return jwt.verify(token, this.secret, verifyOptions);\r\n } catch (err: any) {\r\n logger.error(\"JWT verification failed\", {\r\n adapter: \"jwt\",\r\n operation: \"verify\",\r\n reason: err?.message\r\n });\r\n\r\n if (err?.name === \"TokenExpiredError\") {\r\n throw new AdapterError(\"JWT token has expired\");\r\n }\r\n\r\n if (err?.name === \"JsonWebTokenError\") {\r\n throw new AdapterError(\"Invalid JWT token\");\r\n }\r\n\r\n throw new AdapterError(\"JWT verification failed\");\r\n }\r\n }\r\n}\r\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hi-secure",
3
- "version": "1.0.32",
3
+ "version": "1.0.34",
4
4
  "description": "Unified security layer for Express.js: authentication, validation, sanitization, rate limiting and CORS",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -1,106 +1,245 @@
1
- import jwt from "jsonwebtoken";
1
+ // import jwt from "jsonwebtoken";
2
+ // import { randomUUID } from "crypto";
3
+ // import { AdapterError } from "../core/errors/AdapterError";
4
+ // import { logger } from "../logging";
5
+
6
+ // export interface JWTAdapterOptions {
7
+ // secret: string;
8
+ // expiresIn?: string | number;
9
+ // algorithm?: jwt.Algorithm;
10
+ // issuer?: string;
11
+ // audience?: string | string[];
12
+ // }
13
+
14
+ // export interface SignOptions {
15
+ // expiresIn?: string | number;
16
+ // jti?: string;
17
+ // subject?: string;
18
+ // issuer?: string;
19
+ // audience?: string | string[];
20
+ // }
21
+
22
+ // export class JWTAdapter {
23
+ // private secret: string;
24
+ // private expiresIn?: string | number;
25
+ // private algorithm: jwt.Algorithm;
26
+ // private issuer?: string;
27
+ // private audience?: string | string[];
28
+
29
+ // constructor(options: JWTAdapterOptions) {
30
+ // if (!options.secret) {
31
+ // throw new AdapterError("JWT secret is required");
32
+ // }
33
+
34
+ // if (options.secret.length < 32) {
35
+ // logger.warn("Weak JWT secret detected", {
36
+ // adapter: "jwt",
37
+ // operation: "init",
38
+ // secretLength: options.secret.length
39
+ // });
40
+ // }
41
+
42
+ // this.secret = options.secret;
43
+ // this.expiresIn = options.expiresIn;
44
+ // this.algorithm = options.algorithm || "HS256";
45
+ // this.issuer = options.issuer;
46
+ // this.audience = options.audience;
47
+ // }
48
+
49
+ // sign(payload: object, options?: SignOptions) {
50
+ // try {
51
+ // const jwtOptions: jwt.SignOptions = {
52
+ // algorithm: this.algorithm,
53
+ // issuer: options?.issuer || this.issuer,
54
+ // audience: options?.audience || this.audience,
55
+ // jwtid: options?.jti || randomUUID(),
56
+ // subject: options?.subject
57
+ // };
58
+
59
+ // if (options?.expiresIn !== undefined) {
60
+ // jwtOptions.expiresIn = options.expiresIn as any;
61
+ // } else if (this.expiresIn !== undefined) {
62
+ // jwtOptions.expiresIn = this.expiresIn as any;
63
+ // }
64
+
65
+ // return jwt.sign(payload, this.secret, jwtOptions);
66
+
67
+ // } catch (err: any) {
68
+ // logger.error("JWT signing failed", {
69
+ // adapter: "jwt",
70
+ // operation: "sign",
71
+ // reason: err?.message
72
+ // });
73
+
74
+ // throw new AdapterError("JWT sign failed");
75
+ // }
76
+ // }
77
+
78
+ // verify(token: string, options?: { audience?: string | string[] }) {
79
+ // try {
80
+ // const verifyOptions: jwt.VerifyOptions = {
81
+ // algorithms: [this.algorithm],
82
+ // issuer: this.issuer,
83
+ // audience: (options?.audience || this.audience) as string
84
+ // };
85
+
86
+ // return jwt.verify(token, this.secret, verifyOptions);
87
+
88
+ // } catch (err: any) {
89
+ // logger.error("JWT verification failed", {
90
+ // adapter: "jwt",
91
+ // operation: "verify",
92
+ // reason: err?.message
93
+ // });
94
+
95
+ // if (err?.name === "TokenExpiredError") {
96
+ // throw new AdapterError("JWT token has expired");
97
+ // }
98
+
99
+ // if (err?.name === "JsonWebTokenError") {
100
+ // throw new AdapterError("Invalid JWT token");
101
+ // }
102
+
103
+ // throw new AdapterError("JWT verification failed");
104
+ // }
105
+ // }
106
+ // }
107
+
108
+
109
+
110
+ import jwt, { SignOptions as JwtSignOptions } from "jsonwebtoken";
2
111
  import { randomUUID } from "crypto";
3
112
  import { AdapterError } from "../core/errors/AdapterError";
4
113
  import { logger } from "../logging";
5
114
 
115
+ type ExpiresIn = JwtSignOptions["expiresIn"];
116
+
6
117
  export interface JWTAdapterOptions {
7
- secret: string;
8
- expiresIn?: string | number;
9
- algorithm?: jwt.Algorithm;
10
- issuer?: string;
11
- audience?: string | string[];
118
+ secret: string;
119
+ expiresIn?: string | number;
120
+ algorithm?: jwt.Algorithm;
121
+ issuer?: string;
122
+ audience?: string | string[];
12
123
  }
13
124
 
14
125
  export interface SignOptions {
15
- expiresIn?: string | number;
16
- jti?: string;
17
- subject?: string;
18
- issuer?: string;
19
- audience?: string | string[];
126
+ expiresIn?: string | number;
127
+ jti?: string;
128
+ subject?: string;
129
+ issuer?: string;
130
+ audience?: string | string[];
131
+ }
132
+
133
+ function normalizeAudience(
134
+ aud?: string | string[]
135
+ ): string | [string, ...string[]] | undefined {
136
+ if (!aud) return undefined;
137
+ if (typeof aud === "string") return aud;
138
+ if (aud.length > 0) return aud as [string, ...string[]];
139
+ return undefined;
20
140
  }
21
141
 
22
142
  export class JWTAdapter {
23
- private secret: string;
24
- private expiresIn?: string | number;
25
- private algorithm: jwt.Algorithm;
26
- private issuer?: string;
27
- private audience?: string | string[];
28
-
29
- constructor(options: JWTAdapterOptions) {
30
- if (!options.secret) {
31
- throw new AdapterError("JWT secret is required");
32
- }
33
-
34
- if (options.secret.length < 32) {
35
- logger.warn("Weak JWT secret detected", {
36
- adapter: "jwt",
37
- operation: "init",
38
- secretLength: options.secret.length
39
- });
40
- }
41
-
42
- this.secret = options.secret;
43
- this.expiresIn = options.expiresIn;
44
- this.algorithm = options.algorithm || "HS256";
45
- this.issuer = options.issuer;
46
- this.audience = options.audience;
143
+ private secret: string;
144
+ private expiresIn?: ExpiresIn;
145
+ private algorithm: jwt.Algorithm;
146
+ private issuer?: string;
147
+ private audience?: string | string[];
148
+
149
+ constructor(options: JWTAdapterOptions) {
150
+ if (!options.secret) {
151
+ throw new AdapterError("JWT secret is required");
47
152
  }
48
153
 
49
- sign(payload: object, options?: SignOptions) {
50
- try {
51
- const jwtOptions: jwt.SignOptions = {
52
- algorithm: this.algorithm,
53
- issuer: options?.issuer || this.issuer,
54
- audience: options?.audience || this.audience,
55
- jwtid: options?.jti || randomUUID(),
56
- subject: options?.subject
57
- };
58
-
59
- if (options?.expiresIn !== undefined) {
60
- jwtOptions.expiresIn = options.expiresIn as any;
61
- } else if (this.expiresIn !== undefined) {
62
- jwtOptions.expiresIn = this.expiresIn as any;
63
- }
64
-
65
- return jwt.sign(payload, this.secret, jwtOptions);
66
-
67
- } catch (err: any) {
68
- logger.error("JWT signing failed", {
69
- adapter: "jwt",
70
- operation: "sign",
71
- reason: err?.message
72
- });
73
-
74
- throw new AdapterError("JWT sign failed");
75
- }
154
+ if (options.secret.length < 32) {
155
+ logger.warn("Weak JWT secret detected", {
156
+ adapter: "jwt",
157
+ secretLength: options.secret.length
158
+ });
76
159
  }
77
160
 
78
- verify(token: string, options?: { audience?: string | string[] }) {
79
- try {
80
- const verifyOptions: jwt.VerifyOptions = {
81
- algorithms: [this.algorithm],
82
- issuer: this.issuer,
83
- audience: (options?.audience || this.audience) as string
84
- };
85
-
86
- return jwt.verify(token, this.secret, verifyOptions);
87
-
88
- } catch (err: any) {
89
- logger.error("JWT verification failed", {
90
- adapter: "jwt",
91
- operation: "verify",
92
- reason: err?.message
93
- });
94
-
95
- if (err?.name === "TokenExpiredError") {
96
- throw new AdapterError("JWT token has expired");
97
- }
98
-
99
- if (err?.name === "JsonWebTokenError") {
100
- throw new AdapterError("Invalid JWT token");
101
- }
102
-
103
- throw new AdapterError("JWT verification failed");
104
- }
161
+ this.secret = options.secret;
162
+ this.algorithm = options.algorithm ?? "HS256";
163
+ this.issuer = options.issuer;
164
+ this.audience = options.audience;
165
+ this.expiresIn = options.expiresIn as ExpiresIn;
166
+ }
167
+
168
+ // ================= SIGN =================
169
+ sign(payload: object, options?: SignOptions) {
170
+ try {
171
+ const jwtOptions: jwt.SignOptions = {
172
+ algorithm: this.algorithm,
173
+ jwtid: options?.jti ?? randomUUID()
174
+ };
175
+
176
+ // ✅ subject ONLY if string
177
+ if (typeof options?.subject === "string") {
178
+ jwtOptions.subject = options.subject;
179
+ }
180
+
181
+ // ✅ issuer
182
+ const issuer = options?.issuer ?? this.issuer;
183
+ if (typeof issuer === "string") {
184
+ jwtOptions.issuer = issuer;
185
+ }
186
+
187
+ // ✅ audience
188
+ const audience = normalizeAudience(options?.audience ?? this.audience);
189
+ if (audience) jwtOptions.audience = audience;
190
+
191
+ // ✅ expiresIn
192
+ const expires =
193
+ options?.expiresIn !== undefined
194
+ ? (options.expiresIn as ExpiresIn)
195
+ : this.expiresIn;
196
+
197
+ if (expires !== undefined) {
198
+ jwtOptions.expiresIn = expires;
199
+ }
200
+
201
+ return jwt.sign(payload, this.secret, jwtOptions);
202
+ } catch (err: any) {
203
+ logger.error("JWT signing failed", {
204
+ adapter: "jwt",
205
+ operation: "sign",
206
+ reason: err?.message
207
+ });
208
+ throw new AdapterError("JWT sign failed");
209
+ }
210
+ }
211
+
212
+ // ================= VERIFY =================
213
+ verify(token: string, options?: { audience?: string | string[] }) {
214
+ try {
215
+ const verifyOptions: jwt.VerifyOptions = {
216
+ algorithms: [this.algorithm]
217
+ };
218
+
219
+ if (typeof this.issuer === "string") {
220
+ verifyOptions.issuer = this.issuer;
221
+ }
222
+
223
+ const audience = normalizeAudience(options?.audience ?? this.audience);
224
+ if (audience) verifyOptions.audience = audience;
225
+
226
+ return jwt.verify(token, this.secret, verifyOptions);
227
+ } catch (err: any) {
228
+ logger.error("JWT verification failed", {
229
+ adapter: "jwt",
230
+ operation: "verify",
231
+ reason: err?.message
232
+ });
233
+
234
+ if (err?.name === "TokenExpiredError") {
235
+ throw new AdapterError("JWT token has expired");
236
+ }
237
+
238
+ if (err?.name === "JsonWebTokenError") {
239
+ throw new AdapterError("Invalid JWT token");
240
+ }
241
+
242
+ throw new AdapterError("JWT verification failed");
105
243
  }
244
+ }
106
245
  }