Common Cookie and CSRF Pitfalls
Because Ory Kratos isn't just an API, but instead talks to your users' browsers directly, several security measures have been implemented in Ory Kratos. One of them is protection against CSRF:
CSRF is an attack that tricks the victim into submitting a malicious request. It inherits the identity and privileges of the victim to perform an undesired function on the victimβs behalf. For most sites, browser requests automatically include any credentials associated with the site, such as the userβs session cookie, IP address, Windows domain credentials, and so forth. Therefore, if the user is authenticated to the site, the site will have no way to distinguish between the forged request sent by the victim and a legitimate request sent by the victim.
To protect against CSRF, several endpoints are protected by Anti-CSRF measures.
Typically, endpoints accepting POST
, DELETE
, PUT
actions have Anti-CSRF
measures. When rendering a form for example, a
<input type="hidden" name="csrf_token" value="...">
HTML Input Element is
added. Ory Kratos compares that value to the value set in the Anti-CSRF Cookie.
If the values match, the request is allowed.
Ory Kratos uses HTTP Cookies to store login sessions when accessed via a browser.
Common Pitfallsβ
Sometimes, cookies and CSRF just wont work - all requests end up with a 401 Unauthorized or 400 Bad Request. Here are some common causes and easy fixes if that happens to you!
Before starting to debug cookie and CSRF issues, make sure to check out the Chrome Developer Tools (or any comparable technology) Cookies tabs in the Application tab
as well as the network tab - look for Cookie
and Set-Cookie
HTTP Headers:
SameSite Attributeβ
If you run Ory Kratos in --dev
mode, it disables SameSite=Lax
as Google
Chrome rejects all cookies that have SameSite=Lax
but have secure
set to
false
. If you require SameSite=Lax
, you need to run Ory Kratos with HTTPS
and not use the --dev
flag.
Ory Kratos running over HTTP without dev-mode enabledβ
Ory Kratos' cookies have the Secure
flag enabled by default. This means that
the browser won't send the cookie unless the URL is a HTTPS URL. If you want Ory
Kratos to work with HTTP (for example on localhost) you can add the --dev
flag: kratos serve --dev
.
Don't do this in production!
Running on separate (sub-)domainsβ
Cookies work best on the same domain. While it's possible to get cookies running on subdomains it isn't possible to do that across Top Level Domains (TLDs).
Make sure that your application (for example the Quickstart self service app )
and Ory Krato's Public API are available on the same domain - preferably without
subdomains. Hosting both systems and routing paths with a Reverse Proxy such as
Nginx or Envoy or AWS API Gateway is the best solution. For example, routing
https://my-website/kratos/...
to Ory Kratos and https://my-website/dashboard
to the SecureApp's Dashboard. Alternatively you can use piping in your app as we
do in the Quickstart guide.
We don't recommend running them on separate subdomains, such as
https://kratos.my-website/
and https://secureapp.my-website/
.
To allow cookies to work across subdomains, make sure to set the domain name in
the Kratos config file under
session.cookie.domain
.
Running the apps on different TLDs won't work at all, such as
https://kratos-my-website/
and https://secureapp-my-website/
.
Running the services on different ports however is ok, if the domain stays the same.
Mixing up 127.0.0.1 and localhostβ
As already explained, make sure that the TLD stays the same. This is also true
for 127.0.0.1
and localhost
which are both separate TLDs. Make sure that you
use 127.0.0.1
or localhost
consistently across your configuration!
Trying to access Ory Kratos Cookies from client-side JavaScriptβ
The cookies Ory Kratos sets can't be accessed directly from Client-Side
JavaScript because the HttpOnly
flag is set. This flag can't be modified!
Accessing Ory Kratos APIs from client-side JavaScript / AJAXβ
When implementing a Single Page App (SPA) using AngularJS or ReactJS you probably want to access Ory Krato's Public APIs.
To prevent several attack vectors, Ory Krato's Public API is protected - even for some GET requests - with Anti-CSRF measures.
Because AJAX doesn't send cookies per default, you need to configure your AJAX
request to include cookies. Using the Browser's fetch
function, you need to
set
credentials: 'include'
for example.
Accessing Ory Kratos APIs from a server-side applicationβ
When implementing a server-side application (for example in PHP, Java, Go,
NodeJS, ...) make sure to include the Cookie
header from the client when
fetching the self-service flows (for example
GET /self-service/login/flows?id=...
):
export default (req: Request, res: Response) => {
// ...
kratos.getSelfServiceLoginFlow(flow, req.header('cookie'))
}
A complete example looks as follows:
Without forwarding the Cookie
HTTP Header it won't be possible to fetch the
flow due to a security error. This protection prevents accidental leak of
personal information when users copy/paste, for example, the login URL.