Laravel Sanctum for SPAs: Cookie Auth, CSRF, CORS, and Production-Safe Defaults

Introduction
Laravel Sanctum is a pragmatic and lightweight library for SPA authentication. When using cookie-based session authentication, you get browser-managed cookies, CSRF protection, and the benefits of same-site controls — but you also need to configure CORS, secure cookies, and routing correctly. This hands-on guide walks through setup, common pitfalls, debugging, and production-safe defaults.
Why cookie auth for SPAs?
Cookie auth keeps session state managed by the browser, reduces exposure to XSS (if cookies are HttpOnly), and integrates with Laravel's CSRF protections. But to make it robust you must align cookie settings, CSRF token handling, and CORS correctly.
Core setup (step-by-step)
- Install and configure Sanctum
- composer require laravel/sanctum
- php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
- Add Sanctum's middleware per docs (ensure middlewareGroup for api uses 'web' where necessary)
- Set up cookie configuration in config/session.php
- 'secure' => env('SESSION_SECURE_COOKIE', true) in production
- 'same_site' => 'lax' or 'none' (see CORS notes below)
- Use a long, random SESSION_COOKIE name for privacy
- Configure CORS (config/cors.php) and environment
- Allowed origins should be explicit (no wildcard for credentials)
- 'supports_credentials' => true
- Set Access-Control-Allow-Credentials on responses
- Frontend flow (example using fetch/axios)
- On app start: call GET /sanctum/csrf-cookie to set XSRF-TOKEN cookie
- On login: POST to /login (include credentials) with credentials: 'include'
- For authenticated requests: include credentials and rely on cookie auth and X-XSRF-TOKEN header
Code snippet (axios):
axios.defaults.withCredentials = true; await axios.get('https://api.example.com/sanctum/csrf-cookie'); await axios.post('https://api.example.com/login', { email, password });
Common misconfigurations and how to fix them
-
Misconfigured CORS or missing credentials: If you get 401s or the cookie never appears, confirm config/cors.php allows the SPA origin and supports credentials. Browsers block setting cookies from cross-origin responses unless Access-Control-Allow-Credentials is true and the request uses credentials.
-
Using '' for Access-Control-Allow-Origin: Browsers forbid '' when credentials are used. Explicitly list origins.
-
Cookie SameSite issues: If your SPA runs on a different top-level domain or uses a cross-site iframe, 'same_site' must be 'none' and cookies must be secure.
-
CSRF token not sent: Call /sanctum/csrf-cookie first, and ensure frontend reads XSRF-TOKEN cookie via header X-XSRF-TOKEN (Axios does this automatically when withCredentials is true).
-
Session driver pitfalls: If you use a distributed session store (Redis), ensure session affinity and same encryption keys across instances.
Debugging checklist (quick)
- Confirm cookie present in browser devtools after /sanctum/csrf-cookie
- Confirm Set-Cookie includes Secure and SameSite as expected
- Confirm Access-Control-Allow-Credentials and Access-Control-Allow-Origin headers
- Inspect network tab for preflight (OPTIONS) and response headers
Comparison: Cookie Auth vs Token Auth
Below is a short comparison to help choose the right approach.
| Feature | Cookie (Session) Auth | Token (API Token / JWT) |
|---|---|---|
| Browser-managed expiry | Yes | Usually client-managed |
| HttpOnly protection | Yes (if set) | No (if stored in localStorage) |
| CSRF protection needed | Yes (laravel provides) | Typically not (use bearer tokens) |
| CORS complexity | High (credentials + origin config) | Lower (bearer tokens) |
CORS and CSRF: how they interact
- CSRF defense requires a secret token and a cookie; Laravel's XSRF-TOKEN cookie plus X-XSRF-TOKEN header verifies intent.
- CORS credentials require both server and client opt-in: server sets Access-Control-Allow-Credentials: true, and client uses credentials: 'include'.
- If you set SameSite=None for cookies, you must also set Secure=true.
Production-safe defaults
- SESSION_SECURE_COOKIE=true in production
- session.same_site='lax' for most first-party SPAs; use 'none' only if cross-site is necessary
- Use strong CSRF cookie rotation and short session lifetimes
- Enable rate limiting on auth endpoints
- Use HTTPS and HSTS headers
Real-World Scenarios
Real-World Scenarios
Scenario 1: Cookie never appears after /sanctum/csrf-cookie
A small team deployed backend on api.example.com and frontend on app.example.com. They called /sanctum/csrf-cookie but the browser didn't store XSRF-TOKEN. The cause was CORS: config/cors.php allowed origins: ['*'] and supports_credentials was false; switching to explicit origin and enabling credentials fixed it.
Scenario 2: Intermittent 419 CSRF errors behind load balancer
A SaaS product used multiple app servers and Redis sessions. Occasionally users got 419 responses. Root cause: clocks out of sync and session affinity missing in the load balancer. Fix: enable sticky sessions or centralize session store correctly and ensure consistent keys.
Scenario 3: Third-party integration required (optional)
An analytics widget loaded on a different domain needed to call an authenticated endpoint. Team realized cookie-based auth isn't suitable for third-party calls; they created a scoped API token with minimal privileges instead.
Latest News & Trends
- Modern browsers tighten SameSite cookie behavior — prefer conservative SameSite settings and test cross-origin patterns.
- Increasing adoption of first-party cookie patterns for SPAs due to XSS resistance compared to token storage.
- Growth in service-worker and PWA usage requires explicit testing of cookie behavior in those contexts.
Latest News & Trends
Note: The items above reflect general trends and evolving browser behavior; always test across the browsers you support.
Checklist
Checklist
-
Backend (Laravel)
- sanctum installed and published
- session driver configured consistently across instances
- config/cors.php allows SPA origin and supports_credentials=true
- SESSION_SECURE_COOKIE enabled in production
- Rate limiting on auth routes
-
Frontend (SPA)
- Call /sanctum/csrf-cookie on app start
- Use credentials: 'include' or axios.withCredentials
- Ensure your domain/subdomain aligns with cookie SameSite choices
- Test login, logout, and token expiration flows
-
Deployment
- HTTPS everywhere and HSTS
- Consistent environment variables across nodes
- Monitoring and access logs for auth failures
Advanced debugging steps
- Reproduce with curl to inspect Set-Cookie and CSRF token header. Example:
curl -i -c cookies.txt 'https://api.example.com/sanctum/csrf-cookie'
- Use browser devtools Application > Cookies and Network to verify cookie attributes.
- Inspect failed preflight (OPTIONS) responses and ensure Access-Control-Allow-Origin matches request origin.
External references and guidance
- For CORS best practices and browser behavior, see Mozilla MDN Web Docs.
- For web security guidelines including CSRF, see OWASP.
- For broader cybersecurity frameworks and controls, consult the NIST Cybersecurity Framework.
- For performance and SEO/UX considerations around secure patterns, see Google Search Central and Google Lighthouse.
- For edge and CDN considerations for headers and cookies, see Cloudflare Learning Center.
Key troubleshooting examples
- 401 after successful login: check that Set-Cookie was sent and subsequent requests include cookie and correct X-XSRF-TOKEN header.
- 419 CSRF mismatch: inspect XSRF-TOKEN cookie vs X-XSRF-TOKEN header values; ensure CSRF cookie is not blocked by SameSite.
- Cookie not persistent: check path, domain, secure flag, and whether the environment is http in local dev.
Key takeaways (before conclusion)
Conclusion
Securely implementing Laravel Sanctum for SPAs centers on aligning cookie settings, CSRF flows, and CORS. With careful configuration and the production-safe defaults above you'll reduce common risks and make debugging predictable.
FAQs
(See the FAQ section below for five common questions.)
About Prateeksha Web Design
Prateeksha Web Design builds secure, accessible web applications and consults on backend authentication, SPA architecture, and production deployments. We implement best practices for secure cookie auth and API protection across Laravel and modern frontends.
Chat with us now Contact us today.