Laravel 12 CORS Middleware Configuration Example

In this laravel tutorial titled “Laravel 12 CORS Middleware Configuration Example”, you will learn how to configure CORS Middleware in laravel 12 application step by step.

When building APIs or frontend–backend integrated applications, you often need to allow cross-origin requests. This is where CORS (Cross-Origin Resource Sharing) comes in. In Laravel 12, configuring CORS is simple and efficient using built-in middleware.

In this laravel 12 tutorial, we’ll walk through how to set up and configure CORS in Laravel 12, customize allowed origins, methods, headers, and how to apply CORS middleware globally or to specific routes.

What is CORS ?

CORS (Cross-Origin Resource Sharing) is a security mechanism implemented by browsers to allow or block requests coming from different domains.

An “origin” means the protocol (http/https), domain, and port number.

Example of different origins:

  • http://localhost:8000 Laravel backend
  • http://localhost:5173 Vue/React frontend
  • https://api.example.com and https://example.com different origins

Normally, browsers block requests between different origins to keep users safe.

CORS allows the server to say: “Yes, this other website is allowed to access my data.

When You Need CORS

You need CORS when:

  • Your frontend (React, Vue, Angular) runs on a different port/domain than your Laravel API
  • You have multiple services (microservices) talking to each other
  • A mobile app calls your Laravel API
  • You want third-party apps or developers to use your API

Read Also : Laravel 12 RouteServiceProvider Configuration Tutorial

How CORS Works in Laravel

When a browser sends a request to another origin, it works in two ways:

Simple Requests

  • Basic GET, POST, or HEAD requests.
  • The browser sends the request with an Origin header, and Laravel replies with the correct CORS headers.

Preflight Requests

  • Used for complex requests (PUT, DELETE, custom headers, JSON, etc.).
  • Before sending the real request, the browser sends an OPTIONS request to ask the server for permission.
  • This is called a preflight request.

Laravel handles both types automatically using the HandleCors middleware.

Laravel 12 Built-in CORS Support

Laravel 12 comes with built-in CORS support—no extra packages are needed. The HandleCors middleware is already included and active in every project.

Step 1: Publish the CORS Configuration File

To customize CORS settings, first publish the configuration file using the Artisan command:

php artisan config:publish cors

This creates a new file at config/cors.php containing all available CORS options.

Step 2: Understanding Configuration Options

Open config/cors.php and you’ll see the default configuration:

Let’s examine each option in detail:

<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Cross-Origin Resource Sharing (CORS) Configuration
    |--------------------------------------------------------------------------
    |
    | Here you may configure your settings for cross-origin resource sharing
    | or "CORS". This determines what cross-origin operations may execute
    | in web browsers. You are free to adjust these settings as needed.
    |
    | To learn more: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
    |
    */

    'paths' => ['api/*', 'sanctum/csrf-cookie'],

    'allowed_methods' => ['*'],

    'allowed_origins' => ['*'],

    'allowed_origins_patterns' => [],

    'allowed_headers' => ['*'],

    'exposed_headers' => [],

    'max_age' => 0,

    'supports_credentials' => false,

];

Let’s examine each option in detail:

paths

Specifies which routes should have CORS enabled. The default [‘api/’, ‘sanctum/csrf-cookie’] applies CORS to all API routes and Laravel Sanctum’s CSRF cookie endpoint. Use [‘*’] to enable CORS for all routes.

'paths' => ['api/*', 'sanctum/csrf-cookie'],
// Or enable for all routes:
'paths' => ['*'],
// Or specify exact paths:
'paths' => ['api/users', 'api/products/*', 'webhooks/*'],

allowed_methods

Defines which HTTP methods are permitted in cross-origin requests. The wildcard [‘*’] allows all methods (GET, POST, PUT, DELETE, PATCH, OPTIONS).

'allowed_methods' => ['*'],
// Or restrict to specific methods:
'allowed_methods' => ['GET', 'POST', 'PUT', 'DELETE'],

allowed_origins

Specifies which domains are allowed to make cross-origin requests. The wildcard ‘*’ allows all origins, but this should never be used in production with credentials.​

// Development - Allow all (not recommended for production):
'allowed_origins' => ['*'],

// Production - Specify exact origins:
'allowed_origins' => [
    'https://example.com',
    'https://app.example.com',
    'http://localhost:5173', // For local development
],

allowed_headers

Defines which HTTP headers can be used in the actual request. The wildcard [‘*’] allows all headers.

'allowed_headers' => ['*'],
// Or specify exact headers:
'allowed_headers' => ['Content-Type', 'Authorization', 'X-Requested-With', 'Accept'],

supports_credentials

Determines whether cookies, authorization headers, or TLS client certificates can be included in cross-origin requests. Set to true when using session-based authentication or cookies.

'supports_credentials' => true,

Important: When supports_credentials is true, you cannot use wildcards (‘*’) in allowed_origins. You must specify exact origins.

allowed_origins_patterns

Use regular expressions to match multiple origins dynamically. For e.g.

'allowed_origins_patterns' => [
    '/^https?:\/\/(.*\.)?example\.com$/', // Matches all subdomains of example.com
    '/^http:\/\/localhost:\d+$/', // Matches localhost with any port
],

exposed_headers

Lists response headers that should be accessible to the client-side JavaScript code.

'exposed_headers' => ['X-Custom-Header', 'X-Total-Count'],

max_age

Specifies how long (in seconds) the browser can cache the preflight response. This reduces the number of preflight requests for repeated API calls.

'max_age' => 3600, // Cache for 1 hour
'max_age' => 86400, // Cache for 24 hours

Conclusion

Configuring CORS in Laravel 12 is simple thanks to the built-in middleware and cors.php configuration file. Whether you’re working on a SPA, mobile app, or external API integration, setting proper CORS rules ensures secure and smooth communication between your frontend and backend.

By following this step-by-step guide, you can:

  • Enable CORS globally
  • Restrict or allow specific domains
  • Apply CORS to individual routes
  • Customize allowed methods, headers, and credentials

Frequently Asked Questions

Q1: Do I need to install a package for CORS in Laravel 12?

No, Laravel 12 has built-in CORS support through the HandleCors middleware. You only need to publish and configure config/cors.php.

Q2: Why does my API work in Postman but not in the browser?

Postman doesn’t enforce CORS restrictions like browsers do. CORS is a browser-security feature. Test with actual browser requests to verify CORS configuration.

Q3: Can I use wildcards for allowed origins in production?

While technically possible, using ‘*’ for allowed origins is highly discouraged in production, especially with supports_credentials: true, as it creates security vulnerabilities.

Q4: What’s the difference between allowed_origins and allowed_origins_patterns? q

allowed_origins lists exact domain strings, while allowed_origins_patterns uses regular expressions to match multiple origins dynamically, useful for subdomains.

Q5: How do I fix “Response to preflight request doesn’t pass access control check”?

Ensure OPTIONS is in allowed_methodsHandleCors middleware is registered and runs early (use prepend), and your CORS configuration matches the request origin.

Q6: Should I configure CORS in Laravel or in Nginx/Apache?

Choose one location to avoid conflicts. Laravel’s CORS configuration is more flexible and easier to maintain, making it the recommended choice.