ory / kratos

The most scalable and customizable identity server on the market. Replace your Homegrown, Auth0, Okta, Firebase with better UX and DX. Has all the tablestakes: Passkeys, Social Sign In, Multi-Factor Auth, SMS, SAML, TOTP, and more. Written in Go, cloud native, headless, API-first. Available as a service on Ory Network and for self-hosters.
https://www.ory.sh/?utm_source=github&utm_medium=banner&utm_campaign=kratos
Apache License 2.0
11.3k stars 964 forks source link

CSRF Error during Login Flow despite passing cookies, X-CSRF-Token headers on SvelteKit Server Side. #4030

Open devNamanG opened 3 months ago

devNamanG commented 3 months ago

Preflight checklist

Ory Network Project

No response

Describe the bug

In my SvelteKit application, in the server-side load function (+page.server.ts), upon receiving a request and checking that there is no existing flow, we creat a login flow using client.createBrowserLoginFlow({ cookie }) and set the cookies that are returned by the response of the above. The browser now has the csrftoken* cookie and the flow id (i am not using url parameters to store the flow, but instead a secure, httponly cookie named flow-id to do the same thing with the expiry set to the flow's expiry). Everything works initially, but when the page is reloaded and the cookie is not expired (i.e. the flow is still valid), we use client.getLoginFlow({ id: flowId, cookie }, {withCredentials: true}) to fetch the flow, but i get the csrf security violation error. I am FORWARDING the cookies to kratos, despite which i still get the csrf violation error. I also tried setting the X-CSRF-Token header since this is a GET request, due to which i can't pass a request body with the csrf_token, despite which the error still comes.

Reproducing the bug

  1. Create a sveltekit app.
  2. Configure Kratos redirect urls to your frontend UI.
  3. In a +page.server.ts, add a load function, which calls the client.createBrowserLoginFlow function and pass the cookies to it, if a flow-id doesn't already exist, and calls client.getLoginFlow if a flow id already exists (and is not expired).
  4. Set the cookies returned by the responses of the function calls, and render the UI.

Relevant log output

Kratos log output: (Note: The cookie name is not csrf_token_redacted, the part after csrf_token_ is redacted and not included in the logs)

2024-08-10 15:11:11 time=2024-08-10T09:41:11Z level=info msg=started handling request func=github.com/ory/x/reqlog.(*Middleware).ServeHTTP file=/go/pkg/mod/github.com/ory/x@v0.0.623/reqlog/middleware.go:134 http_request=map[headers:map[accept:application/json, text/plain, */* accept-encoding:gzip, br cdn-loop:cloudflare cf-connecting-ip:49.205.86.254 cf-ipcountry:IN cf-ray:8b0f075c7ddda98e-SIN cf-visitor:{"scheme":"https"} cf-warp-tag-id:04876878-1a3e-416f-bf89-50cfa6b3ed98 connection:keep-alive cookie:[] user-agent:axios/1.7.3 x-forwarded-for:49.205.86.254 x-forwarded-proto:https] host:kratos.example.com method:GET path:/self-service/login/browser query:<nil> remote:172.20.0.5:34670 scheme:http]
2024-08-10 15:11:11 time=2024-08-10T09:41:11Z level=info msg=completed handling request func=github.com/ory/x/reqlog.(*Middleware).ServeHTTP file=/go/pkg/mod/github.com/ory/x@v0.0.623/reqlog/middleware.go:146 http_request=map[headers:map[accept:application/json, text/plain, */* accept-encoding:gzip, br cdn-loop:cloudflare cf-connecting-ip:49.205.86.254 cf-ipcountry:IN cf-ray:8b0f075c7ddda98e-SIN cf-visitor:{"scheme":"https"} cf-warp-tag-id:04876878-1a3e-416f-bf89-50cfa6b3ed98 connection:keep-alive cookie:[] user-agent:axios/1.7.3 x-forwarded-for:49.205.86.254 x-forwarded-proto:https] host:kratos.example.com method:GET path:/self-service/login/browser query:<nil> remote:172.20.0.5:34670 scheme:http] http_response=map[headers:map[cache-control:private, no-cache, no-store, must-revalidate content-type:application/json; charset=utf-8 set-cookie:[csrf_token_redacted=4bxDGHkTqyCyFbImW7+EC/amBO2BBpwzgGD08+WTgRI=; Path=/; Domain=example.com; Max-Age=31536000; HttpOnly; SameSite=Lax] vary:Origin] size:1507 status:200 text_status:OK took:35.597608ms]
2024-08-10 15:11:18 time=2024-08-10T09:41:18Z level=info msg=started handling request func=github.com/ory/x/reqlog.(*Middleware).ServeHTTP file=/go/pkg/mod/github.com/ory/x@v0.0.623/reqlog/middleware.go:134 http_request=map[headers:map[accept:application/json, text/plain, */* accept-encoding:gzip, br cdn-loop:cloudflare cf-connecting-ip:49.205.86.254 cf-ipcountry:IN cf-ray:8b0f0788bea79ca7-SIN cf-visitor:{"scheme":"https"} cf-warp-tag-id:04876878-1a3e-416f-bf89-50cfa6b3ed98 connection:keep-alive cookie:[flow-id=2ffa8904-99b7-4e52-a5c0-e591b09cf3f6; csrf_token_redacted=4bxDGHkTqyCyFbImW7%2BEC%2FamBO2BBpwzgGD08%2BWTgRI%3D] user-agent:axios/1.7.3 x-csrf-token:4bxDGHkTqyCyFbImW7%2BEC%2FamBO2BBpwzgGD08%2BWTgRI%3D x-forwarded-for:49.205.86.254 x-forwarded-proto:https] host:kratos.example.com method:GET path:/self-service/login/flows query:id=2ffa8904-99b7-4e52-a5c0-e591b09cf3f6 remote:172.20.0.5:34670 scheme:http]
2024-08-10 15:11:18 time=2024-08-10T09:41:18Z level=info msg=An error occurred while handling a request func=github.com/ory/x/logrusx.(*Logger).ReportError file=/go/pkg/mod/github.com/ory/x@v0.0.623/logrusx/logrus.go:230 audience=application error=map[debug: details:map[docs:https://www.ory.sh/kratos/docs/debug/csrf hint:The anti-CSRF cookie was found but the CSRF token was not included in the HTTP request body (csrf_token) nor in the HTTP Header (X-CSRF-Token). reject_reason:The HTTP Cookie Header was set and a CSRF token was sent but they do not match. We recommend deleting all cookies for this domain and retrying the flow.] message:the request was rejected to protect you from Cross-Site-Request-Forgery reason:Please retry the flow and optionally clear your cookies. The request was rejected to protect you from Cross-Site-Request-Forgery (CSRF) which could cause account takeover, leaking personal information, and other serious security issues. stack_trace:
2024-08-10 15:11:18 github.com/ory/kratos/x.CSRFErrorReason
2024-08-10 15:11:18 /project/x/nosurf.go:198
2024-08-10 15:11:18 github.com/ory/kratos/selfservice/flow/login.(*Handler).getLoginFlow
2024-08-10 15:11:18 /project/selfservice/flow/login/handler.go:615
2024-08-10 15:11:18 github.com/ory/kratos/x.(*RouterPublic).GET.NoCacheHandle.func1
2024-08-10 15:11:18 /project/x/nocache.go:21
2024-08-10 15:11:18 github.com/ory/kratos/x.(*RouterPublic).Handle.NoCacheHandle.func1
2024-08-10 15:11:18 /project/x/nocache.go:21
2024-08-10 15:11:18 github.com/julienschmidt/httprouter.(*Router).ServeHTTP
2024-08-10 15:11:18 /go/pkg/mod/github.com/julienschmidt/httprouter@v1.3.0/router.go:387
2024-08-10 15:11:18 github.com/ory/nosurf.(*CSRFHandler).handleSuccess
2024-08-10 15:11:18 /go/pkg/mod/github.com/ory/nosurf@v1.2.7/handler.go:234
2024-08-10 15:11:18 github.com/ory/nosurf.(*CSRFHandler).ServeHTTP
2024-08-10 15:11:18 /go/pkg/mod/github.com/ory/nosurf@v1.2.7/handler.go:191
2024-08-10 15:11:18 github.com/ory/kratos/cmd/daemon.servePublic.MaxBytesHandler.func4
2024-08-10 15:11:18 /usr/local/go/src/net/http/server.go:3841
2024-08-10 15:11:18 net/http.HandlerFunc.ServeHTTP
2024-08-10 15:11:18 /usr/local/go/src/net/http/server.go:2166
2024-08-10 15:11:18 github.com/urfave/negroni.(*Negroni).UseHandler.Wrap.func1
2024-08-10 15:11:18 /go/pkg/mod/github.com/urfave/negroni@v1.0.0/negroni.go:46
2024-08-10 15:11:18 github.com/urfave/negroni.HandlerFunc.ServeHTTP
2024-08-10 15:11:18 /go/pkg/mod/github.com/urfave/negroni@v1.0.0/negroni.go:29
2024-08-10 15:11:18 github.com/urfave/negroni.middleware.ServeHTTP
2024-08-10 15:11:18 /go/pkg/mod/github.com/urfave/negroni@v1.0.0/negroni.go:38
2024-08-10 15:11:18 github.com/ory/kratos/x.init.func1
2024-08-10 15:11:18 /project/x/clean_url.go:15
2024-08-10 15:11:18 github.com/urfave/negroni.HandlerFunc.ServeHTTP
2024-08-10 15:11:18 /go/pkg/mod/github.com/urfave/negroni@v1.0.0/negroni.go:29
2024-08-10 15:11:18 github.com/urfave/negroni.middleware.ServeHTTP
2024-08-10 15:11:18 /go/pkg/mod/github.com/urfave/negroni@v1.0.0/negroni.go:38
2024-08-10 15:11:18 github.com/rs/cors.(*Cors).ServeHTTP
2024-08-10 15:11:18 /go/pkg/mod/github.com/rs/cors@v1.8.2/cors.go:266
2024-08-10 15:11:18 github.com/ory/kratos/cmd/daemon.servePublic.func1
2024-08-10 15:11:18 /project/cmd/daemon/serve.go:114
2024-08-10 15:11:18 github.com/urfave/negroni.HandlerFunc.ServeHTTP
2024-08-10 15:11:18 /go/pkg/mod/github.com/urfave/negroni@v1.0.0/negroni.go:29
2024-08-10 15:11:18 github.com/urfave/negroni.middleware.ServeHTTP
2024-08-10 15:11:18 /go/pkg/mod/github.com/urfave/negroni@v1.0.0/negroni.go:38
2024-08-10 15:11:18 net/http.HandlerFunc.ServeHTTP
2024-08-10 15:11:18 /usr/local/go/src/net/http/server.go:2166
2024-08-10 15:11:18 github.com/prometheus/client_golang/prometheus/promhttp.InstrumentHandlerResponseSize.func1
2024-08-10 15:11:18 /go/pkg/mod/github.com/prometheus/client_golang@v1.13.0/prometheus/promhttp/instrument_server.go:284
2024-08-10 15:11:18 net/http.HandlerFunc.ServeHTTP
2024-08-10 15:11:18 /usr/local/go/src/net/http/server.go:2166
2024-08-10 15:11:18 github.com/prometheus/client_golang/prometheus/promhttp.InstrumentHandlerCounter.func1
2024-08-10 15:11:18 /go/pkg/mod/github.com/prometheus/client_golang@v1.13.0/prometheus/promhttp/instrument_server.go:142
2024-08-10 15:11:18 net/http.HandlerFunc.ServeHTTP
2024-08-10 15:11:18 /usr/local/go/src/net/http/server.go:2166
2024-08-10 15:11:18 github.com/prometheus/client_golang/prometheus/promhttp.InstrumentHandlerDuration.func1
2024-08-10 15:11:18 /go/pkg/mod/github.com/prometheus/client_golang@v1.13.0/prometheus/promhttp/instrument_server.go:92
2024-08-10 15:11:18 net/http.HandlerFunc.ServeHTTP
2024-08-10 15:11:18 /usr/local/go/src/net/http/server.go:2166
2024-08-10 15:11:18 github.com/prometheus/client_golang/prometheus/promhttp.InstrumentHandlerDuration.func2
2024-08-10 15:11:18 /go/pkg/mod/github.com/prometheus/client_golang@v1.13.0/prometheus/promhttp/instrument_server.go:104
2024-08-10 15:11:18 net/http.HandlerFunc.ServeHTTP
2024-08-10 15:11:18 /usr/local/go/src/net/http/server.go:2166
2024-08-10 15:11:18 github.com/prometheus/client_golang/prometheus/promhttp.InstrumentHandlerRequestSize.func1
2024-08-10 15:11:18 /go/pkg/mod/github.com/prometheus/client_golang@v1.13.0/prometheus/promhttp/instrument_server.go:234
2024-08-10 15:11:18 net/http.HandlerFunc.ServeHTTP
2024-08-10 15:11:18 /usr/local/go/src/net/http/server.go:2166
2024-08-10 15:11:18 github.com/ory/x/prometheusx.Metrics.Instrument.Metrics.instrumentHandlerStatusBucket.func1
2024-08-10 15:11:18 /go/pkg/mod/github.com/ory/x@v0.0.623/prometheusx/metrics.go:115
2024-08-10 15:11:18 net/http.HandlerFunc.ServeHTTP
2024-08-10 15:11:18 /usr/local/go/src/net/http/server.go:2166 status:Forbidden status_code:403] http_request=map[headers:map[accept:application/json, text/plain, */* accept-encoding:gzip, br cdn-loop:cloudflare cf-connecting-ip:49.205.86.254 cf-ipcountry:IN cf-ray:8b0f0788bea79ca7-SIN cf-visitor:{"scheme":"https"} cf-warp-tag-id:04876878-1a3e-416f-bf89-50cfa6b3ed98 connection:keep-alive cookie:[flow-id=2ffa8904-99b7-4e52-a5c0-e591b09cf3f6; csrf_token_redacted=4bxDGHkTqyCyFbImW7%2BEC%2FamBO2BBpwzgGD08%2BWTgRI%3D] user-agent:axios/1.7.3 x-csrf-token:4bxDGHkTqyCyFbImW7%2BEC%2FamBO2BBpwzgGD08%2BWTgRI%3D x-forwarded-for:49.205.86.254 x-forwarded-proto:https] host:kratos.example.com method:GET path:/self-service/login/flows query:id=2ffa8904-99b7-4e52-a5c0-e591b09cf3f6 remote:172.20.0.5:34670 scheme:http] http_response=map[status_code:403] service_name=Ory Kratos service_version=v1.2.0
2024-08-10 15:11:18 time=2024-08-10T09:41:18Z level=info msg=completed handling request func=github.com/ory/x/reqlog.(*Middleware).ServeHTTP file=/go/pkg/mod/github.com/ory/x@v0.0.623/reqlog/middleware.go:146 http_request=map[headers:map[accept:application/json, text/plain, */* accept-encoding:gzip, br cdn-loop:cloudflare cf-connecting-ip:49.205.86.254 cf-ipcountry:IN cf-ray:8b0f0788bea79ca7-SIN cf-visitor:{"scheme":"https"} cf-warp-tag-id:04876878-1a3e-416f-bf89-50cfa6b3ed98 connection:keep-alive cookie:[flow-id=2ffa8904-99b7-4e52-a5c0-e591b09cf3f6; csrf_token_redacted=4bxDGHkTqyCyFbImW7%2BEC%2FamBO2BBpwzgGD08%2BWTgRI%3D] user-agent:axios/1.7.3 x-csrf-token:4bxDGHkTqyCyFbImW7%2BEC%2FamBO2BBpwzgGD08%2BWTgRI%3D x-forwarded-for:49.205.86.254 x-forwarded-proto:https] host:kratos.example.com method:GET path:/self-service/login/flows query:id=2ffa8904-99b7-4e52-a5c0-e591b09cf3f6 remote:172.20.0.5:34670 scheme:http] http_response=map[headers:map[cache-control:private, no-cache, no-store, must-revalidate content-type:application/json set-cookie:[csrf_token_redacted=MRX1aycrAmY+2g62w3S5kMAFYsEvYNlXOk5AfkgJ9Nw=; Path=/; Domain=example.com; Max-Age=31536000; HttpOnly; SameSite=Lax] vary:Origin] size:794 status:403 text_status:Forbidden took:3.765172ms]

Relevant configuration

cookies:
  path: /
  # same_site: Lax (yes, i tried with and without setting this option.
  domain: example.com

Version

1.2.0

On which operating system are you observing this issue?

Linux

In which environment are you deploying?

Docker Compose

Additional Context

My Kratos public api is hosted at kratos.example.com and the UI is hosted at ui.example.com.

devNamanG commented 1 month ago

It's been more than a month and I have not been able to solve this issue, neither has this issue been updated by any one from Ory Team. It'd be really helpful if someone can help me with this.