feat: OIDC JWKS staleness alarm and forced refresh endpoint - #809
Open
Hollujay wants to merge 1 commit into
Open
feat: OIDC JWKS staleness alarm and forced refresh endpoint#809Hollujay wants to merge 1 commit into
Hollujay wants to merge 1 commit into
Conversation
|
@Hollujay Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
Hollujay
force-pushed
the
feat/oidc-jwks-staleness-alarm
branch
from
August 3, 2026 04:43
fcf4feb to
967bdff
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements #686 — OIDC JWKS staleness alarm and forced refresh endpoint.
Per-issuer JWKS cache age tracking, a Prometheus staleness gauge, and an admin-only dual-control force-refresh endpoint with rate limiting, audit events, and request coalescing. Replaces the previous single-admin confirmation approach (header + body boolean) merged in #589 with a genuine two-admin approval flow, per the issue requirements.
New endpoint
POST /auth/oidc/jwks/refresh(+ aliasPOST /api/auth/oidc/jwks/refresh):{ issuerUrl?: string }→202+approvalId. Omitted issuer = refresh all tracked issuers.{ approvalId }→200+{ refreshedIssuers, failedIssuers }(502when all fail, partial-failure reporting otherwise).Changes
src/auth/oidc/jwksCache.ts— per-issuerfetchedAt/last-refresh tracking,getCacheAgeSeconds(issuer),getTrackedIssuers(), gauge emission (oidc.jwks.age_secondslabeled by issuer, 60s unref'd ticker), single-flight coalescing per JWKS URI with apendingIssuersregistry so every issuer awaiting a shared fetch is accounted for; in-flight slot released on success and failure.src/auth/oidc/jwksRefreshApprovalGate.ts— new in-memory dual-control gate: proposer ≠ approver, TTL expiry, one-approval-per-proposal, distinct error types.src/auth/oidc/oidcAdapterService.ts—refreshAllJwks()with per-issuerPromise.allSettledpartial-failure results,getTrackedJwksIssuers().src/auth/oidc/oidcRoute.ts— dual-control handler, sharedcreateRateLimitMiddleware(10 req/min per admin,keyPrefix: 'oidc-jwks-refresh'), enriched audit events (actor/proposer/approver/scope/status/reason), non-admins rejected before the gate/limiter.docs/oidc-jwks-staleness-alarm.md— design, threat model, security assumptions, runbook.Security notes
409); proposals expire after 5 minutes. Modeled on the repo's existing dual-control patterns (OFAC review queue, tenant-settings propose/approve, legal-hold).502with per-issuer reasons. Audit events record every outcome.Test results
Full OIDC module (
npx jest --runInBand src/auth/oidc/): 153 passed, 0 failed (7 suites).Module coverage (
--coverageonsrc/auth/oidc/*.ts):npx tsc --noEmit: 0 errors in changed files. Baseline upstream master has 438 pre-existing errors; this branch 430 (the diff fixes 6 of its own plus 2 pre-existing inoidc.test.ts).Pre-existing repo conditions (not introduced here)
48e4dcd0— 215/224 suites fail to even load due to a ts-jestgetCacheKeybug under Node 24 (environment incompatibility), plus pre-existing failures (missingSTELLAR_SERVER_SECRET, DB-backed suites, tests written against older signatures). Full-suite run on this branch: 1957 passed / 284 failed, with zero real failures in OIDC/health suites..github/workflows/ci.ymldoes not execute jest (onlynpm ci, audit, alert-mapping validation).amlAuditRepodeclaration insrc/index.tsand a missingconsumedJtisfield inoidcAdapterService.ts; both are already fixed upstream and confirmed identical after rebase.48e4dcd0) — clean 10-file diff, linear history.Closes #686