fix(server): suppress HS256 JWKS entry when SIGNING_KEY is unbound#32
Merged
khaliqgant merged 1 commit intomainfrom Apr 23, 2026
Merged
Conversation
The keys array hardcoded the HS256 entry, so deployments that retired HS256 by removing the SIGNING_KEY binding (per the RS256 migration step 3 runbook) still advertised HS256 in JWKS. Cosmetic — the entry never contained `k`, so no verifier could validate HS256 tokens against it — but it violated the migration exit criteria and confused operators reading the runbook literally. Now: HS256 entry only appears when SIGNING_KEY is actually bound. New regression test covers the post-sunset case (HS256 unbound, RSA present → only the RSA key) and the empty-config case. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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
Same-day follow-up to phase 122 step 3 (cloud#299, merged + deployed today), which removed the
SIGNING_KEYworker binding on the relayauth worker and setRELAYAUTH_VERIFIER_ACCEPT_HS256=falseon sage + specialist-worker.The runbook's exit criterion for step 3 is that JWKS at https://api.relayauth.dev/.well-known/jwks.json publishes RSA only. It still publishes HS256:
Root cause
packages/server/src/routes/jwks.tshardcoded the HS256 entry into thekeysarray, gated only onSIGNING_KEY_ID(still present for legacy kid accounting), not onSIGNING_KEY(which #299 removed). So the worker can't sign or verify HS256 anymore — there is no key material — but JWKS still advertises HS256 as a supported algorithm.Cosmetic, not a security regression
The entry has no
kfield (the actual HMAC secret); the old comment explicitly said "never the symmetric key material." No verifier can validate HS256 tokens against this entry. The migration's security objective (no downstream service will accept HS256) is already met byRELAYAUTH_VERIFIER_ACCEPT_HS256=falseon sage + specialist-worker.That said, the runbook exit criterion reads "no HS256 in JWKS" literally, and operators correctly read the current output as a regression. This PR closes that gap.
Fix
jwks.tsnow gates the HS256 entry onc.env.SIGNING_KEYbeing bound. Comment rewritten to explain why (publishingkwould allow token forgery) and that unbindingSIGNING_KEYis the retirement signal.Downstream work (not in this PR)
For the production JWKS endpoint to actually drop the HS256 entry:
@relayauth/server(user manages the version bump + publish post-merge).@relayauth/serverdep incloudand redeploy the relayauth worker.Test plan
npx tsc --noEmitonpackages/serverpassespackages/server/src/__tests__/jwks-rsa.test.ts):JWKS suppresses the HS256 metadata once SIGNING_KEY is unbound (post-sunset)— SIGNING_KEY unset + RSA public PEM set → keys contains only the RSA JWKJWKS returns an empty key set when neither HS256 nor RS256 material is configured— both unset →keys: []curl https://<stage>/.well-known/jwks.jsonreturns RSA only🤖 Generated with Claude Code