@naturalcycles/nodejs-lib 15.117.0 → 15.119.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -175,6 +175,31 @@ export declare class JWTService2<T extends AnyObject = AnyObject> {
175
175
  constructor(cfg: JWTService2Cfg<T>);
176
176
  sign<TT extends T = T>(payload: TT, opt: JWTSignOptions<TT>): Promise<JWTString>;
177
177
  verify<TT extends T = T>(token: JWTString, opt?: JWTVerifyOptions<TT>): Promise<TT>;
178
+ /**
179
+ * Tries to Verify the token, returning an [error, payload] tuple instead of throwing:
180
+ * - [null, payload] - the token verified, payload can be trusted
181
+ * - [error, null] - verification failed
182
+ *
183
+ * Same contract as tryToVerifyOrDecode, but without the unverified-decode fallback:
184
+ * the payload is only returned when the token verified.
185
+ */
186
+ tryToVerify<TT extends T = T>(token: JWTString, opt?: JWTVerifyOptions<TT>): Promise<[err: null, payload: TT] | [err: Error, payload: null]>;
187
+ /**
188
+ * Tries to Verify the token, falling back to unverified Decode on failure,
189
+ * so the caller can "peek" into the token's content even when it doesn't verify.
190
+ *
191
+ * Returns an [error, payload] tuple - ALWAYS check the error first:
192
+ * - [null, payload] - the token verified, payload can be trusted
193
+ * - [error, payload] - verification failed, but the token could still be decoded.
194
+ * When the error is JWTExpiredError/JWTNotYetValidError, the signature was already
195
+ * verified and only the time-claim check failed, so the payload is trustworthy
196
+ * (just expired/not yet valid). For any other error the payload is completely
197
+ * UNVERIFIED - never trust it, only peek (e.g to log/report the claimed identity).
198
+ * - [error, null] - the token could not even be decoded
199
+ *
200
+ * The decode fallback is raw: opt.schema/cfg.schema are only applied on the Verify path.
201
+ */
202
+ tryToVerifyOrDecode<TT extends T = T>(token: JWTString, opt?: JWTVerifyOptions<TT>): Promise<[err: null, payload: TT] | [err: Error, payload: TT | null]>;
178
203
  decode<TT extends T = T>(token: JWTString, opt?: JWTDecodeOptions<TT>): JWTDecoded<TT>;
179
204
  /**
180
205
  * Schema-validation errors on Verify/Decode are extended with cfg.errorData:
@@ -88,6 +88,52 @@ export class JWTService2 {
88
88
  this.validate(data, schema);
89
89
  return data;
90
90
  }
91
+ /**
92
+ * Tries to Verify the token, returning an [error, payload] tuple instead of throwing:
93
+ * - [null, payload] - the token verified, payload can be trusted
94
+ * - [error, null] - verification failed
95
+ *
96
+ * Same contract as tryToVerifyOrDecode, but without the unverified-decode fallback:
97
+ * the payload is only returned when the token verified.
98
+ */
99
+ async tryToVerify(token, opt = {}) {
100
+ try {
101
+ return [null, await this.verify(token, opt)];
102
+ }
103
+ catch (err) {
104
+ return [err, null];
105
+ }
106
+ }
107
+ /**
108
+ * Tries to Verify the token, falling back to unverified Decode on failure,
109
+ * so the caller can "peek" into the token's content even when it doesn't verify.
110
+ *
111
+ * Returns an [error, payload] tuple - ALWAYS check the error first:
112
+ * - [null, payload] - the token verified, payload can be trusted
113
+ * - [error, payload] - verification failed, but the token could still be decoded.
114
+ * When the error is JWTExpiredError/JWTNotYetValidError, the signature was already
115
+ * verified and only the time-claim check failed, so the payload is trustworthy
116
+ * (just expired/not yet valid). For any other error the payload is completely
117
+ * UNVERIFIED - never trust it, only peek (e.g to log/report the claimed identity).
118
+ * - [error, null] - the token could not even be decoded
119
+ *
120
+ * The decode fallback is raw: opt.schema/cfg.schema are only applied on the Verify path.
121
+ */
122
+ async tryToVerifyOrDecode(token, opt = {}) {
123
+ const [verifyError, payload] = await this.tryToVerify(token, opt);
124
+ if (!verifyError)
125
+ return [null, payload];
126
+ // Expired/not-yet-valid errors already carry the (signature-verified) payload
127
+ if (verifyError instanceof JWTExpiredError || verifyError instanceof JWTNotYetValidError) {
128
+ return [verifyError, verifyError.payload];
129
+ }
130
+ try {
131
+ return [verifyError, jwtDecode(token).payload];
132
+ }
133
+ catch {
134
+ return [verifyError, null];
135
+ }
136
+ }
91
137
  decode(token, opt = {}) {
92
138
  let decoded;
93
139
  try {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@naturalcycles/nodejs-lib",
3
3
  "type": "module",
4
- "version": "15.117.0",
4
+ "version": "15.119.0",
5
5
  "dependencies": {
6
6
  "@naturalcycles/js-lib": "^15",
7
7
  "@standard-schema/spec": "^1",
@@ -274,6 +274,59 @@ export class JWTService2<T extends AnyObject = AnyObject> {
274
274
  return data
275
275
  }
276
276
 
277
+ /**
278
+ * Tries to Verify the token, returning an [error, payload] tuple instead of throwing:
279
+ * - [null, payload] - the token verified, payload can be trusted
280
+ * - [error, null] - verification failed
281
+ *
282
+ * Same contract as tryToVerifyOrDecode, but without the unverified-decode fallback:
283
+ * the payload is only returned when the token verified.
284
+ */
285
+ async tryToVerify<TT extends T = T>(
286
+ token: JWTString,
287
+ opt: JWTVerifyOptions<TT> = {},
288
+ ): Promise<[err: null, payload: TT] | [err: Error, payload: null]> {
289
+ try {
290
+ return [null, await this.verify<TT>(token, opt)]
291
+ } catch (err) {
292
+ return [err as Error, null]
293
+ }
294
+ }
295
+
296
+ /**
297
+ * Tries to Verify the token, falling back to unverified Decode on failure,
298
+ * so the caller can "peek" into the token's content even when it doesn't verify.
299
+ *
300
+ * Returns an [error, payload] tuple - ALWAYS check the error first:
301
+ * - [null, payload] - the token verified, payload can be trusted
302
+ * - [error, payload] - verification failed, but the token could still be decoded.
303
+ * When the error is JWTExpiredError/JWTNotYetValidError, the signature was already
304
+ * verified and only the time-claim check failed, so the payload is trustworthy
305
+ * (just expired/not yet valid). For any other error the payload is completely
306
+ * UNVERIFIED - never trust it, only peek (e.g to log/report the claimed identity).
307
+ * - [error, null] - the token could not even be decoded
308
+ *
309
+ * The decode fallback is raw: opt.schema/cfg.schema are only applied on the Verify path.
310
+ */
311
+ async tryToVerifyOrDecode<TT extends T = T>(
312
+ token: JWTString,
313
+ opt: JWTVerifyOptions<TT> = {},
314
+ ): Promise<[err: null, payload: TT] | [err: Error, payload: TT | null]> {
315
+ const [verifyError, payload] = await this.tryToVerify<TT>(token, opt)
316
+ if (!verifyError) return [null, payload]
317
+
318
+ // Expired/not-yet-valid errors already carry the (signature-verified) payload
319
+ if (verifyError instanceof JWTExpiredError || verifyError instanceof JWTNotYetValidError) {
320
+ return [verifyError, verifyError.payload as TT]
321
+ }
322
+
323
+ try {
324
+ return [verifyError, jwtDecode<TT>(token).payload]
325
+ } catch {
326
+ return [verifyError, null]
327
+ }
328
+ }
329
+
277
330
  decode<TT extends T = T>(token: JWTString, opt: JWTDecodeOptions<TT> = {}): JWTDecoded<TT> {
278
331
  let decoded: JWTDecoded<TT>
279
332