Skip to content

Implement JWT-SVID OAuth client authentication (spiffe_jwt) #6203

Description

@jhrozek

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions