@peac/jwks-cache 0.10.7 → 0.10.9
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/dist/cache.d.ts +20 -1
- package/dist/cache.d.ts.map +1 -1
- package/dist/cache.js +40 -3
- package/dist/cache.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/resolver.d.ts +5 -2
- package/dist/resolver.d.ts.map +1 -1
- package/dist/resolver.js +48 -5
- package/dist/resolver.js.map +1 -1
- package/dist/types.d.ts +18 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
package/dist/cache.d.ts
CHANGED
|
@@ -2,12 +2,27 @@
|
|
|
2
2
|
* In-memory cache implementation.
|
|
3
3
|
*/
|
|
4
4
|
import type { CacheBackend, CacheEntry } from './types.js';
|
|
5
|
+
export interface InMemoryCacheOptions {
|
|
6
|
+
/** Max entries before LRU eviction (default: 1000). */
|
|
7
|
+
maxEntries?: number;
|
|
8
|
+
}
|
|
5
9
|
/**
|
|
6
|
-
*
|
|
10
|
+
* In-memory cache with TTL, bounded size, and stale-if-error support.
|
|
11
|
+
*
|
|
12
|
+
* Uses Map insertion order for LRU eviction: oldest entries are evicted
|
|
13
|
+
* first when maxEntries is exceeded. On get(), entries are re-inserted
|
|
14
|
+
* to refresh their position (most-recently-used).
|
|
7
15
|
*/
|
|
8
16
|
export declare class InMemoryCache implements CacheBackend {
|
|
9
17
|
private readonly cache;
|
|
18
|
+
private readonly maxEntries;
|
|
19
|
+
constructor(options?: InMemoryCacheOptions);
|
|
10
20
|
get(key: string): Promise<CacheEntry | null>;
|
|
21
|
+
/**
|
|
22
|
+
* Get entry even if expired (for stale-if-error fallback).
|
|
23
|
+
* Returns null only if key was never cached.
|
|
24
|
+
*/
|
|
25
|
+
getStale(key: string): Promise<CacheEntry | null>;
|
|
11
26
|
set(key: string, value: CacheEntry): Promise<void>;
|
|
12
27
|
delete(key: string): Promise<void>;
|
|
13
28
|
/**
|
|
@@ -18,6 +33,10 @@ export declare class InMemoryCache implements CacheBackend {
|
|
|
18
33
|
* Get current cache size.
|
|
19
34
|
*/
|
|
20
35
|
get size(): number;
|
|
36
|
+
/**
|
|
37
|
+
* Evict oldest entries (by Map insertion order) when over capacity.
|
|
38
|
+
*/
|
|
39
|
+
private evictIfNeeded;
|
|
21
40
|
}
|
|
22
41
|
/**
|
|
23
42
|
* Build cache key for a specific key ID.
|
package/dist/cache.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAI3D,MAAM,WAAW,oBAAoB;IACnC,uDAAuD;IACvD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;GAMG;AACH,qBAAa,aAAc,YAAW,YAAY;IAChD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiC;IACvD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;gBAExB,OAAO,CAAC,EAAE,oBAAoB;IAIpC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAoBlD;;;OAGG;IACG,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAIjD,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IASlD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIxC;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;OAEG;IACH,OAAO,CAAC,aAAa;CAUtB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAEvE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAWlF"}
|
package/dist/cache.js
CHANGED
|
@@ -1,26 +1,49 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* In-memory cache implementation.
|
|
3
3
|
*/
|
|
4
|
+
const DEFAULT_MAX_ENTRIES = 1000;
|
|
4
5
|
/**
|
|
5
|
-
*
|
|
6
|
+
* In-memory cache with TTL, bounded size, and stale-if-error support.
|
|
7
|
+
*
|
|
8
|
+
* Uses Map insertion order for LRU eviction: oldest entries are evicted
|
|
9
|
+
* first when maxEntries is exceeded. On get(), entries are re-inserted
|
|
10
|
+
* to refresh their position (most-recently-used).
|
|
6
11
|
*/
|
|
7
12
|
export class InMemoryCache {
|
|
8
13
|
cache = new Map();
|
|
14
|
+
maxEntries;
|
|
15
|
+
constructor(options) {
|
|
16
|
+
this.maxEntries = options?.maxEntries ?? DEFAULT_MAX_ENTRIES;
|
|
17
|
+
}
|
|
9
18
|
async get(key) {
|
|
10
19
|
const entry = this.cache.get(key);
|
|
11
20
|
if (!entry) {
|
|
12
21
|
return null;
|
|
13
22
|
}
|
|
14
|
-
// Check expiration
|
|
23
|
+
// Check expiration -- return null but KEEP entry for stale fallback
|
|
15
24
|
const now = Math.floor(Date.now() / 1000);
|
|
16
25
|
if (now >= entry.expiresAt) {
|
|
17
|
-
this.cache.delete(key);
|
|
18
26
|
return null;
|
|
19
27
|
}
|
|
28
|
+
// Refresh position in Map for LRU ordering (move to end)
|
|
29
|
+
this.cache.delete(key);
|
|
30
|
+
this.cache.set(key, entry);
|
|
20
31
|
return entry;
|
|
21
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* Get entry even if expired (for stale-if-error fallback).
|
|
35
|
+
* Returns null only if key was never cached.
|
|
36
|
+
*/
|
|
37
|
+
async getStale(key) {
|
|
38
|
+
return this.cache.get(key) ?? null;
|
|
39
|
+
}
|
|
22
40
|
async set(key, value) {
|
|
41
|
+
// If key already exists, delete first to refresh insertion order
|
|
42
|
+
if (this.cache.has(key)) {
|
|
43
|
+
this.cache.delete(key);
|
|
44
|
+
}
|
|
23
45
|
this.cache.set(key, value);
|
|
46
|
+
this.evictIfNeeded();
|
|
24
47
|
}
|
|
25
48
|
async delete(key) {
|
|
26
49
|
this.cache.delete(key);
|
|
@@ -37,6 +60,20 @@ export class InMemoryCache {
|
|
|
37
60
|
get size() {
|
|
38
61
|
return this.cache.size;
|
|
39
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* Evict oldest entries (by Map insertion order) when over capacity.
|
|
65
|
+
*/
|
|
66
|
+
evictIfNeeded() {
|
|
67
|
+
while (this.cache.size > this.maxEntries) {
|
|
68
|
+
const oldestKey = this.cache.keys().next().value;
|
|
69
|
+
if (oldestKey !== undefined) {
|
|
70
|
+
this.cache.delete(oldestKey);
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
40
77
|
}
|
|
41
78
|
/**
|
|
42
79
|
* Build cache key for a specific key ID.
|
package/dist/cache.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Edge-safe JWKS fetch and cache with SSRF protection.
|
|
5
5
|
*/
|
|
6
6
|
export type { JWK, JWKS, CacheBackend, CacheEntry, ResolverOptions, ResolvedKey, JwksKeyResolver, } from './types.js';
|
|
7
|
+
export type { InMemoryCacheOptions } from './cache.js';
|
|
7
8
|
export { InMemoryCache, buildCacheKey, buildJwksCacheKey, parseCacheControlMaxAge, } from './cache.js';
|
|
8
9
|
export { validateUrl, isMetadataIp } from './security.js';
|
|
9
10
|
export { createResolver, resolveKey, importJwkAsEd25519, createJwkVerifier } from './resolver.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,YAAY,EACV,GAAG,EACH,IAAI,EACJ,YAAY,EACZ,UAAU,EACV,eAAe,EACf,WAAW,EACX,eAAe,GAChB,MAAM,YAAY,CAAC;AAGpB,OAAO,EACL,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,uBAAuB,GACxB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAG1D,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAGlG,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACrE,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,YAAY,EACV,GAAG,EACH,IAAI,EACJ,YAAY,EACZ,UAAU,EACV,eAAe,EACf,WAAW,EACX,eAAe,GAChB,MAAM,YAAY,CAAC;AAGpB,YAAY,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,EACL,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,uBAAuB,GACxB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAG1D,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAGlG,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACrE,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAeH,OAAO,EACL,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,uBAAuB,GACxB,MAAM,YAAY,CAAC;AAEpB,WAAW;AACX,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE1D,WAAW;AACX,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAElG,SAAS;AACT,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/resolver.d.ts
CHANGED
|
@@ -4,7 +4,10 @@
|
|
|
4
4
|
import type { SignatureVerifier } from '@peac/http-signatures';
|
|
5
5
|
import type { JWK, ResolverOptions, ResolvedKey, JwksKeyResolver } from './types.js';
|
|
6
6
|
/**
|
|
7
|
-
* Create a JWKS key resolver.
|
|
7
|
+
* Create a JWKS key resolver with singleflight dedup.
|
|
8
|
+
*
|
|
9
|
+
* Concurrent calls for the same issuer+keyid coalesce into a single
|
|
10
|
+
* network request, preventing thundering herd on cache miss.
|
|
8
11
|
*
|
|
9
12
|
* @param options - Resolver options
|
|
10
13
|
* @returns Key resolver function
|
|
@@ -18,7 +21,7 @@ export declare function createResolver(options?: ResolverOptions): JwksKeyResolv
|
|
|
18
21
|
* 2. /keys?keyID=<kid>
|
|
19
22
|
* 3. /.well-known/jwks.json (fallback)
|
|
20
23
|
*/
|
|
21
|
-
export declare function resolveKey(issuer: string, keyid: string, options: Required<Pick<ResolverOptions, 'cache' | 'defaultTtlSeconds' | 'maxTtlSeconds' | 'minTtlSeconds' | 'timeoutMs' | 'maxResponseBytes' | 'maxKeys' | 'allowLocalhost'>> & Pick<ResolverOptions, 'isAllowedHost'>): Promise<ResolvedKey | null>;
|
|
24
|
+
export declare function resolveKey(issuer: string, keyid: string, options: Required<Pick<ResolverOptions, 'cache' | 'defaultTtlSeconds' | 'maxTtlSeconds' | 'minTtlSeconds' | 'timeoutMs' | 'maxResponseBytes' | 'maxKeys' | 'allowLocalhost' | 'allowStale' | 'maxStaleAgeSeconds'>> & Pick<ResolverOptions, 'isAllowedHost'>): Promise<ResolvedKey | null>;
|
|
22
25
|
/**
|
|
23
26
|
* Import a JWK as Ed25519 public key.
|
|
24
27
|
*
|
package/dist/resolver.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../src/resolver.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,KAAK,EACV,GAAG,EAGH,eAAe,EACf,WAAW,EACX,eAAe,EAChB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../src/resolver.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,KAAK,EACV,GAAG,EAGH,eAAe,EACf,WAAW,EACX,eAAe,EAChB,MAAM,YAAY,CAAC;AAapB;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,OAAO,GAAE,eAAoB,GAAG,eAAe,CAmD7E;AAED;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,QAAQ,CACf,IAAI,CACF,eAAe,EACb,OAAO,GACP,mBAAmB,GACnB,eAAe,GACf,eAAe,GACf,WAAW,GACX,kBAAkB,GAClB,SAAS,GACT,gBAAgB,GAChB,YAAY,GACZ,oBAAoB,CACvB,CACF,GACC,IAAI,CAAC,eAAe,EAAE,eAAe,CAAC,GACvC,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CA+J7B;AAkHD;;;;;GAKG;AACH,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,CAYnE;AAED;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAa5E"}
|
package/dist/resolver.js
CHANGED
|
@@ -10,17 +10,29 @@ const MIN_TTL_SECONDS = 60;
|
|
|
10
10
|
const DEFAULT_TIMEOUT_MS = 5000;
|
|
11
11
|
const DEFAULT_MAX_RESPONSE_BYTES = 1024 * 1024; // 1MB
|
|
12
12
|
const DEFAULT_MAX_KEYS = 100;
|
|
13
|
+
const DEFAULT_MAX_STALE_AGE_SECONDS = 172800; // 48 hours
|
|
13
14
|
/**
|
|
14
|
-
* Create a JWKS key resolver.
|
|
15
|
+
* Create a JWKS key resolver with singleflight dedup.
|
|
16
|
+
*
|
|
17
|
+
* Concurrent calls for the same issuer+keyid coalesce into a single
|
|
18
|
+
* network request, preventing thundering herd on cache miss.
|
|
15
19
|
*
|
|
16
20
|
* @param options - Resolver options
|
|
17
21
|
* @returns Key resolver function
|
|
18
22
|
*/
|
|
19
23
|
export function createResolver(options = {}) {
|
|
20
24
|
const cache = options.cache ?? new InMemoryCache();
|
|
21
|
-
const { defaultTtlSeconds = DEFAULT_TTL_SECONDS, maxTtlSeconds = MAX_TTL_SECONDS, minTtlSeconds = MIN_TTL_SECONDS, timeoutMs = DEFAULT_TIMEOUT_MS, maxResponseBytes = DEFAULT_MAX_RESPONSE_BYTES, maxKeys = DEFAULT_MAX_KEYS, isAllowedHost, allowLocalhost = false, } = options;
|
|
25
|
+
const { defaultTtlSeconds = DEFAULT_TTL_SECONDS, maxTtlSeconds = MAX_TTL_SECONDS, minTtlSeconds = MIN_TTL_SECONDS, timeoutMs = DEFAULT_TIMEOUT_MS, maxResponseBytes = DEFAULT_MAX_RESPONSE_BYTES, maxKeys = DEFAULT_MAX_KEYS, isAllowedHost, allowLocalhost = false, allowStale = false, maxStaleAgeSeconds = DEFAULT_MAX_STALE_AGE_SECONDS, } = options;
|
|
26
|
+
// Singleflight: dedup concurrent resolves for the same issuer+keyid
|
|
27
|
+
const inflight = new Map();
|
|
22
28
|
return async (issuer, keyid) => {
|
|
23
|
-
const
|
|
29
|
+
const flightKey = `${issuer}:${keyid}`;
|
|
30
|
+
const existing = inflight.get(flightKey);
|
|
31
|
+
if (existing) {
|
|
32
|
+
const resolvedKey = await existing;
|
|
33
|
+
return resolvedKey ? createJwkVerifier(resolvedKey.jwk) : null;
|
|
34
|
+
}
|
|
35
|
+
const promise = resolveKey(issuer, keyid, {
|
|
24
36
|
cache,
|
|
25
37
|
defaultTtlSeconds,
|
|
26
38
|
maxTtlSeconds,
|
|
@@ -30,7 +42,13 @@ export function createResolver(options = {}) {
|
|
|
30
42
|
maxKeys,
|
|
31
43
|
isAllowedHost,
|
|
32
44
|
allowLocalhost,
|
|
45
|
+
allowStale,
|
|
46
|
+
maxStaleAgeSeconds,
|
|
47
|
+
}).finally(() => {
|
|
48
|
+
inflight.delete(flightKey);
|
|
33
49
|
});
|
|
50
|
+
inflight.set(flightKey, promise);
|
|
51
|
+
const resolvedKey = await promise;
|
|
34
52
|
if (!resolvedKey) {
|
|
35
53
|
return null;
|
|
36
54
|
}
|
|
@@ -46,7 +64,7 @@ export function createResolver(options = {}) {
|
|
|
46
64
|
* 3. /.well-known/jwks.json (fallback)
|
|
47
65
|
*/
|
|
48
66
|
export async function resolveKey(issuer, keyid, options) {
|
|
49
|
-
const { cache, isAllowedHost, allowLocalhost } = options;
|
|
67
|
+
const { cache, isAllowedHost, allowLocalhost, allowStale, maxStaleAgeSeconds } = options;
|
|
50
68
|
// Normalize issuer to origin
|
|
51
69
|
const issuerOrigin = new URL(issuer).origin;
|
|
52
70
|
const cacheKey = buildCacheKey(issuerOrigin, keyid);
|
|
@@ -135,8 +153,33 @@ export async function resolveKey(issuer, keyid, options) {
|
|
|
135
153
|
// Continue to next path
|
|
136
154
|
}
|
|
137
155
|
}
|
|
138
|
-
// All paths failed
|
|
156
|
+
// All paths failed -- try stale fallback if allowed.
|
|
157
|
+
// Only fall back on transient network errors. Fail closed on security policy
|
|
158
|
+
// violations (SSRF), semantic errors (invalid JWKS, too many keys, too large),
|
|
159
|
+
// and parse failures -- these indicate the server is misconfigured or
|
|
160
|
+
// compromised, not that the network is temporarily unreachable.
|
|
139
161
|
if (errors.length > 0) {
|
|
162
|
+
// Fail closed: stale only if every error is a known-transient JwksError.
|
|
163
|
+
// Non-JwksError (bugs, unexpected throws) must NOT widen stale eligibility.
|
|
164
|
+
const allTransient = errors.every((e) => e instanceof JwksError &&
|
|
165
|
+
(e.code === ErrorCodes.JWKS_FETCH_FAILED || e.code === ErrorCodes.JWKS_TIMEOUT));
|
|
166
|
+
if (allowStale && allTransient && 'getStale' in cache && typeof cache.getStale === 'function') {
|
|
167
|
+
const staleEntry = await cache.getStale(cacheKey);
|
|
168
|
+
if (staleEntry) {
|
|
169
|
+
const now = Math.floor(Date.now() / 1000);
|
|
170
|
+
const staleAge = now - staleEntry.expiresAt;
|
|
171
|
+
if (staleAge >= 0 && staleAge <= maxStaleAgeSeconds) {
|
|
172
|
+
return {
|
|
173
|
+
jwk: staleEntry.jwk,
|
|
174
|
+
source: '/.well-known/jwks',
|
|
175
|
+
cached: true,
|
|
176
|
+
stale: true,
|
|
177
|
+
staleAgeSeconds: staleAge,
|
|
178
|
+
keyExpiredAt: staleEntry.expiresAt,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
140
183
|
const lastError = errors[errors.length - 1];
|
|
141
184
|
if (lastError instanceof JwksError) {
|
|
142
185
|
throw lastError;
|
package/dist/resolver.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolver.js","sourceRoot":"","sources":["../src/resolver.ts"],"names":[],"mappings":"AAAA;;GAEG;AAWH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAEnF,MAAM,mBAAmB,GAAG,IAAI,CAAC,CAAC,SAAS;AAC3C,MAAM,eAAe,GAAG,KAAK,CAAC,CAAC,WAAW;AAC1C,MAAM,eAAe,GAAG,EAAE,CAAC;AAC3B,MAAM,kBAAkB,GAAG,IAAI,CAAC;AAChC,MAAM,0BAA0B,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,MAAM;AACtD,MAAM,gBAAgB,GAAG,GAAG,CAAC;
|
|
1
|
+
{"version":3,"file":"resolver.js","sourceRoot":"","sources":["../src/resolver.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -80,6 +80,18 @@ export interface ResolverOptions {
|
|
|
80
80
|
isAllowedHost?: (host: string) => boolean;
|
|
81
81
|
/** Allow localhost in dev mode (defaults to false) */
|
|
82
82
|
allowLocalhost?: boolean;
|
|
83
|
+
/**
|
|
84
|
+
* Allow serving stale cached keys when fetch fails (default: false).
|
|
85
|
+
* When true, expired cache entries are served as a fallback if all
|
|
86
|
+
* discovery paths fail, up to maxStaleAgeSeconds past expiry.
|
|
87
|
+
*/
|
|
88
|
+
allowStale?: boolean;
|
|
89
|
+
/**
|
|
90
|
+
* Hard cap for stale age in seconds (default: 172800 / 48h).
|
|
91
|
+
* Entries older than this past their original expiry are never served,
|
|
92
|
+
* even with allowStale: true. Prevents silently accepting ancient keys.
|
|
93
|
+
*/
|
|
94
|
+
maxStaleAgeSeconds?: number;
|
|
83
95
|
}
|
|
84
96
|
/**
|
|
85
97
|
* Resolved key result.
|
|
@@ -91,6 +103,12 @@ export interface ResolvedKey {
|
|
|
91
103
|
source: '/.well-known/jwks' | '/.well-known/jwks.json' | '/keys';
|
|
92
104
|
/** Whether result was from cache */
|
|
93
105
|
cached: boolean;
|
|
106
|
+
/** True when serving a past-expiry cached entry (stale-if-error) */
|
|
107
|
+
stale?: boolean;
|
|
108
|
+
/** How many seconds past the original TTL expiry */
|
|
109
|
+
staleAgeSeconds?: number;
|
|
110
|
+
/** Unix timestamp (seconds) when the cache entry expired */
|
|
111
|
+
keyExpiredAt?: number;
|
|
94
112
|
}
|
|
95
113
|
/**
|
|
96
114
|
* Key resolver function type for TAP integration.
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE/D;;GAEG;AACH,MAAM,WAAW,GAAG;IAClB,2CAA2C;IAC3C,GAAG,EAAE,MAAM,CAAC;IACZ,gCAAgC;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,6BAA6B;IAC7B,CAAC,EAAE,MAAM,CAAC;IACV,wBAAwB;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,sCAAsC;IACtC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,0CAA0C;IAC1C,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,MAAM,WAAW,IAAI;IACnB,IAAI,EAAE,GAAG,EAAE,CAAC;CACb;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;OAIG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IAE7C;;;;OAIG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEnD;;;OAGG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,iBAAiB;IACjB,GAAG,EAAE,GAAG,CAAC;IACT,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,4CAA4C;IAC5C,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,gDAAgD;IAChD,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,6CAA6C;IAC7C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,0CAA0C;IAC1C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,6CAA6C;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mDAAmD;IACnD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,yCAAyC;IACzC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6DAA6D;IAC7D,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IAC1C,sDAAsD;IACtD,cAAc,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE/D;;GAEG;AACH,MAAM,WAAW,GAAG;IAClB,2CAA2C;IAC3C,GAAG,EAAE,MAAM,CAAC;IACZ,gCAAgC;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,6BAA6B;IAC7B,CAAC,EAAE,MAAM,CAAC;IACV,wBAAwB;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,sCAAsC;IACtC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,0CAA0C;IAC1C,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,MAAM,WAAW,IAAI;IACnB,IAAI,EAAE,GAAG,EAAE,CAAC;CACb;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;OAIG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IAE7C;;;;OAIG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEnD;;;OAGG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,iBAAiB;IACjB,GAAG,EAAE,GAAG,CAAC;IACT,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,4CAA4C;IAC5C,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,gDAAgD;IAChD,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,6CAA6C;IAC7C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,0CAA0C;IAC1C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,6CAA6C;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mDAAmD;IACnD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,yCAAyC;IACzC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6DAA6D;IAC7D,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IAC1C,sDAAsD;IACtD,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,cAAc;IACd,GAAG,EAAE,GAAG,CAAC;IACT,kCAAkC;IAClC,MAAM,EAAE,mBAAmB,GAAG,wBAAwB,GAAG,OAAO,CAAC;IACjE,oCAAoC;IACpC,MAAM,EAAE,OAAO,CAAC;IAChB,oEAAoE;IACpE,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,oDAAoD;IACpD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,4DAA4D;IAC5D,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@peac/jwks-cache",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.9",
|
|
4
4
|
"description": "Edge-safe JWKS fetch and cache with SSRF protection",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"access": "public"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@peac/http-signatures": "0.10.
|
|
40
|
+
"@peac/http-signatures": "0.10.9"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"typescript": "^5.3.0",
|