To configure CORS in Laravel 13, publish the config file with php artisan config:publish cors, then set paths, allowed_origins, allowed_methods and allowed_headers in config/cors.php. Laravel's built-in CORS middleware reads that file and answers preflight OPTIONS requests for you.

What is CORS and when do you need it?

Browsers block JavaScript on one origin (scheme, host and port) from reading responses from another origin unless the server allows it with CORS headers. You need to configure it when a separate frontend, for example a React app on http://localhost:5173, calls your Laravel API on http://localhost:8000.

What do you need before you start?

  • Laravel 13 on PHP 8.3 or newer
  • A frontend on a different origin that calls your API

How do you publish the CORS config?

The file is not published by default. Laravel uses sensible built-in defaults until you publish it.

php artisan config:publish cors 

How do you set allowed origins?

<?php // config/cors.php return [ 'paths' => ['api/*', 'sanctum/csrf-cookie'], 'allowed_methods' => ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'], 'allowed_origins' => [ env('FRONTEND_URL', 'http://localhost:5173'), ], 'allowed_origins_patterns' => [], 'allowed_headers' => ['Content-Type', 'Authorization', 'Accept', 'X-Requested-With'], 'exposed_headers' => [], 'max_age' => 600, 'supports_credentials' => false, ]; 

Only paths matching paths get CORS headers. List every origin you trust. Avoid * on authenticated APIs.

# .env FRONTEND_URL=https://app.example.com 

How do you allow cookies or credentials?

For cookie-based SPA authentication, such as Sanctum SPA mode, the response must include Access-Control-Allow-Credentials: true. Set supports_credentials to true. With credentials, the browser rejects a wildcard origin, so use explicit origins.

'supports_credentials' => true, 

On the frontend, enable credentials in your HTTP client, for example axios.defaults.withCredentials = true.

How does the middleware work?

Laravel registers its CORS handling in the global middleware stack, so you do not add it to routes. After editing the config, clear the cached config if you ever ran config:cache.

php artisan config:clear 

How do you verify it works?

Send a preflight request with curl and look at the response headers.

curl -i -X OPTIONS http://localhost:8000/api/user \ -H "Origin: http://localhost:5173" \ -H "Access-Control-Request-Method: GET" \ -H "Access-Control-Request-Headers: Authorization" 

You should see Access-Control-Allow-Origin: http://localhost:5173 and the allowed methods. Then repeat with a disallowed origin and confirm the header is absent.

What are the common mistakes?

  • The route is not covered by paths
  • Using * together with supports_credentials
  • A trailing slash in the origin, such as http://localhost:5173/
  • Cached config hiding your changes
  • Debugging a 500 error as if it were CORS. When an error response lacks CORS headers the browser reports a CORS failure, so check the Laravel log first

FAQ

Do I need a CORS package in Laravel 13?

No. Handling is built into the framework and configured with config/cors.php.

Why does the browser say CORS but curl works?

CORS is enforced by browsers only. curl ignores it, so test with the Origin header as shown above.

Can I use a pattern for many subdomains?

Yes. Use allowed_origins_patterns with a regular expression such as #^https://.*\.example\.com$#.

References

Originally published on yasiramin.dev.