Skip to content

Commit eadce3f

Browse files
Goosterhofclaude
andcommitted
docs(http): surface Sanctum XSRF interaction (queue #22)
Add an Authentication & XSRF section to docs/packages/http.md sibling- level to the Doctrine #8 Timeout block, naming Laravel Sanctum SPA explicitly, explaining the XSRF-TOKEN cookie + axios 1.x withXSRFToken mechanics, and stating the HTTP 419 failure mode (which mocked transports do not surface, per ADR-0017). Stateless / token / non- Sanctum stacks documented as the inverse case. Expand the API Reference row for options.withXSRFToken with the same guidance and a cross-link to the new section. Add a one-line README pointer mirroring the Timeout pointer shape landed by Engineer PR #68 (no full duplication; docs page is source of truth). Closes enforcement queue #22 docs path. Commander disposition: docs- only. Library default of withXSRFToken: false stays as-is. No oxlint call-site rule. No source code changes. No version bump. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent f51e8b2 commit eadce3f

2 files changed

Lines changed: 35 additions & 8 deletions

File tree

docs/packages/http.md

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,29 @@ The default is also exported as a barrel-level constant for consumers that want
9999
import {DEFAULT_TIMEOUT_MS} from '@script-development/fs-http';
100100
```
101101

102+
## Authentication & XSRF
103+
104+
`withXSRFToken` defaults to `false` because the factory does not know what authentication shape it sits in front of — Laravel Sanctum SPA, stateless API tokens, OIDC backends, and third-party API gateways all want different answers. Consumers must opt in explicitly when their backend plants an XSRF cookie.
105+
106+
### Laravel Sanctum SPA
107+
108+
Laravel's Sanctum stateful middleware plants an `XSRF-TOKEN` cookie on the SPA's domain during the `/sanctum/csrf-cookie` handshake. axios 1.x will only read that cookie and forward it as the `X-XSRF-TOKEN` header when `withXSRFToken: true` is passed explicitly. Without that flag every state-changing request (POST / PUT / PATCH / DELETE) returns **HTTP 419 (CSRF token mismatch)** from Sanctum's middleware.
109+
110+
```typescript
111+
const http = createHttpService(`${location.origin}/api`, {
112+
withXSRFToken: true, // Laravel Sanctum SPA — read XSRF-TOKEN cookie
113+
withCredentials: true, // send session cookie (default true)
114+
});
115+
```
116+
117+
::: warning Mocked transports hide this failure mode
118+
Page-integration test suites that mock `@script-development/fs-http` (per ADR-0017) bypass axios entirely — the XSRF cookie / `X-XSRF-TOKEN` header round-trip never executes, so a missing `withXSRFToken: true` does not surface in test output. The first signal arrives in production: every state-changing request to a Sanctum SPA backend returns 419. Set `withXSRFToken: true` at instantiation in any Sanctum SPA consumer.
119+
:::
120+
121+
### Stateless / token / non-Sanctum stacks
122+
123+
Stateless API token stacks (Bearer tokens, OAuth2 access tokens), OIDC backends that do not plant an `XSRF-TOKEN` cookie, and third-party API gateways should leave `withXSRFToken` at the default `false`. Enabling it is a no-op when no `XSRF-TOKEN` cookie exists on the request origin, but the explicit `false` documents the consumer's authentication shape and prevents drift if a Sanctum-shaped middleware is added to the same domain later.
124+
102125
## Middleware
103126

104127
The middleware system lets you intercept requests at three points in the lifecycle. Every registration returns an unregister function:
@@ -199,14 +222,14 @@ try {
199222

200223
### `createHttpService(baseURL, options?)`
201224

202-
| Parameter | Type | Description |
203-
| -------------------------- | ------------------------ | ----------------------------------------------------------------------- |
204-
| `baseURL` | `string` | Base URL for all requests |
205-
| `options.timeout` | `number \| undefined` | Request timeout in milliseconds (default: `30000`; pass `0` to disable) |
206-
| `options.headers` | `Record<string, string>` | Default headers |
207-
| `options.withCredentials` | `boolean` | Send cookies cross-origin (default: `true`) |
208-
| `options.withXSRFToken` | `boolean` | Include XSRF token (default: `false`) |
209-
| `options.smartCredentials` | `boolean` | Auto-toggle credentials by origin (default: `false`) |
225+
| Parameter | Type | Description |
226+
| -------------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
227+
| `baseURL` | `string` | Base URL for all requests |
228+
| `options.timeout` | `number \| undefined` | Request timeout in milliseconds (default: `30000`; pass `0` to disable) |
229+
| `options.headers` | `Record<string, string>` | Default headers |
230+
| `options.withCredentials` | `boolean` | Send cookies cross-origin (default: `true`) |
231+
| `options.withXSRFToken` | `boolean` | Forward `XSRF-TOKEN` cookie as `X-XSRF-TOKEN` header (default: `false`). Set `true` for Laravel Sanctum SPA; leave `false` for stateless / token / non-Sanctum stacks. See [Authentication & XSRF](#authentication-xsrf). |
232+
| `options.smartCredentials` | `boolean` | Auto-toggle credentials by origin (default: `false`) |
210233

211234
### Constants
212235

packages/http/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ Creates a new HTTP service instance.
4646

4747
Per **Doctrine #8 library-author extension** (war-room CLAUDE.md, 2026-04-22), the factory applies a **30000ms default timeout** with `timeout: 0` opt-out and per-request override. See [the docs site Timeout section](https://packages.script.nl/packages/http#timeout) for the full surface contract.
4848

49+
### Authentication & XSRF
50+
51+
For Laravel Sanctum SPA consumers, `withXSRFToken: true` is required to avoid HTTP 419 (CSRF mismatch) on state-changing requests; mocked transports do not surface this. See [the docs site Authentication & XSRF section](https://packages.script.nl/packages/http#authentication-xsrf) for the full discussion (including stateless / non-Sanctum guidance).
52+
4953
### Request Methods
5054

5155
- `getRequest<T>(endpoint, options?)` — GET request

0 commit comments

Comments
 (0)