gateway: JWT SecurityPolicy blocks CORS preflight requests, breaking OIDC + JWT flow
Description:
the JWT configuration in the Security filter does not include the bypass_cors_preflight
configuration option. Without this setting, OPTIONS requests are blocked unless the JWT is provided.
If the JWT is being passed through cookies with a standard OIDC frontend / JWT backend setup then the credentials won’t be included since the preflight request needs to include the Access-Control-Allow-Credentials: true
response header` before credentials will be sent.
I think bypass_cors_preflight should be set to true by default. I can’t think of a good reason why someone would want to require a JWT for OPTIONS requests since Envoy doesn’t even send OPTIONS requests down to the backend service. As a result the backend application can’t customize the response. So blocking by default will just confuse people while providing no real benefit.
About this issue
- Original URL
- State: open
- Created 6 months ago
- Comments: 16 (11 by maintainers)
@apjoseph @arkodg
I tested the below SecurityPolicy with cors and jwt, and it worked.
Use
curl
to send a CORS preflight request with the originhttp://www.foo.com
, and it succeeded.Tried to use another origin
http://www.bar.com
, and it failed with401 Unauthorized
, which is expected because this origin doesn’t match the CORS setting in the SecuritPolicy, and it’s passed down to the JWT filter.In this comment, I followed the user doc to test, but the demo SecurityPolicy in the user doc is wrong, the cors setting in the user doc is
but the test command is
Since the
http://www.foo.com
origin in the test command doesn’t match thewww.foo.com
in the SecurityPolicy, the CORS filter ignores this OPTION request and passes it down to the JWT filter. That’s why it gets a401 Unauthorized
response.My bad on the confusing doc 😃. I’m the one who wrote it. I’ll go ahead to raise a PR to clean things up.
@apjoseph I suspect your preflight request failed for a similar reason. Could you please try to verify it with
curl
and share the SecurityPolicy and the curl command and result?@zhaohuabing I think its worth further debugging https://github.com/envoyproxy/gateway/issues/2312#issuecomment-1866051928 to understand why the
OPTIONS
request is getting a401
in your test above instead of returning after hitting the cors filter because it doesnt match with https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/cors_filter#cors@zhaohuabing Another potential solution is to allow different security policies to be applied when a different method is specified with the same path. This was actually my attempted workaround when I first encountered the issue. I created two http routes:
api-route
api-route-cors
and then created corresponding SecurityPolicies for both HttpRoutes. I only included the JWT section in the SecurityPolicy for
api-route
. I assumed this would prevent OPTIONS requests from being blocked; however when looking at the response from egctl I found that it was being applied to both HttpRoutes BUT only in some instances. Other times it would remove JWT auth from BOTH HttpRoutes -depending on which security policy was applied last.I am not sure whether this is intended behavior or not, but it was counter intuitive to me as I would have expected all attributes of a match to be taken into account when applying a security policy if they are in separate routes -especially since the security policy is explicitly bound to an HTTPRoute
I like your approach of just turning the
bypass_cors_preflight
on by default though. It would be highly annoying to need to configure separate HttpRoute objects just for CORS.