Description:
I am using envoy gateway in namespace mode and I have various frontends and backends at different subdomains which the single gateway handles traffic across these subdomains.
I have two security policy - policy a at gateway level and policy b targeting a specific route to a particular backend. Both policies share the same oidc and jwt configurations but policy b has an additional authorisation configuration to perform additional check against jwt claims.
When policy b is present, the frontend is unable to send request to that particular backend with 302 Found (envoy log: oauth missing credentials). When trying to open the backend url on the browser directly, 401 error with oauth flow error message was shown and envoy logs showing CSRF token validation failed. Even after modifying policy b to be exactly the same as policy a, same error exists. After policy b is deleted, the frontend can successfully send request to the protected backend with no issue.
This behaviour appears related to, but not fully explained by, this issue: #7205. The symptoms are similar (unexpected auth redirects and CSRF-related failures), but the setup differs due to the shared OIDC/JWT sessions and the additional authorization check in a route-specific policy.
Repro steps:
policy a:
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: SecurityPolicy
metadata:
name: gateway-security-policy
namespace: {{ .Values.namespace }}
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: internal-gateway
cors:
allowOrigins:
{{- range .Values.instances }}
- "https://{{ .subdomain }}.{{ $.Values.namespace }}.{{ $.Values.domain }}"
{{- end }}
allowMethods:
- GET
- POST
- PUT
- DELETE
- OPTIONS
allowHeaders:
- Accept
- Authorization
- Content-Type
- X-CSRF-Token
exposeHeaders:
- Link
allowCredentials: true
oidc:
provider:
issuer: https://auth.{{ .Values.domain }}
clientIDRef:
name: internal-gateway-secret
namespace: {{ .Values.namespace }}
clientSecret:
name: internal-gateway-secret
namespace: {{ .Values.namespace }}
redirectURL: https://auth.{{ .Values.namespace }}.{{ .Values.domain }}/oauth2/callback
scopes:
- openid
- profile
- offline_access
- urn:zitadel:iam:org:project:{{ .Values.gateway.project_id }}:roles
logoutPath: /logout
cookieDomain: "{{ .Values.namespace }}.{{ .Values.domain }}"
forwardAccessToken: true
jwt:
providers:
- name: zitadel
remoteJWKS:
uri: https://auth.{{ .Values.domain }}/oauth/v2/keys
claimToHeaders:
- claim: sub
header: X-Zitadel-Sub
- claim: urn:zitadel:iam:org:project:{{ .Values.gateway.project_id }}:roles
header: X-Zitadel-Roles
policy b (extra config):
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
name: xxx
authorization:
defaultAction: Deny
rules:
- action: Allow
name: allow-user
principal:
jwt:
claims:
- name: sub
valueType: StringArray
values:
- 'xxx'
provider: zitadel
- action: Allow
name: allow-roles
principal:
jwt:
claims:
- name: urn:zitadel:iam:org:project:xxx:roles
valueType: StringArray
values:
- admin
provider: zitadel
Environment:
gateway-helm 1.7.1
Logs:
302 Found (oauth missing credentials)
[pod/internal-gateway-65b697df8b-r8g2m/envoy] {":authority":","bytes_received":0,"bytes_sent":0,"connection_termination_details":null,"downstream_local_address":"10.244.2.217:10080","downstream_remote_address":"10.226.0.6:20089","duration":0,"method":"GET","protocol":"HTTP/1.1","requested_server_name":null,"response_code":302,"response_code_details":"oauth.missing_credentials","response_flags":"-","route_name":"i","start_time":"2026-04-01T14:37:09.644Z","upstream_cluster":"httproute//rule/0","upstream_host":null,"upstream_local_address":null,"upstream_transport_failure_reason":null,"user-agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36 Edg/146.0.0.0","x-envoy-origin-path":"/","x-envoy-upstream-service-time":null,"x-forwarded-for":"","x-request-id":"f2a86c40-f883-4991-b795-dd9fce2ec3cb"}
401 unauthorised (CSRF token validation failed)
[pod/internal-gateway-65b697df8b-r8g2m/envoy] [2026-04-01 14:38:40.746][14][warning][oauth2] [source/extensions/filters/http/oauth2/filter.cc:1390] [Tags: "ConnectionId":"141","StreamId":"4191718425724896979"] Responding with 401 Unauthorized. Cause: CSRF token validation failed
[pod/internal-gateway-65b697df8b-r8g2m/envoy] {":authority":"","bytes_received":0,"bytes_sent":18,"connection_termination_details":null,"downstream_local_address":"10.244.2.217:10080","downstream_remote_address":"10.226.0.6:44793","duration":0,"method":"GET","protocol":"HTTP/1.1","requested_server_name":null,"response_code":401,"response_code_details":"CSRF_token_validation_failed","response_flags":"-","route_name":"httproute//rule/0/match/0/","start_time":"2026-04-01T14:38:40.746Z","upstream_cluster":null,"upstream_host":null,"upstream_local_address":null,"upstream_transport_failure_reason":null,"user-agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36 Edg/146.0.0.0","x-envoy-origin-path":"/oauth2/callback?code=some-code","x-envoy-upstream-service-time":null,"x-forwarded-for":"","x-request-id":"e9d381a9-52c0-44f6-85a3-c3d54cc034ac"}
Description:
I am using envoy gateway in namespace mode and I have various frontends and backends at different subdomains which the single gateway handles traffic across these subdomains.
I have two security policy -
policy aat gateway level andpolicy btargeting a specific route to a particular backend. Both policies share the sameoidcandjwtconfigurations butpolicy bhas an additionalauthorisationconfiguration to perform additional check against jwt claims.When
policy bis present, the frontend is unable to send request to that particular backend with 302 Found (envoy log: oauth missing credentials). When trying to open the backend url on the browser directly, 401 error withoauth flow errormessage was shown and envoy logs showingCSRF token validation failed. Even after modifyingpolicy bto be exactly the same aspolicy a, same error exists. Afterpolicy bis deleted, the frontend can successfully send request to the protected backend with no issue.This behaviour appears related to, but not fully explained by, this issue: #7205. The symptoms are similar (unexpected auth redirects and CSRF-related failures), but the setup differs due to the shared OIDC/JWT sessions and the additional authorization check in a route-specific policy.
Repro steps:
policy a:
policy b (extra config):
Environment:
Logs:
302 Found (oauth missing credentials)
401 unauthorised (CSRF token validation failed)