{"ok": true, "database": "docs", "table": "sections", "rows": [{"id": "upgrade_guide:upgrade-guide-csrf", "page": "upgrade_guide", "ref": "upgrade-guide-csrf", "title": "CSRF protection is now header-based", "content": "Datasette's Cross-Site Request Forgery protection no longer uses tokens. The previous  asgi-csrf  mechanism - which set a  ds_csrftoken  cookie and required a matching  <input type=\"hidden\" name=\"csrftoken\">  in every form - has been replaced with an ASGI middleware that inspects the browser-set  Sec-Fetch-Site  and  Origin  headers, following the approach described in  Filippo Valsorda's research  and implemented in Go 1.25's  http.CrossOriginProtection . \n                 This works identically on HTTPS, HTTP, and localhost. Non-browser clients (curl, Python  requests , server-to-server scripts) do not send  Sec-Fetch-Site  or  Origin  and are passed through unchanged - CSRF is a browser-only attack. \n                 Requests that carry an explicit  Authorization: Bearer ...  header are also exempt from the CSRF check, because bearer tokens are not ambient browser credentials: a malicious cross-origin page cannot cause the browser to attach a target site's bearer token unless the attacker's JavaScript already possesses it. This exemption is narrow - it covers the  Bearer  scheme only, not  Basic  or  Digest  - and it does not depend on the  --cors  setting. The exemption is about CSRF classification, not browser read access; CORS still controls the latter.", "breadcrumbs": "[\"Upgrade guide\", \"Datasette 1.0a20 plugin upgrade guide\"]", "references": "[{\"href\": \"https://words.filippo.io/csrf/\", \"label\": \"Filippo Valsorda's research\"}]"}], "primary_keys": ["id"], "primary_key_values": ["upgrade_guide:upgrade-guide-csrf"], "query_ms": 5.868424999789568, "truncated": false}