@fluojs/jwt 1.0.1 → 1.0.3

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/README.ko.md CHANGED
@@ -150,7 +150,7 @@ const verifier = new DefaultJwtVerifier({
150
150
 
151
151
  `jwksRequestTimeoutMs`의 기본값은 `5_000`이며, 예산을 넘기면 진행 중인 JWKS fetch를 abort합니다.
152
152
 
153
- JWKS key는 `jwksCacheTtl` 밀리초 동안 cache되며 기본값은 `600_000`입니다. in-memory cache는 `jwksCacheMaxEntries`로 제한되고 기본값은 `100`입니다. lookup 전 만료된 entry를 정리하고, 제한을 넘으면 가장 오래 보관된 key를 제거합니다. 수동 shutdown이나 identity-provider 재설정 시에는 `JwksClient.dispose()` / `DefaultJwtVerifier.dispose()`로 보관 중인 remote key material을 비울 수 있습니다. `jwksCacheTtl`을 `0`으로 설정하면 bounded fetch timeout은 유지하면서 key 보관만 비활성화합니다.
153
+ JWKS key는 `jwksCacheTtl` 밀리초 동안 cache되며 기본값은 `600_000`입니다. in-memory cache는 `jwksCacheMaxEntries`로 제한되고 기본값은 `100`입니다. lookup 전 만료된 entry를 정리하고, 제한을 넘으면 가장 오래 보관된 key를 제거합니다. `JwtModule`은 관리 중인 `DefaultJwtVerifier` shutdown hook을 호출하므로 module teardown 중 보관 중인 remote key material이 정리됩니다. 수동으로 생성한 verifier나 client는 수동 shutdown 또는 identity-provider 재설정 여전히 `JwksClient.dispose()` / `DefaultJwtVerifier.dispose()`를 호출해야 합니다. `jwksCacheTtl`을 `0`으로 설정하면 bounded fetch timeout은 유지하면서 key 보관만 비활성화합니다.
154
154
 
155
155
  `JwtService.verify(token, options)`는 호출 단위의 알고리즘/클레임 정책 재정의(`issuer`, `audience`, `clockSkewSeconds`, `maxAge`, `requireExp`)를 적용하더라도, 내부 JWKS client나 정적 key-resolution cache를 다시 만들지 않습니다. 호출 단위 검증은 `jwksUri`, `keys[]`, `publicKey`, `secret`, `secretOrKeyProvider` 같은 구성된 key source 자체를 교체하지는 않습니다.
156
156
 
@@ -170,6 +170,8 @@ JWT 서명과 검증에는 `algorithms`에 지원되는 알고리즘이 하나
170
170
 
171
171
  검증은 잘못된 시간 정책에 대해 fail closed로 동작합니다. 검증에 참여하는 `exp`, `nbf`, `iat` 클레임은 유한한 JWT NumericDate 숫자여야 하며, `clockSkewSeconds`도 음수가 아닌 유한 숫자여야 합니다. 유한하지 않은 값은 expiration, not-before, age check를 늘리는 대신 거부됩니다. verifier 시간이 `exp` NumericDate에 도달하면 토큰은 만료된 것으로 처리되며, 양수 clock skew가 경계를 덮지 않는 한 equality도 만료로 간주합니다.
172
172
 
173
+ 루트 `@fluojs/jwt` import surface는 runtime-specific 인증 경로를 선택하기 전에도 안전하게 로드할 수 있습니다. Node.js `node:crypto` primitive는 서명, 검증, JWKS key parsing, refresh-token id 생성이 실제로 실행될 때만 lazy load됩니다. 이 방식은 기존 public export를 유지하면서 module import 시점의 Node-specific crypto 작업을 피합니다.
174
+
173
175
  ## 공개 API 개요
174
176
 
175
177
  ### 주요 클래스
@@ -192,6 +194,9 @@ JWT 서명과 검증에는 `algorithms`에 지원되는 알고리즘이 하나
192
194
  - `createJwtPlatformStatusSnapshot(...)`, `createJwtPlatformDiagnosticIssues(...)`: status 및 diagnostic helper입니다.
193
195
  - `JWT_OPTIONS`, `HMAC_HASH`, `ASYMMETRIC_HASH`: 모듈과 검증 레이어에서 사용하는 export token/constant입니다.
194
196
 
197
+ ### Deprecated compatibility helper
198
+ - `normalizeRefreshTokenOptions(...)`: 기존 caller의 root import 호환성만을 위해 유지됩니다. package normalization 내부 helper를 직접 호출하기보다 `JwtModule.forRoot(...)` / `JwtModule.forRootAsync(...)`와 `RefreshTokenService`를 사용하세요.
199
+
195
200
  ## 관련 패키지
196
201
 
197
202
  - `@fluojs/passport`: 이 코어 패키지를 사용하여 가드와 전략을 실행하는 인증 계층입니다.
package/README.md CHANGED
@@ -150,7 +150,7 @@ const verifier = new DefaultJwtVerifier({
150
150
 
151
151
  `jwksRequestTimeoutMs` defaults to `5_000` and aborts the outbound JWKS fetch once that budget is exceeded.
152
152
 
153
- JWKS keys are cached for `jwksCacheTtl` milliseconds (`600_000` by default) and the in-memory cache is bounded by `jwksCacheMaxEntries` (`100` by default). Expired entries are pruned before lookups, the oldest retained key is evicted when the bound is exceeded, and `JwksClient.dispose()` / `DefaultJwtVerifier.dispose()` clears retained remote key material during manual shutdown or identity-provider reconfiguration. A `jwksCacheTtl` of `0` disables key retention while still using bounded fetch timeouts.
153
+ JWKS keys are cached for `jwksCacheTtl` milliseconds (`600_000` by default) and the in-memory cache is bounded by `jwksCacheMaxEntries` (`100` by default). Expired entries are pruned before lookups, the oldest retained key is evicted when the bound is exceeded, and `JwtModule` calls the managed `DefaultJwtVerifier` shutdown hook so retained remote key material is cleared during module teardown. Manually constructed verifiers or clients should still call `JwksClient.dispose()` / `DefaultJwtVerifier.dispose()` during manual shutdown or identity-provider reconfiguration. A `jwksCacheTtl` of `0` disables key retention while still using bounded fetch timeouts.
154
154
 
155
155
  `JwtService.verify(token, options)` applies per-call algorithm and claim-policy overrides (`issuer`, `audience`, `clockSkewSeconds`, `maxAge`, `requireExp`) without rebuilding the underlying JWKS client or static key-resolution cache. Per-call verification does not replace configured key sources such as `jwksUri`, `keys[]`, `publicKey`, `secret`, or `secretOrKeyProvider`.
156
156
 
@@ -170,6 +170,8 @@ Access-token TTL must also be a positive finite number. When `accessTokenTtlSeco
170
170
 
171
171
  Verification fails closed on malformed time policy. `exp`, `nbf`, and `iat` claims that participate in verification must be finite JWT NumericDate numbers, and `clockSkewSeconds` must be a non-negative finite number. Non-finite values are rejected instead of extending expiration, not-before, or age checks. A token is expired when verifier time reaches its `exp` NumericDate; equality is treated as expired unless positive clock skew still covers the boundary.
172
172
 
173
+ The root `@fluojs/jwt` import surface is safe to load before selecting a runtime-specific authentication path: Node.js `node:crypto` primitives are loaded lazily only when signing, verification, JWKS key parsing, or refresh-token id generation actually executes. This preserves the existing public exports while avoiding Node-specific crypto work at module import time.
174
+
173
175
  ## Public API Overview
174
176
 
175
177
  ### Core Classes
@@ -192,6 +194,9 @@ Verification fails closed on malformed time policy. `exp`, `nbf`, and `iat` clai
192
194
  - `createJwtPlatformStatusSnapshot(...)` and `createJwtPlatformDiagnosticIssues(...)`: Status and diagnostic helpers.
193
195
  - `JWT_OPTIONS`, `HMAC_HASH`, `ASYMMETRIC_HASH`: Exported tokens/constants used by the module and verification layer.
194
196
 
197
+ ### Deprecated compatibility helpers
198
+ - `normalizeRefreshTokenOptions(...)`: Retained only for root-import compatibility with existing callers. Prefer `JwtModule.forRoot(...)` / `JwtModule.forRootAsync(...)` plus `RefreshTokenService` instead of calling package normalization internals.
199
+
195
200
  ## Related Packages
196
201
 
197
202
  - `@fluojs/passport`: The auth execution layer that uses this core for guards and strategies.
package/dist/index.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  export * from './errors.js';
2
2
  export * from './signing/jwks.js';
3
3
  export * from './module.js';
4
- export * from './refresh/refresh-token.js';
4
+ export { RefreshTokenService, normalizeRefreshTokenOptions, } from './refresh/refresh-token.js';
5
+ export type { RefreshTokenConsumeInput, RefreshTokenConsumeResult, RefreshTokenOptions, RefreshTokenRecord, RefreshTokenRotateInput, RefreshTokenStore, } from './refresh/refresh-token.js';
5
6
  export * from './service.js';
6
7
  export * from './signing/signer.js';
7
8
  export * from './status.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,4BAA4B,CAAC;AAC3C,cAAc,cAAc,CAAC;AAC7B,cAAc,qBAAqB,CAAC;AACpC,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,OAAO,EACL,mBAAmB,EACnB,4BAA4B,GAC7B,MAAM,4BAA4B,CAAC;AACpC,YAAY,EACV,wBAAwB,EACxB,yBAAyB,EACzB,mBAAmB,EACnB,kBAAkB,EAClB,uBAAuB,EACvB,iBAAiB,GAClB,MAAM,4BAA4B,CAAC;AACpC,cAAc,cAAc,CAAC;AAC7B,cAAc,qBAAqB,CAAC;AACpC,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,uBAAuB,CAAC"}
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  export * from './errors.js';
2
2
  export * from './signing/jwks.js';
3
3
  export * from './module.js';
4
- export * from './refresh/refresh-token.js';
4
+ export { RefreshTokenService, normalizeRefreshTokenOptions } from './refresh/refresh-token.js';
5
5
  export * from './service.js';
6
6
  export * from './signing/signer.js';
7
7
  export * from './status.js';
@@ -52,7 +52,12 @@ export interface RefreshTokenOptions {
52
52
  store: RefreshTokenStore;
53
53
  }
54
54
  /**
55
- * Normalize refresh token options.
55
+ * Normalize refresh token options for legacy root-import callers.
56
+ *
57
+ * @deprecated This helper is retained only for compatibility with existing
58
+ * root `@fluojs/jwt` imports. Prefer configuring refresh tokens through
59
+ * `JwtModule.forRoot(...)` / `JwtModule.forRootAsync(...)` and resolving
60
+ * `RefreshTokenService` instead of calling package normalization internals.
56
61
  *
57
62
  * @param options The options.
58
63
  * @returns The normalize refresh token options result.
@@ -1 +1 @@
1
- {"version":3,"file":"refresh-token.d.ts","sourceRoot":"","sources":["../../src/refresh/refresh-token.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAEjE;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,SAAS,CAAC,CAAC;IAC/D,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,OAAO,CAAC,CAAC,KAAK,EAAE,wBAAwB,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAAC;IAC9E,MAAM,CAAC,CAAC,KAAK,EAAE,uBAAuB,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAAC;CAC7E;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,IAAI,CAAC;CACX;AAED;;GAEG;AACH,MAAM,WAAW,uBAAwB,SAAQ,wBAAwB;IACvE,WAAW,EAAE,kBAAkB,CAAC;CACjC;AAED;;GAEG;AACH,MAAM,MAAM,yBAAyB,GAAG,UAAU,GAAG,cAAc,GAAG,SAAS,GAAG,WAAW,GAAG,UAAU,GAAG,SAAS,CAAC;AAEvH;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,IAAI,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,IAAI,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,MAAM,CAAC;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,iBAAiB,CAAC;CAC1B;AAED;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,mBAAmB,GAAG,SAAS,GAAG,mBAAmB,CA6B1G;AAQD;;GAEG;AACH,qBAAa,mBAAmB;IAK5B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAL3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsB;gBAG5C,OAAO,EAAE,mBAAmB,EACX,MAAM,EAAE,gBAAgB,EACxB,QAAQ,EAAE,kBAAkB;IAKzC,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAMnD,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC;IA0EhG,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlD,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAI3C,2BAA2B;YAQ3B,mBAAmB;YAUnB,4BAA4B;YA8B5B,mBAAmB;CA4BlC"}
1
+ {"version":3,"file":"refresh-token.d.ts","sourceRoot":"","sources":["../../src/refresh/refresh-token.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAEjE;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,SAAS,CAAC,CAAC;IAC/D,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,OAAO,CAAC,CAAC,KAAK,EAAE,wBAAwB,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAAC;IAC9E,MAAM,CAAC,CAAC,KAAK,EAAE,uBAAuB,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAAC;CAC7E;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,IAAI,CAAC;CACX;AAED;;GAEG;AACH,MAAM,WAAW,uBAAwB,SAAQ,wBAAwB;IACvE,WAAW,EAAE,kBAAkB,CAAC;CACjC;AAED;;GAEG;AACH,MAAM,MAAM,yBAAyB,GAAG,UAAU,GAAG,cAAc,GAAG,SAAS,GAAG,WAAW,GAAG,UAAU,GAAG,SAAS,CAAC;AAEvH;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,IAAI,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,IAAI,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,MAAM,CAAC;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,iBAAiB,CAAC;CAC1B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,mBAAmB,GAAG,SAAS,GAAG,mBAAmB,CA6B1G;AAQD;;GAEG;AACH,qBAAa,mBAAmB;IAK5B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAL3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsB;gBAG5C,OAAO,EAAE,mBAAmB,EACX,MAAM,EAAE,gBAAgB,EACxB,QAAQ,EAAE,kBAAkB;IAKzC,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAOnD,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC;IA0EhG,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlD,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAI3C,2BAA2B;YAQ3B,mBAAmB;YAUnB,4BAA4B;YA+B5B,mBAAmB;CA4BlC"}
@@ -1,4 +1,3 @@
1
- import { randomUUID } from 'node:crypto';
2
1
  import { JwtConfigurationError, JwtExpiredTokenError, JwtInvalidTokenError } from '../errors.js';
3
2
 
4
3
  /**
@@ -26,7 +25,12 @@ import { JwtConfigurationError, JwtExpiredTokenError, JwtInvalidTokenError } fro
26
25
  */
27
26
 
28
27
  /**
29
- * Normalize refresh token options.
28
+ * Normalize refresh token options for legacy root-import callers.
29
+ *
30
+ * @deprecated This helper is retained only for compatibility with existing
31
+ * root `@fluojs/jwt` imports. Prefer configuring refresh tokens through
32
+ * `JwtModule.forRoot(...)` / `JwtModule.forRootAsync(...)` and resolving
33
+ * `RefreshTokenService` instead of calling package normalization internals.
30
34
  *
31
35
  * @param options The options.
32
36
  * @returns The normalize refresh token options result.
@@ -62,6 +66,9 @@ export class RefreshTokenService {
62
66
  this.options = normalizeRefreshTokenOptions(options);
63
67
  }
64
68
  async issueRefreshToken(subject) {
69
+ const {
70
+ randomUUID
71
+ } = await import('node:crypto');
65
72
  const family = randomUUID();
66
73
  return this.issueRefreshTokenWithFamily(subject, family);
67
74
  }
@@ -152,6 +159,9 @@ export class RefreshTokenService {
152
159
  }
153
160
  async createRefreshTokenWithFamily(subject, family) {
154
161
  const now = Math.floor(Date.now() / 1000);
162
+ const {
163
+ randomUUID
164
+ } = await import('node:crypto');
155
165
  const tokenId = randomUUID();
156
166
  const expiresAt = new Date((now + this.options.expiresInSeconds) * 1000);
157
167
  const record = {
@@ -1,4 +1,4 @@
1
- import { type KeyObject } from 'node:crypto';
1
+ import type { KeyObject } from 'node:crypto';
2
2
  /**
3
3
  * Represents the jwks client.
4
4
  */
@@ -1 +1 @@
1
- {"version":3,"file":"jwks.d.ts","sourceRoot":"","sources":["../../src/signing/jwks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AAiC9D;;GAEG;AACH,qBAAa,UAAU;IAKnB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IACjC,OAAO,CAAC,QAAQ,CAAC,eAAe;IAPlC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA4D;IAClF,OAAO,CAAC,mBAAmB,CAAK;gBAGb,GAAG,EAAE,MAAM,EACX,QAAQ,GAAE,MAAgB,EAC1B,gBAAgB,GAAE,MAAc,EAChC,eAAe,GAAE,MAAuC;IAO3E;;;;;OAKG;IACH,OAAO,IAAI,IAAI;IAKf,OAAO,CAAC,YAAY;IAId,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IA0CpD,OAAO,CAAC,wBAAwB;IAQhC,OAAO,CAAC,uBAAuB;YAYjB,SAAS;CAsCxB"}
1
+ {"version":3,"file":"jwks.d.ts","sourceRoot":"","sources":["../../src/signing/jwks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAiC7C;;GAEG;AACH,qBAAa,UAAU;IAKnB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IACjC,OAAO,CAAC,QAAQ,CAAC,eAAe;IAPlC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA4D;IAClF,OAAO,CAAC,mBAAmB,CAAK;gBAGb,GAAG,EAAE,MAAM,EACX,QAAQ,GAAE,MAAgB,EAC1B,gBAAgB,GAAE,MAAc,EAChC,eAAe,GAAE,MAAuC;IAO3E;;;;;OAKG;IACH,OAAO,IAAI,IAAI;IAKf,OAAO,CAAC,YAAY;IAId,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IA2CpD,OAAO,CAAC,wBAAwB;IAQhC,OAAO,CAAC,uBAAuB;YAYjB,SAAS;CAsCxB"}
@@ -1,4 +1,3 @@
1
- import { createPublicKey } from 'node:crypto';
2
1
  import { JwtConfigurationError, JwtInvalidTokenError } from '../errors.js';
3
2
  const DEFAULT_JWKS_CACHE_MAX_ENTRIES = 100;
4
3
  function assertNonNegativeFiniteNumber(value, label) {
@@ -64,6 +63,9 @@ export class JwksClient {
64
63
  }
65
64
  let key;
66
65
  try {
66
+ const {
67
+ createPublicKey
68
+ } = await import('node:crypto');
67
69
  key = createPublicKey({
68
70
  format: 'jwk',
69
71
  key: jwk
@@ -1 +1 @@
1
- {"version":3,"file":"signer.d.ts","sourceRoot":"","sources":["../../src/signing/signer.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAgB,SAAS,EAAe,kBAAkB,EAAE,MAAM,aAAa,CAAC;AA0D5F;;GAEG;AACH,qBACa,gBAAgB;IAGf,OAAO,CAAC,QAAQ,CAAC,OAAO;IAFpC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAiB;gBAEtB,OAAO,EAAE,kBAAkB;IAOlD,eAAe,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC;IAInD,gBAAgB,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC;IAK1D,OAAO,CAAC,4BAA4B;YAYtB,SAAS;CAkFxB"}
1
+ {"version":3,"file":"signer.d.ts","sourceRoot":"","sources":["../../src/signing/signer.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAgB,SAAS,EAAe,kBAAkB,EAAE,MAAM,aAAa,CAAC;AA0D5F;;GAEG;AACH,qBACa,gBAAgB;IAGf,OAAO,CAAC,QAAQ,CAAC,OAAO;IAFpC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAiB;gBAEtB,OAAO,EAAE,kBAAkB;IAOlD,eAAe,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC;IAInD,gBAAgB,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC;IAK1D,OAAO,CAAC,4BAA4B;YAYtB,SAAS;CAoFxB"}
@@ -4,7 +4,6 @@ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol"
4
4
  function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
5
5
  function _setFunctionName(e, t, n) { "symbol" == typeof t && (t = (t = t.description) ? "[" + t + "]" : ""); try { Object.defineProperty(e, "name", { configurable: !0, value: n ? n + " " + t : t }); } catch (e) {} return e; }
6
6
  function _checkInRHS(e) { if (Object(e) !== e) throw TypeError("right-hand side of 'in' should be an object, got " + (null !== e ? typeof e : "null")); return e; }
7
- import { createHmac, createSign } from 'node:crypto';
8
7
  import { Inject } from '@fluojs/core';
9
8
  import { JwtConfigurationError } from '../errors.js';
10
9
  import { normalizeRefreshTokenOptions } from '../refresh/refresh-token.js';
@@ -121,6 +120,9 @@ class DefaultJwtSigner {
121
120
  if (!hash) {
122
121
  throw new JwtConfigurationError(`No hash mapping for asymmetric algorithm "${algorithm}".`);
123
122
  }
123
+ const {
124
+ createSign
125
+ } = await import('node:crypto');
124
126
  const signer = createSign(hash);
125
127
  signer.update(signingInput);
126
128
  const isEc = algorithm.startsWith('ES');
@@ -137,6 +139,9 @@ class DefaultJwtSigner {
137
139
  if (!hash) {
138
140
  throw new JwtConfigurationError(`No hash mapping for HMAC algorithm "${algorithm}".`);
139
141
  }
142
+ const {
143
+ createHmac
144
+ } = await import('node:crypto');
140
145
  signatureSegment = encodeBase64Url(createHmac(hash, secret).update(signingInput).digest());
141
146
  }
142
147
  return `${headerSegment}.${payloadSegment}.${signatureSegment}`;
@@ -1,5 +1,5 @@
1
1
  import type { JwtPrincipal, JwtVerifierOptions } from '../types.js';
2
- import { DefaultJwtVerifier } from './verifier.js';
2
+ import type { DefaultJwtVerifier } from './verifier.js';
3
3
  type AccessTokenVerificationOverrides = Pick<JwtVerifierOptions, 'algorithms' | 'audience' | 'clockSkewSeconds' | 'issuer' | 'maxAge' | 'requireExp'>;
4
4
  /**
5
5
  * Applies supported per-call access-token overrides through the verifier's public API.
@@ -1 +1 @@
1
- {"version":3,"file":"verifier-internal.d.ts","sourceRoot":"","sources":["../../src/signing/verifier-internal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAEnD,KAAK,gCAAgC,GAAG,IAAI,CAC1C,kBAAkB,EAClB,YAAY,GAAG,UAAU,GAAG,kBAAkB,GAAG,QAAQ,GAAG,QAAQ,GAAG,YAAY,CACpF,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,8BAA8B,CAC5C,QAAQ,EAAE,kBAAkB,EAC5B,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,OAAO,CAAC,gCAAgC,CAAC,GACnD,OAAO,CAAC,YAAY,CAAC,CAEvB"}
1
+ {"version":3,"file":"verifier-internal.d.ts","sourceRoot":"","sources":["../../src/signing/verifier-internal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEpE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAExD,KAAK,gCAAgC,GAAG,IAAI,CAC1C,kBAAkB,EAClB,YAAY,GAAG,UAAU,GAAG,kBAAkB,GAAG,QAAQ,GAAG,QAAQ,GAAG,YAAY,CACpF,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,8BAA8B,CAC5C,QAAQ,EAAE,kBAAkB,EAC5B,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,OAAO,CAAC,gCAAgC,CAAC,GACnD,OAAO,CAAC,YAAY,CAAC,CAEvB"}
@@ -1,3 +1,4 @@
1
+ import type { OnModuleDestroy } from '@fluojs/runtime';
1
2
  import type { JwtAlgorithm, JwtPrincipal, JwtVerifierOptions } from '../types.js';
2
3
  /**
3
4
  * Provides the resolved JWT verifier options through dependency injection.
@@ -15,7 +16,7 @@ type AccessTokenVerificationOverrides = Pick<JwtVerifierOptions, 'algorithms' |
15
16
  /**
16
17
  * Verifies JWT access and refresh tokens against the configured key sources.
17
18
  */
18
- export declare class DefaultJwtVerifier {
19
+ export declare class DefaultJwtVerifier implements OnModuleDestroy {
19
20
  private readonly options;
20
21
  private readonly jwksClient;
21
22
  private readonly keyResolutionState;
@@ -31,6 +32,10 @@ export declare class DefaultJwtVerifier {
31
32
  * owned by the verifier and are therefore left untouched.
32
33
  */
33
34
  dispose(): void;
35
+ /**
36
+ * Releases verifier-owned remote JWKS cache entries during module teardown.
37
+ */
38
+ onModuleDestroy(): void;
34
39
  /**
35
40
  * Verifies a JWT access token with per-call claim-policy overrides while reusing configured key sources.
36
41
  *
@@ -1 +1 @@
1
- {"version":3,"file":"verifier.d.ts","sourceRoot":"","sources":["../../src/signing/verifier.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,YAAY,EAA0B,YAAY,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAG1G;;GAEG;AACH,eAAO,MAAM,WAAW,eAAiC,CAAC;AAE1D;;GAEG;AACH,eAAO,MAAM,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,CAI3D,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe,EAAE,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,CAOjE,CAAC;AAmDF,KAAK,gCAAgC,GAAG,IAAI,CAC1C,kBAAkB,EAClB,YAAY,GAAG,UAAU,GAAG,kBAAkB,GAAG,QAAQ,GAAG,QAAQ,GAAG,YAAY,CACpF,CAAC;AA+LF;;GAEG;AACH,qBACa,kBAAkB;IAMjB,OAAO,CAAC,QAAQ,CAAC,OAAO;IALpC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAyB;IACpD,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAqB;IACxD,OAAO,CAAC,QAAQ,CAAC,yBAAyB,CAAqB;IAC/D,OAAO,CAAC,QAAQ,CAAC,0BAA0B,CAAiC;gBAE/C,OAAO,EAAE,kBAAkB;IAalD,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAI7D;;;;;;OAMG;IACH,OAAO,IAAI,IAAI;IAIf;;;;;;;;;;OAUG;IACG,8BAA8B,CAClC,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,OAAO,CAAC,gCAAgC,CAAC,GACnD,OAAO,CAAC,YAAY,CAAC;IAqBlB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAQ9D,OAAO,CAAC,gCAAgC;YAsB1B,WAAW;IA+BzB,OAAO,CAAC,kBAAkB;YAUZ,oBAAoB;YAgBpB,wBAAwB;YAsBxB,8BAA8B;YAsB9B,kBAAkB;IAWhC,OAAO,CAAC,mBAAmB;IAwB3B,OAAO,CAAC,oBAAoB;IA2B5B,OAAO,CAAC,yBAAyB;YAiBnB,oBAAoB;CAOnC"}
1
+ {"version":3,"file":"verifier.d.ts","sourceRoot":"","sources":["../../src/signing/verifier.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAIvD,OAAO,KAAK,EAAE,YAAY,EAA0B,YAAY,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAG1G;;GAEG;AACH,eAAO,MAAM,WAAW,eAAiC,CAAC;AAE1D;;GAEG;AACH,eAAO,MAAM,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,CAI3D,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe,EAAE,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,CAOjE,CAAC;AAmDF,KAAK,gCAAgC,GAAG,IAAI,CAC1C,kBAAkB,EAClB,YAAY,GAAG,UAAU,GAAG,kBAAkB,GAAG,QAAQ,GAAG,QAAQ,GAAG,YAAY,CACpF,CAAC;AAiMF;;GAEG;AACH,qBACa,kBAAmB,YAAW,eAAe;IAM5C,OAAO,CAAC,QAAQ,CAAC,OAAO;IALpC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAyB;IACpD,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAqB;IACxD,OAAO,CAAC,QAAQ,CAAC,yBAAyB,CAAqB;IAC/D,OAAO,CAAC,QAAQ,CAAC,0BAA0B,CAAiC;gBAE/C,OAAO,EAAE,kBAAkB;IAalD,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAI7D;;;;;;OAMG;IACH,OAAO,IAAI,IAAI;IAIf;;OAEG;IACH,eAAe,IAAI,IAAI;IAIvB;;;;;;;;;;OAUG;IACG,8BAA8B,CAClC,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,OAAO,CAAC,gCAAgC,CAAC,GACnD,OAAO,CAAC,YAAY,CAAC;IAqBlB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAQ9D,OAAO,CAAC,gCAAgC;YAsB1B,WAAW;IA+BzB,OAAO,CAAC,kBAAkB;YAUZ,oBAAoB;YAgBpB,wBAAwB;YAsBxB,8BAA8B;YAsB9B,kBAAkB;IAWhC,OAAO,CAAC,mBAAmB;IAwB3B,OAAO,CAAC,oBAAoB;IA2B5B,OAAO,CAAC,yBAAyB;YAiBnB,oBAAoB;CAOnC"}
@@ -4,7 +4,6 @@ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol"
4
4
  function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
5
5
  function _setFunctionName(e, t, n) { "symbol" == typeof t && (t = (t = t.description) ? "[" + t + "]" : ""); try { Object.defineProperty(e, "name", { configurable: !0, value: n ? n + " " + t : t }); } catch (e) {} return e; }
6
6
  function _checkInRHS(e) { if (Object(e) !== e) throw TypeError("right-hand side of 'in' should be an object, got " + (null !== e ? typeof e : "null")); return e; }
7
- import { createHmac, createVerify, timingSafeEqual } from 'node:crypto';
8
7
  import { Inject } from '@fluojs/core';
9
8
  import { JwtConfigurationError, JwtExpiredTokenError, JwtInvalidTokenError } from '../errors.js';
10
9
  import { normalizeRefreshTokenOptions } from '../refresh/refresh-token.js';
@@ -130,11 +129,15 @@ function resolveStaticPublicKey(options, keyState, kid) {
130
129
  }
131
130
  return keyState.defaultPublicKey ?? options.publicKey;
132
131
  }
133
- function verifyHmacSignature(algorithm, secret, signingInput, signatureSegment) {
132
+ async function verifyHmacSignature(algorithm, secret, signingInput, signatureSegment) {
134
133
  const hash = HMAC_HASH[algorithm];
135
134
  if (!hash) {
136
135
  throw new JwtInvalidTokenError();
137
136
  }
137
+ const {
138
+ createHmac,
139
+ timingSafeEqual
140
+ } = await import('node:crypto');
138
141
  const expected = encodeBase64Url(createHmac(hash, secret).update(signingInput).digest());
139
142
  const expectedBuf = Buffer.from(expected, 'base64url');
140
143
  const actualBuf = Buffer.from(signatureSegment, 'base64url');
@@ -142,11 +145,14 @@ function verifyHmacSignature(algorithm, secret, signingInput, signatureSegment)
142
145
  throw new JwtInvalidTokenError();
143
146
  }
144
147
  }
145
- function verifyAsymmetricSignature(algorithm, publicKey, signingInput, signatureSegment) {
148
+ async function verifyAsymmetricSignature(algorithm, publicKey, signingInput, signatureSegment) {
146
149
  const hash = ASYMMETRIC_HASH[algorithm];
147
150
  if (!hash) {
148
151
  throw new JwtInvalidTokenError();
149
152
  }
153
+ const {
154
+ createVerify
155
+ } = await import('node:crypto');
150
156
  const verifier = createVerify(hash);
151
157
  verifier.update(signingInput);
152
158
  const isEc = algorithm.startsWith('ES');
@@ -226,6 +232,13 @@ class DefaultJwtVerifier {
226
232
  this.jwksClient?.dispose();
227
233
  }
228
234
 
235
+ /**
236
+ * Releases verifier-owned remote JWKS cache entries during module teardown.
237
+ */
238
+ onModuleDestroy() {
239
+ this.dispose();
240
+ }
241
+
229
242
  /**
230
243
  * Verifies a JWT access token with per-call claim-policy overrides while reusing configured key sources.
231
244
  *
@@ -310,7 +323,7 @@ class DefaultJwtVerifier {
310
323
  if (!secret) {
311
324
  throw new JwtConfigurationError('JWT secret is not configured.');
312
325
  }
313
- verifyHmacSignature(header.alg, secret, signingInput, signatureSegment);
326
+ await verifyHmacSignature(header.alg, secret, signingInput, signatureSegment);
314
327
  }
315
328
  async verifyAsymmetricTokenSignature(header, signingInput, signatureSegment, options, keyResolutionState, jwksClient) {
316
329
  const providerKey = await this.resolveProviderKey(options, header);
@@ -318,7 +331,7 @@ class DefaultJwtVerifier {
318
331
  if (!publicKey) {
319
332
  throw new JwtConfigurationError('JWT public key is not configured.');
320
333
  }
321
- verifyAsymmetricSignature(header.alg, publicKey, signingInput, signatureSegment);
334
+ await verifyAsymmetricSignature(header.alg, publicKey, signingInput, signatureSegment);
322
335
  }
323
336
  async resolveProviderKey(options, header) {
324
337
  if (!options.secretOrKeyProvider) {
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "signing",
10
10
  "verification"
11
11
  ],
12
- "version": "1.0.1",
12
+ "version": "1.0.3",
13
13
  "private": false,
14
14
  "license": "MIT",
15
15
  "repository": {
@@ -36,9 +36,9 @@
36
36
  "dist"
37
37
  ],
38
38
  "dependencies": {
39
- "@fluojs/di": "^1.0.3",
40
39
  "@fluojs/core": "^1.0.3",
41
- "@fluojs/runtime": "^1.1.1"
40
+ "@fluojs/di": "^1.1.0",
41
+ "@fluojs/runtime": "^1.1.8"
42
42
  },
43
43
  "devDependencies": {
44
44
  "vitest": "^3.2.4"