envoyproxy / envoyproxy/gateway

SecurityPolicy JWT claimToHeaders can't address claim names containing dots (e.g. URI-namespaced OIDC claims)

Open
#9,964 1 comment 0 reactions 0 assignees View on GitHub
triage
Dominant language
Go
Stars
3k
Forks
864
Avg merge
2d 2h
Merged PRs (30d)
140

Description

### Description

`SecurityPolicy.spec.jwt.providers[].claimToHeaders[].claim` is passed straight through to Envoy's `jwt_authn` filter as `claim_name`, which Envoy always splits on `.` to address nested claims.

This makes it impossible to extract any claim whose own name contains a dot — most commonly URI-namespaced custom claims emitted by OIDC providers (auth0 etc.), e.g. `https://example.com/claims/tenant_name`.
Envoy misinterprets the dots as a nested-object path, the lookup fails, and the header is silently never set (no error, no log).

Envoy Gateway does no transformation of the claim name — it forwards the string as-is to Envoy. The gap is in the `SecurityPolicy` CRD.

### Confirmed via xDS dump

```json
"claim_to_headers": [
{ "header_name": "Tenant-Name", "claim_name": "https://auth.example.com/claims/tenant_name" }
]
```

### Envoy already solves this but not included on SecurityPolicy CRD

Envoy's `jwt_authn` filter has a second field, [`claim_path`](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/http/jwt_authn/v3/config.proto#extensions-filters-http-jwt-authn-v3-jwtclaimtoheader), which takes an explicit list of path segments and matches each one literally against a JSON key — built for exactly this case:

```yaml
claim_to_headers:
- header_name: x-jwt-claim
claim_path:
- key: "https://example.com/claims/tenant_name"
```

`SecurityPolicy`'s `ClaimToHeader` type has no equivalent field today.
https://gateway.envoyproxy.io/docs/api/extension_types/#claimtoheader

### Proposed fix

Add an optional `claimPath []string` field to `ClaimToHeader`, mutually exclusive with `claim`, mapping 1:1 to Envoy's `claim_path` segments:

```go
type ClaimToHeader struct {
Header string `json:"header"`
Claim string `json:"claim,omitempty"` // existing, dot-split nested claim lookup
ClaimPath []string `json:"claimPath,omitempty"` // new, explicit segments for dotted/URI-namespaced claim names
}
```

Validate that exactly one of `claim`/`claimPath` is set per entry.

Existing configs using `claim` are unaffected.

### Repro

```yaml
claimToHeaders:
- claim: "https://example.com/claims/tenant_name"
header: Tenant-Name
```

A verified JWT containing that claim never populates `Tenant-Name`

Contributor guide

No contributing guide indexed for this repository

Research direction

Start at the SecurityPolicy CRD's ClaimToHeader type and trace its mapping to Envoy jwt_authn claim_to_headers, using the supplied xDS example as the reference. Check the existing validation and translation tests for this type. Done means claimPath maps to literal Envoy claim_path segments, claim and claimPath are mutually exclusive, and existing claim behavior remains unchanged.

Written by the indexing model from the issue text.

Assessment

Tech stack
go, kubernetes
Domain
api, backend
Issue type
Feature
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
75/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.