ory / kratos

Next-gen identity server replacing your Auth0, Okta, Firebase with hardened security and PassKeys, SMS, OIDC, Social Sign In, MFA, FIDO, TOTP and OTP, WebAuthn, passwordless and much more. Golang, headless, API-first. Available as a worry-free SaaS with the fairest pricing on the market!
https://www.ory.sh/kratos/?utm_source=github&utm_medium=banner&utm_campaign=kratos
Apache License 2.0
11.04k stars 949 forks source link

CORS Headers aren't being added to response #2922

Closed jwmay2012 closed 1 year ago

jwmay2012 commented 1 year ago

Preflight checklist

Describe the bug

CORS related headers are claimed by kratos logs to be added to /self-service/login/browser response, but no such headers are present.

Reproducing the bug

curl -v -H "Origin: https://mydomain.com/" -H "Accept: application/json" http://auth.mydomain.com/self-service/login/browser

...
< HTTP/1.1 200 OK
< Cache-Control: private, no-cache, no-store, must-revalidate
< Content-Type: application/json; charset=utf-8
< Set-Cookie: csrf_token_5c51a995dd623ddb0e303f9eaf4401a59ccc98b62b61aebc2deae2ca0c291484=gFj0H6qF1crfDdy2yedTkVggypxI3Lx9tsFzSqyzprg=; Path=/; Domain=mydomain.com; Max-Age=31536000; HttpOnly; Secure; SameSite=Lax
< Vary: Cookie
< Date: Thu, 01 Dec 2022 22:06:17 GMT
< Content-Length: 1983
...

Notice absence of any CORS headers.

[cors] logs claim proper headers were added. CURL/Browser disagrees.

Relevant log output

time=2022-12-01T22:07:07Z level=info msg=started handling request http_request=map[headers:map[accept:application/json origin:https://mydomain.com/ user-agent:curl/7.86.0] host:kratos-public method:GET path:/self-service/login/browser query:<nil> remote:252.64.130.136:55654 scheme:http]
[cors] 2022/12/01 22:07:07 ServeHTTP: Actual request

[cors] 2022/12/01 22:07:07   Actual response added headers: map[Access-Control-Allow-Credentials:[true] Access-Control-Allow-Origin:[https://mydoamin.com] Access-Control-Expose-Headers:[Content-Type, Set-Cookie] Cache-Control:[private, no-cache, no-store, must-revalidate] Content-Type:[application/json; charset=utf-8] Set-Cookie:[csrf_token_5c51a995dd623ddb0e303f9eaf4401a59ccc98b62b61aebc2deae2ca0c291484=WZg0C6YgiwgCbm/xCYlQzqFN1b9iOdmabk41fSA72Fs=; Path=/; Domain=mydomain.com; Max-Age=31536000; HttpOnly; Secure; SameSite=Lax] Vary:[Cookie Origin]]

time=2022-12-01T22:07:07Z level=info msg=completed handling request http_request=map[headers:map[accept:application/json origin:https://mydomain.com/ user-agent:curl/7.86.0] host:kratos-public method:GET path:/self-service/login/browser query:<nil> remote:252.64.130.136:55654 scheme:http] http_response=map[headers:map[access-control-allow-credentials:true access-control-allow-origin:https://mydoamin.com access-control-expose-headers:Content-Type, Set-Cookie cache-control:private, no-cache, no-store, must-revalidate content-type:application/json; charset=utf-8 set-cookie:[csrf_token_5c51a995dd623ddb0e303f9eaf4401a59ccc98b62b61aebc2deae2ca0c291484=WZg0C6YgiwgCbm/xCYlQzqFN1b9iOdmabk41fSA72Fs=; Path=/; Domain=mydomain.com; Max-Age=31536000; HttpOnly; Secure; SameSite=Lax] vary:Cookie] size:1983 status:200 text_status:OK took:10.017559ms]

Relevant configuration

serve:
  public:
    base_url: https://auth.mydomain.com/
    cors:
      enabled: true
      debug: true
      allowed_origins:
      - https://mydomain.com/
      allowed_methods:
      - POST
      - GET
      - PUT
      - PATCH
      - DELETE
      allowed_headers:
      - Authorization
      - Cookie
      - Content-Type
      exposed_headers:
      - Content-Type
      - Set-Cookie

Version

v0.11.0-alpha.0.pre.2

On which operating system are you observing this issue?

Linux

In which environment are you deploying?

Kubernetes

Additional Context

Browser's view:

Access to XMLHttpRequest at 'https://auth.mydomain.com/self-service/login/browser' from origin 'https://mydomain.com/' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

Workaround is to manually set the CORS headers with a reverse proxy like Traefik.

jwmay2012 commented 1 year ago

Also reproduced on v0.11.0

CNLHC commented 1 year ago

Same problem here

baszalmstra commented 1 year ago

Same problem here!

aeneasr commented 1 year ago

Please use a separate gateway as a workaroudn for now, we will most likely remove CORS configuration from Ory Kratos in the forseeable future!

jwmay2012 commented 1 year ago

I'll go ahead and post my kubernetes/traefik solution then--

apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
  name: kratos-cors
  namespace: kratos
spec:
  headers:
    accessControlAllowMethods:
    - POST
    - GET
    - PUT
    - PATCH
    - DELETE
    accessControlAllowOriginList:
    - https://mydomain.com
    accessControlAllowHeaders:
    - Authorization
    - Cookie
    - Content-Type
    accessControlExposeHeaders:
    - Content-Type
    - Set-Cookie
    accessControlMaxAge: 100
    addVaryHeader: true
    accessControlAllowCredentials: true
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: kratos-public
  namespace: kratos
spec:
  entryPoints:
  - websecure
  routes:
  - match: Host(`kratos-public.mydomain.com`) || Host(`kratos.mydomain.com`)
    kind: Rule
    middlewares:
        - name: kratos-cors
    services:
    - name: kratos-public
      port: 80
  tls:
    secretName: kratos-public-mydomain-com

Can Oathkeeper's header Mutator be used to add response headers?

baszalmstra commented 1 year ago

Thanks! That's exactly the route I took!

baszalmstra commented 1 year ago

Mm but how would you solve this when working with docker-compose on a local machine?

jwmay2012 commented 1 year ago

Well, some gateway/proxy is still required to add the headers. Unless I'm mistaken, Oathkeeper only adds headers for incoming requests to the backend, not to outgoing responses. So something else is needed.

I would be including Traefik in my docker-compose environments as well. I usually do anyways because I like using domain names over ports and https(+mkcert) over http. (especially for Kratos testing) And it makes it similar to my "production" homelab Portainer compose deployments.

I don't have an example on hand, but here's the Traefik CORS Docs.

For work, I use Tilt for local, with Traefik.

baszalmstra commented 1 year ago

To me then it seems that removing CORS configuration will make local development considerably more complicated than it is now. Will the quickstart in the docs also be updated to show how to deal with this?

jwmay2012 commented 1 year ago

I think the quickstart uses the server-side browser flow example UI, correct? CORS issues won't arise until you've started doing client side AJAX flows. I suppose that's how I've gone 3 months tinkering with kratos/ory without noticing the CORS issues until we started integrating with our SPA. 🤷🏻‍♂️

But yeah, this doc page should be replaced.

aeneasr commented 1 year ago

We also welcome hotfixes to the problem! Maybe the middleware is misisng or something :)

kstasik commented 1 year ago

I encountered the same problem during migration from v0.10 to v0.11. I think this change introduced the error:

https://github.com/ory/kratos/commit/37b1a3bb0cf2ea859d672674ca0e95893e63301b#diff-72566b47e51d7d721721de7d2e07c322112c4c9e4edb9a8730bb0eb2a40407d1R109

The interesting thing is that OPTIONS request/response is working correctly but not knowing why CORS response headers disappear during the actual request.

alnr commented 1 year ago

Closed via https://github.com/ory/kratos/pull/2934

prajaybasu commented 1 year ago

I already use Envoy in front of Kratos to control access to the admin APIs, but this broke my setup locally and I also had to deploy a hotfix to my proxy config as I was expecting Kratos to control the CORS headers. Is there a hotfix version going to be released with #2934 anytime soon?

jijjijj commented 1 year ago

Yes, the hotfix version with #2934 is much needed. Is there any updates on that?