Skip to content

Commit e1dce49

Browse files
committed
chore: JWKs caching
1 parent a4be956 commit e1dce49

1 file changed

Lines changed: 36 additions & 10 deletions

File tree

infrastructure/evault-core/src/core/protocol/vault-access-guard.ts

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@ export type VaultContext = YogaInitialContext & {
1010
eName: string | null;
1111
};
1212

13+
type CachedJWKS = {
14+
jwks: ReturnType<typeof jose.createLocalJWKSet>;
15+
expiresAt: number;
16+
};
17+
const jwksCache = new Map<string, CachedJWKS>();
18+
const JWKS_TTL_MS = 24 * 60 * 60 * 1000;
19+
const JWKS_FETCH_TIMEOUT_MS = 5000;
20+
1321
export class VaultAccessGuard {
1422
constructor(private db: DbService) {}
1523

@@ -35,12 +43,25 @@ export class VaultAccessGuard {
3543
return null;
3644
}
3745

38-
const jwksResponse = await axios.get(
39-
new URL(`/.well-known/jwks.json`, registryUrl).toString(),
40-
);
46+
const jwksUrl = new URL(
47+
`/.well-known/jwks.json`,
48+
registryUrl,
49+
).toString();
50+
51+
const now = Date.now();
52+
let cached = jwksCache.get(jwksUrl);
53+
if (!cached || cached.expiresAt <= now) {
54+
const jwksResponse = await axios.get(jwksUrl, {
55+
timeout: JWKS_FETCH_TIMEOUT_MS,
56+
});
57+
cached = {
58+
jwks: jose.createLocalJWKSet(jwksResponse.data),
59+
expiresAt: now + JWKS_TTL_MS,
60+
};
61+
jwksCache.set(jwksUrl, cached);
62+
}
4163

42-
const JWKS = jose.createLocalJWKSet(jwksResponse.data);
43-
const { payload } = await jose.jwtVerify(token, JWKS);
64+
const { payload } = await jose.jwtVerify(token, cached.jwks);
4465

4566
return payload;
4667
} catch (error) {
@@ -115,11 +136,16 @@ export class VaultAccessGuard {
115136
metaEnvelopeId: string,
116137
context: VaultContext,
117138
): Promise<{ hasAccess: boolean; exists: boolean }> {
118-
// Validate token if present
119-
const authHeader =
120-
context.request?.headers?.get("authorization") ??
121-
context.request?.headers?.get("Authorization");
122-
const tokenPayload = await this.validateToken(authHeader);
139+
// Reuse token payload already validated by validateAuthentication() earlier
140+
// in the middleware; only re-validate as a fallback (e.g. store operations
141+
// where an upstream pass may not have populated it).
142+
let tokenPayload = context.tokenPayload ?? null;
143+
if (!tokenPayload) {
144+
const authHeader =
145+
context.request?.headers?.get("authorization") ??
146+
context.request?.headers?.get("Authorization");
147+
tokenPayload = await this.validateToken(authHeader);
148+
}
123149

124150
if (tokenPayload) {
125151
// Token is valid, set platform context and allow access

0 commit comments

Comments
 (0)