Skip to content

Howto CSRF tokens

root edited this page Apr 19, 2026 · 1 revision

How to use CSRF tokens in scripts

Bindery v1.0 replaces the X-Requested-With header check with a double-submit CSRF token on all session-cookie-authenticated mutations (POST, PUT, PATCH, DELETE).

Browser users: the UI handles this transparently — no action needed.

API-key users: CSRF is not required. X-Api-Key requests bypass the check entirely. Existing automation continues to work without changes.

Scripts using session cookies: read on.


When you need a CSRF token

You need a token if your script:

  • Authenticates with a bindery_session cookie (e.g., you logged in via the browser and grabbed the cookie), and
  • Makes any mutating request (POST, PUT, PATCH, DELETE)

If you're using X-Api-Key, skip this page — you're already exempt.

Fetching a token

TOKEN=$(curl -s \
  -b "bindery_session=<your-session-cookie>" \
  http://bindery:8787/api/v1/auth/csrf \
  | jq -r .token)

Tokens are per-session and do not expire between requests in the same session. Fetch once, reuse for the session lifetime.

Using the token

Pass it as the X-CSRF-Token header on every mutating request:

curl -X POST http://bindery:8787/api/v1/author \
  -b "bindery_session=<your-session-cookie>" \
  -H "X-CSRF-Token: $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "Ursula K. Le Guin"}'

Full example — add an author via session cookie

#!/usr/bin/env bash
BINDERY=http://bindery:8787
COOKIE="bindery_session=<your-session-cookie>"

# 1. Fetch CSRF token
TOKEN=$(curl -s -b "$COOKIE" "$BINDERY/api/v1/auth/csrf" | jq -r .token)

# 2. Use it on the mutation
curl -X POST "$BINDERY/api/v1/author" \
  -b "$COOKIE" \
  -H "X-CSRF-Token: $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "Ursula K. Le Guin"}'

Migrating existing scripts

If your script was using X-Requested-With: XMLHttpRequest (the pre-v1.0 CSRF bypass), switch to X-Api-Key:

# Before (v0.x)
curl -X POST http://bindery:8787/api/v1/author \
  -b "bindery_session=<cookie>" \
  -H "X-Requested-With: XMLHttpRequest" \
  ...

# After — option A: switch to API key (simplest, recommended)
curl -X POST http://bindery:8787/api/v1/author \
  -H "X-Api-Key: <your-api-key>" \
  ...

# After — option B: keep session cookie, add CSRF preflight
TOKEN=$(curl -s -b "bindery_session=<cookie>" http://bindery:8787/api/v1/auth/csrf | jq -r .token)
curl -X POST http://bindery:8787/api/v1/author \
  -b "bindery_session=<cookie>" \
  -H "X-CSRF-Token: $TOKEN" \
  ...

Option A is simpler and recommended for automation. Your API key is in Settings → My Account → API Key.


Troubleshooting

Symptom Cause Fix
403 Forbidden on mutations that worked before v1.0 Script uses session-cookie auth but doesn't send X-CSRF-Token Switch to X-Api-Key, or add the CSRF preflight (see above)
403 even with X-CSRF-Token present Token was fetched with a different session cookie than the one used on the mutation Fetch the token and make the mutation with the same bindery_session cookie value
401 Unauthorized on GET /api/v1/auth/csrf Session cookie is expired or invalid Log in again to get a fresh session cookie
X-Requested-With: XMLHttpRequest stopped working Removed in v1.0 Switch to X-Api-Key or use the CSRF token flow

See also: docs/multi-user.md — CSRF tokens | Troubleshooting

Clone this wiki locally