Sanctum SPA authentication: common misconfigurations
Spent three days debugging Sanctum SPA auth issues on a Vue + Laravel setup. Documenting the mistakes for others.
The CSRF cookie flow is conceptually simple but breaks in non-obvious ways.
Most common mistake: calling /sanctum/csrf-cookie before the login request, then making the login request without including the XSRF-TOKEN header. Axios sends it automatically if you have withCredentials: true and the cookie is present. Check browser dev tools, Network tab.
CORS is the second common issue. SESSION_DOMAIN in .env needs to match the subdomain relationship between API and SPA. If SPA is on app.example.com and API on api.example.com, SESSION_DOMAIN=.example.com with the leading dot.
stateful_domains in sanctum.php config must include the domain where the SPA is served. This determines which requests use cookie-based auth vs token auth.
Running SPA on localhost:3000 and API on localhost:8000 breaks same-origin cookie rules. You need to proxy /api through the SPA dev server (Vite proxy config) to make them appear same-origin.
In production, session cookies need Secure and SameSite=Lax. SameSite=None requires Secure (HTTPS). Getting this wrong means cookies are silently dropped by modern browsers.
For mobile apps or non-browser clients, use Sanctum tokens (not cookie auth). SPA cookie auth is specifically for browser same-site scenarios. Mixing the two approaches on the same client causes subtle bugs.
```php blocks are runnable.