Skip to content

Cookie auth

Use cookie authentication for browser-based apps where you want the browser to manage tokens automatically.

How it works

  1. Login sets three cookies: access token (HttpOnly), refresh token (HttpOnly), and CSRF token (readable by JS)
  2. GET requests work automatically — the browser sends cookies, no CSRF needed
  3. POST/PUT/PATCH/DELETE requests require the CSRF token in the X-CSRF-Token header
  4. Refresh and logout work via cookies — no need to manage tokens in JS

Login

const res = await fetch("/auth/login", {
  method: "POST",
  credentials: "include",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ email, password }),
});

After login, the browser stores the cookies automatically. You can ignore the JSON response body if you only use cookie transport.

Reading protected data (GET)

// Cookies are sent automatically — no extra headers needed
const res = await fetch("/auth/me", { credentials: "include" });
const user = await res.json();

Mutating requests (POST/PUT/PATCH/DELETE)

For any non-GET request to a protected route, you must include the CSRF token:

function getCsrfToken() {
  return document.cookie
    .split("; ")
    .find(row => row.startsWith("bf_csrf_token="))
    ?.split("=")[1];
}

const res = await fetch("/some-protected-endpoint", {
  method: "POST",
  credentials: "include",
  headers: {
    "Content-Type": "application/json",
    "X-CSRF-Token": getCsrfToken(),
  },
  body: JSON.stringify({ ... }),
});

Refreshing

const res = await fetch("/auth/refresh", {
  method: "POST",
  credentials: "include",
  headers: { "X-CSRF-Token": getCsrfToken() },
});
// New cookies are set automatically in the response

After refreshing, re-read the CSRF cookie — it changes on each refresh.

Logout

await fetch("/auth/logout", {
  method: "POST",
  credentials: "include",
  headers: { "X-CSRF-Token": getCsrfToken() },
});
// Cookies are cleared by the response

Local development

By default, cookies have Secure=True, which means they only work over HTTPS. For local development, disable this:

BluefoxAuth(app, settings, cookie_secure=False)

Cross-domain cookies

If your API and frontend are on different subdomains (e.g. api.example.com and app.example.com):

BluefoxAuth(app, settings, cookie_domain=".example.com")