Appearance
CORS & Sanctum (SPA authentication)
ExchangePro uses Laravel Sanctum in stateful (cookie) mode. The Nuxt app and API must be configured so cookies and CSRF tokens work across origins.
How authentication works
mermaid
sequenceDiagram
participant Browser
participant Nuxt
participant API as Laravel API
Browser->>Nuxt: Open /signin
Nuxt->>API: GET /sanctum/csrf-cookie
API-->>Browser: Set XSRF-TOKEN cookie
Nuxt->>API: POST /api/auth/signin (with X-XSRF-TOKEN)
API-->>Browser: Set session cookie
Nuxt->>API: GET /api/user (authenticated)- Frontend fetches CSRF cookie from
{API_URL}/sanctum/csrf-cookie. - Login POST includes
X-XSRF-TOKENheader. - Laravel session cookie is stored for the API domain.
- Subsequent API calls send cookies (
credentials: include).
CORS configuration
Origins are configured in backend/.env, not hardcoded in config/cors.php.
By default, FRONTEND_URL is the only allowed origin. For multiple frontends (e.g. www + apex, or local + LAN), set:
ini
FRONTEND_URL=http://localhost:4000
# Optional — full URLs with scheme, comma-separated
CORS_ALLOWED_ORIGINS=http://localhost:4000,http://127.0.0.1:4000,https://yourdomain.com,https://www.yourdomain.comIf CORS_ALLOWED_ORIGINS is omitted, Laravel uses FRONTEND_URL only.
Rules
- Each entry must be a full origin: scheme + host + port (e.g.
https://yourdomain.com). - Do not use
*whensupports_credentialsistrue. - Match the URL users type in the browser (including
wwwif you use it).
After changing .env, clear config cache:
bash
php artisan config:clearSanctum stateful domains
File: backend/config/sanctum.php
Prefer setting domains via environment variable instead of editing hardcoded LAN IPs:
ini
SANCTUM_STATEFUL_DOMAINS=localhost,localhost:4000,127.0.0.1,127.0.0.1:4000,yourdomain.com,www.yourdomain.comInclude:
- Host only (no scheme)
- Host:port for dev servers
Sanctum treats requests from these domains as “first-party” for session authentication.
Same-site deployment tips
| Setup | Cookie notes |
|---|---|
API api.domain.com + app domain.com | May need SESSION_DOMAIN=.domain.com |
Same origin /api reverse proxy | Simplest cookie behavior |
| Different domains entirely | Strict CORS + correct SANCTUM_STATEFUL_DOMAINS |
Admin API middleware
Admin routes use:
text
middleware: auth:sanctum, admin, lastSeenThe admin middleware checks that the logged-in user has role = admin (works with Sanctum cookie sessions).
If admin requests return 401/403, see Troubleshooting.
HTTPS requirement
Production must use HTTPS on both frontend and API so browsers accept Secure cookies.
Quick test
bash
# CSRF cookie (note -c jar for cookies)
curl -c cookies.txt -b cookies.txt \
https://api.yourdomain.com/sanctum/csrf-cookie
# Login (replace token from XSRF-TOKEN cookie)
curl -c cookies.txt -b cookies.txt \
-H "X-XSRF-TOKEN: YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"email":"admin@example.com","password":"secret"}' \
https://api.yourdomain.com/api/auth/signinBrowser-based login via the UI is the recommended test.