Skip to main content
Lead Generation Websites, Google Maps Ranking, WhatsApp Funnels, Ecommerce, SEO, Web DesignSpeed Optimization · Conversion Optimization · Monthly Lead Systems · AI AutomationLead Generation Websites, Google Maps Ranking, WhatsApp Funnels, Ecommerce, SEO, Web Design

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

Published: January 14, 2026
Written by Sumeet Shroff
Laravel Sanctum for SPAs: Cookie Auth, CSRF, CORS, and Production-Safe Defaults
Table of Contents
  1. Real-World Scenarios
  2. Scenario 1: Cookie never appears after /sanctum/csrf-cookie
  3. Scenario 2: Intermittent 419 CSRF errors behind load balancer
  4. Scenario 3: Third-party integration required (optional)
  5. Checklist
  6. About Prateeksha Web Design
In this guide you’ll learn
  • How to set up Laravel Sanctum cookie authentication for SPAs step-by-step
  • How CSRF and CORS interplay with cookie auth and how to configure them securely
  • Common misconfigurations, debugging techniques, 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.

Tip Use cookie-based auth for first-party SPAs (same site or subdomain) — it's simpler and more secure than sending tokens in localStorage.

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)

  1. 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)
  1. 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
  1. 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
  1. 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.

FeatureCookie (Session) AuthToken (API Token / JWT)
Browser-managed expiryYesUsually client-managed
HttpOnly protectionYes (if set)No (if stored in localStorage)
CSRF protection neededYes (laravel provides)Typically not (use bearer tokens)
CORS complexityHigh (credentials + origin config)Lower (bearer tokens)
Fact Cookie auth with proper HttpOnly and Secure flags significantly reduces token theft risk from XSS compared to storing tokens in localStorage.

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
Warning Never set Access-Control-Allow-Origin to '*' if you allow credentials. That combination will be blocked by browsers and opens security risks.

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

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)

Key takeaways
  • Cookie-based auth with Sanctum is secure for first-party SPAs when cookies, CSRF, and CORS are configured together.
  • Always enable credentials and explicit allowed origins in CORS — never use '*' with cookies.
  • Set secure, HttpOnly, and appropriate SameSite cookie flags, and use HTTPS in production.
  • Call /sanctum/csrf-cookie before login and use credentials: 'include' to ensure cookies are sent.
  • Use monitoring and consistent session storage across instances, and rate-limit auth endpoints.

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.

Sumeet Shroff
Sumeet Shroff
Sumeet Shroff is a renowned expert in web design and development, sharing insights on modern web technologies, design trends, and digital marketing.

Comments

Leave a Comment

Loading comments...