Description
Implement the spiffe_jwt client-authentication method: a workload presents a
JWT-SVID as an OAuth client assertion, and the authorization server
authenticates the client from the validated assertion.
This must work independently of the TLS peer-certificate path. Deployments
that terminate TLS at an ingress cannot present a client certificate to the
authorization server at all, so JWT-SVID is not a convenience alternative to
spiffe_x509 — it is the only SPIFFE option in a large class of real
deployments.
The dominant risk here is type confusion. A JWT-SVID, an OIDC ID token and an
ordinary access token are all signed JWTs, and the same IdP may sign several of
them. Accepting the wrong one as a client assertion would let any bearer of a
routine token authenticate as the workload.
Scope
- Accept exactly one
client_assertion with
client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-spiffe.
- Validate JWT-SVID signatures using only the
jwt-svid keys of the configured
trust-domain bundle from sub-issue 2.
- Extract the SPIFFE ID from
sub and resolve it through the shared
client-association policy from sub-issue 1.
- Enforce assertion size, cardinality, algorithm, expiry and clock-skew limits.
- Advertise
spiffe_jwt only when the method is fully configured and
operational.
Acceptance criteria
Assertion acceptance:
client_assertion_type matches
urn:ietf:params:oauth:client-assertion-type:jwt-spiffe exactly.
- The request contains exactly one JWT-SVID assertion.
sub is a valid SPIFFE ID associated with the requested OAuth client.
exp is present and valid.
aud contains the ToolHive authorization-server issuer as its sole value.
- The signature validates using only permitted
jwt-svid keys from the
associated trust-domain bundle.
Rejection:
- Ordinary OIDC access tokens, ID tokens and generic signed JWTs are rejected.
- Wrong audiences, trust domains, keys, algorithms and client associations are
rejected.
- A malformed or unauthorized assertion cannot fall back to public or
secret-based client authentication.
Hygiene:
- Assertions and their claims are never written to logs.
Reuse
Signature verification and key resolution should come from
pkg/oauthproto/jwks.go via sub-issue 2's bundle registry, restricted to the
bundle's jwt-svid keys. That fetcher already handles caching, refresh on kid
miss, and a stale-on-error path; this issue adds the key-subset restriction and
the SVID-specific claim rules, not a second validation stack.
Dependencies
- Sub-issue 1 (identity, association and configuration model)
- Sub-issue 2 (trust-domain bundle management) — specifically its
jwt-svid
key restriction
pkg/oauthproto/jwks.go (unpushed, xaa-spike-1)
Can proceed in parallel with the X.509-SVID sub-issue once both foundations
exist.
Related
- Part of the SPIFFE client-authentication epic
Description
Implement the
spiffe_jwtclient-authentication method: a workload presents aJWT-SVID as an OAuth client assertion, and the authorization server
authenticates the client from the validated assertion.
This must work independently of the TLS peer-certificate path. Deployments
that terminate TLS at an ingress cannot present a client certificate to the
authorization server at all, so JWT-SVID is not a convenience alternative to
spiffe_x509— it is the only SPIFFE option in a large class of realdeployments.
The dominant risk here is type confusion. A JWT-SVID, an OIDC ID token and an
ordinary access token are all signed JWTs, and the same IdP may sign several of
them. Accepting the wrong one as a client assertion would let any bearer of a
routine token authenticate as the workload.
Scope
client_assertionwithclient_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-spiffe.jwt-svidkeys of the configuredtrust-domain bundle from sub-issue 2.
suband resolve it through the sharedclient-association policy from sub-issue 1.
spiffe_jwtonly when the method is fully configured andoperational.
Acceptance criteria
Assertion acceptance:
client_assertion_typematchesurn:ietf:params:oauth:client-assertion-type:jwt-spiffeexactly.subis a valid SPIFFE ID associated with the requested OAuth client.expis present and valid.audcontains the ToolHive authorization-server issuer as its sole value.jwt-svidkeys from theassociated trust-domain bundle.
Rejection:
rejected.
secret-based client authentication.
Hygiene:
Reuse
Signature verification and key resolution should come from
pkg/oauthproto/jwks.govia sub-issue 2's bundle registry, restricted to thebundle's
jwt-svidkeys. That fetcher already handles caching, refresh onkidmiss, and a stale-on-error path; this issue adds the key-subset restriction and
the SVID-specific claim rules, not a second validation stack.
Dependencies
jwt-svidkey restriction
pkg/oauthproto/jwks.go(unpushed,xaa-spike-1)Can proceed in parallel with the X.509-SVID sub-issue once both foundations
exist.
Related