---
title: "Browser cookies and CSRF"
description: "Configure hardened first-party browser sessions with double-submit CSRF protection."
image: "https://adonisjs-jwt.pages.dev/og.png"
---

> Documentation Index
> Fetch the complete documentation index at: https://adonisjs-jwt.pages.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Browser cookies and CSRF

Cookie transport stores access and refresh credentials in `httpOnly` cookies. JavaScript cannot
read those credentials, but the browser sends them automatically; unsafe methods therefore require
CSRF protection.

## Configure cookie mode

```ts
transport: transports.cookie({
  secure: true,
  sameSite: 'lax',
  accessCookie: 'jwt_access',
  refreshCookie: 'jwt_refresh',
  csrfCookie: 'jwt_csrf',
  csrfHeader: 'x-csrf-token',
  accessPath: '/',
  refreshPath: '/auth/refresh',
})
```

`SameSite` is restricted to `lax` or `strict`. Keep `secure: true` outside local HTTP tests. The
refresh cookie is scoped to the refresh route, reducing where the long-lived credential is sent.
The package writes the CSRF cookie without `httpOnly` so browser code can echo it.

## Send the CSRF proof

For `POST`, `PUT`, `PATCH`, and `DELETE`, read the `jwt_csrf` cookie and copy its exact value into
`x-csrf-token`:

```ts
await fetch('/auth/refresh', {
  method: 'POST',
  credentials: 'include',
  headers: { 'x-csrf-token': readCookie('jwt_csrf') },
})
```

The guard compares the cookie and header with a timing-safe equality check. Missing or mismatched
proof raises `E_CSRF_TOKEN_MISMATCH`. `GET`, `HEAD`, and `OPTIONS` do not require the header.

## Deployment checklist

- Terminate TLS before the application and leave `secure: true`.
- Use one canonical first-party origin when possible.
- Set `domain` only when trusted sibling subdomains must share authentication.
- Do not widen the refresh cookie path beyond the refresh endpoint.
- Keep state-changing routes on unsafe HTTP methods; never mutate state through `GET`.
- If `@adonisjs/shield` also performs CSRF validation, align the exempt routes and header name so
  both layers enforce the same browser contract.

Logout clears all three cookies with the same path, domain, `SameSite`, and secure attributes used
when writing them.

Source: https://adonisjs-jwt.pages.dev/browser-cookies/index.mdx
