@@ -149,6 +149,30 @@ syntax = "proto3";
149149// paths: ["/healthz"]
150150// ```
151151//
152+ // Alternatively, you can use `requireJwt: true` to enforce JWT requirement directly in the RequestAuthentication
153+ // policy without needing a separate AuthorizationPolicy. This approach returns 401 Unauthorized with a
154+ // `WWW-Authenticate: Bearer` header for missing JWTs instead of 403 Forbidden:
155+ //
156+ // ```yaml
157+ // apiVersion: security.istio.io/v1
158+ // kind: RequestAuthentication
159+ // metadata:
160+ // name: httpbin
161+ // namespace: foo
162+ // spec:
163+ // selector:
164+ // matchLabels:
165+ // app: httpbin
166+ // jwtRules:
167+ // - issuer: "issuer-foo"
168+ // jwksUri: https://example.com/.well-known/jwks.json
169+ // requireJwt: true
170+ // ```
171+ //
172+ // With `requireJwt: true`, requests without a JWT will be rejected with 401 Unauthorized and a
173+ // `WWW-Authenticate: Bearer` header, making it clearer that authentication is required. This is semantically
174+ // more accurate than the 403 Forbidden returned by AuthorizationPolicy and complies with RFC 7235.
175+ //
152176// [Experimental] Routing based on derived [metadata](https://istio.io/latest/docs/reference/config/security/conditions/)
153177// is now supported. A prefix '@' is used to denote a match against internal metadata instead of the headers in the request.
154178// Currently this feature is only supported for the following metadata:
@@ -333,6 +357,18 @@ message RequestAuthentication {
333357//
334358// With this configuration, a JWT containing `"custom_scope": "read write admin"` will allow
335359// authorization policies to match against individual values like "read", "write", or "admin".
360+ //
361+ // This example shows how to require JWT tokens and return 401 for missing tokens:
362+ //
363+ // ```yaml
364+ // issuer: https://example.com
365+ // jwksUri: https://example.com/.well-known/jwks.json
366+ // requireJwt: true
367+ // ```
368+ //
369+ // With `requireJwt: true`, requests without a JWT will receive a 401 Unauthorized response with a
370+ // `WWW-Authenticate: Bearer` header directly from the authentication filter, eliminating the need
371+ // for a separate AuthorizationPolicy when you simply want to require authentication.
336372// +kubebuilder:validation:XValidation:message="only one of jwks or jwksUri can be set",rule="oneof(self.jwksUri, self.jwks_uri, self.jwks)"
337373message JWTRule {
338374 // Identifies the issuer that issued the JWT. See
@@ -487,8 +523,37 @@ message JWTRule {
487523 // +kubebuilder:validation:MaxItems=64
488524 repeated string space_delimited_claims = 14 ;
489525
526+ // If set to true, requests without a valid JWT token will be rejected with a 401 Unauthorized status code
527+ // along with a `WWW-Authenticate` header indicating the Bearer authentication scheme is required.
528+ // If set to false or unset (default), requests without a JWT token are allowed to pass through but will not have
529+ // an authenticated identity. In the default case, to enforce that requests must have authentication,
530+ // you should use an AuthorizationPolicy with requestPrincipals.
531+ //
532+ // Note: Setting this to true changes the HTTP status code for missing JWT from 403 (via AuthorizationPolicy)
533+ // to 401 (via RequestAuthentication), which is semantically more accurate for authentication failures and
534+ // includes the proper `WWW-Authenticate` header as required by RFC 7235.
535+ //
536+ // Example usage:
537+ // ```yaml
538+ // jwtRules:
539+ // - issuer: "https://example.com"
540+ // jwksUri: https://example.com/.well-known/jwks.json
541+ // requireJwt: true
542+ // ```
543+ //
544+ // With `requireJwt: true`:
545+ // - Request with missing JWT -> 401 Unauthorized (with WWW-Authenticate: Bearer header)
546+ // - Request with invalid/expired JWT -> 401 Unauthorized (with WWW-Authenticate: Bearer header)
547+ // - Request with valid JWT -> Accepted
548+ //
549+ // With `requireJwt: false` (default):
550+ // - Request with missing JWT -> Accepted (no authenticated identity)
551+ // - Request with invalid/expired JWT -> 401 Unauthorized (with WWW-Authenticate: Bearer header)
552+ // - Request with valid JWT -> Accepted (with authenticated identity)
553+ bool require_jwt = 15 ;
554+
490555 // $hide_from_docs
491- // Next available field number: 15
556+ // Next available field number: 16
492557}
493558
494559// This message specifies a header location to extract JWT token.
0 commit comments