feat(auth): bind a JWKS key to the tenants it may sign for - #18
Merged
Merged
Conversation
A JWKS entry may carry a tenants list; tokens signed by that key are accepted only for those tenant_id values (reason tenant_not_allowed, 401). A bound key never falls back to the single-tenant namespace. A malformed list is a configuration error at startup, never an unbound key. Keys without the member behave as before.
Review repairs for the tenant binding: a bound key is checked against the signed tenant_id, so a token without one is refused even when the default namespace is listed; a bound kid configured again in any key source fails startup instead of being silently replaced by an unbound copy; a tenants list on an entry without a kid fails startup. Drops two prose pins (synthetic weak-token message, rate-limit message).
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.
What
A JWKS entry in
CODEAPI_JWT_JWKS_JSONmay carry"tenants": ["<tenant_id>", ...]. A token signed by that key is accepted only when itstenant_idis in the list; otherwise 401 with reasontenant_not_allowed.Why
Today any trusted key can mint code runs for any tenant: the engine takes the tenant from the token. AX41 trusts the staging key, so a holder of the staging private key can run code as any production tenant. Thor chose option A (bind keys to tenants in the engine). Finding: "Production code engine trusts lab and staging signing keys".
Behaviour
tenantsbehave exactly as before.tenant_idonly: a token without one is refused even if the default namespace (CODEAPI_JWT_SINGLE_TENANT_IDorlegacy) is listed.CODEAPI_JWT_PUBLIC_KEY, the HS256 secret) fails startup instead of being replaced by an unbound copy; atenantslist on an entry without akidfails startup.configerror, sostartup.tsfails at boot instead of trusting the key for every tenant.CODEAPI_JWT_PUBLIC_KEY,CODEAPI_JWT_PUBLIC_KEYS_DIRand HS256 keys are unchanged.Proof
bun test src/auth src/middleware: 54/54. The review-repair tests (signed tenant_id with a listed default, kidless binding, second key source) fail on cb089f3 (3 fail, 20 pass) and pass here.Deploy
api only (the only verifier). Config change on AX41: add
tenantsto thecodeapi-staging-20260916entry. The plan is in the Security PRIMARY artifactAX41-KEY-TENANT-BINDING-DEPLOY.md. Ships with the fixed #16 redeploy.