@@ -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+
1321export 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