Back to Blog
Lesson 57 of the Intermediate Laravel: Real-World Application Patterns course
LaravelJune 27, 20263 min read

Secure API Design: Hardening Laravel Against Web Vulnerabilities

Learn to secure your Laravel API by mastering CORS, implementing CSRF protection for SPAs, and managing sensitive headers to prevent common web attacks.

Laravelsecurityapicorsauthenticationphpbackend

Previously in this course, we explored rate limiting API endpoints to protect our infrastructure from abuse. In this lesson, we shift our focus to the request lifecycle itself, ensuring that the communication between your client-side application and your Laravel API remains locked down.

Building a secure API isn't just about authentication; it’s about controlling how and from where your application is accessed.

Understanding CORS in a Modern API

Cross-Origin Resource Sharing (CORS) is a browser-level security feature. By default, browsers restrict cross-origin HTTP requests initiated from scripts. If your frontend lives on app.example.com and your API on api.example.com, the browser will block requests unless your API explicitly permits them.

Configuring CORS Correctly

In Laravel, CORS is handled via the config/cors.php file. A common pitfall is setting allowed_origins to ['*']. This effectively disables CORS protection, allowing any malicious site to make requests to your API on behalf of your users.

Instead, define your specific production domains:

PHP
#6A9955">// config/cors.php
'allowed_origins' => ['https:#6A9955">//app.example.com'],

'allowed_headers' => ['Content-Type', 'X-Requested-With', 'Authorization', 'X-XSRF-TOKEN'],

'supports_credentials' => true,

If you're building a Single Page Application (SPA) using Laravel Sanctum, supports_credentials must be true to allow the browser to send cookies (like your session cookie) across origins.

Implementing CSRF Protection for SPAs

Cross-Site Request Forgery (CSRF) tricks a user into submitting a request to a web application where they are currently authenticated. While APIs using stateless tokens (like Bearer tokens) are immune to CSRF, many Laravel SPAs use session-based authentication for convenience.

If you are using Sanctum's SPA authentication, you must implement CSRF protection. Laravel handles this via the EnsureFrontendRequestsAreStateful middleware.

The CSRF Workflow

  1. GET Request: The client makes a request to /sanctum/csrf-cookie.
  2. Cookie Issuance: Laravel sets an XSRF-TOKEN cookie.
  3. Client Header: The frontend reads this cookie and includes its value in the X-XSRF-TOKEN header of subsequent state-changing requests (POST, PUT, DELETE).
  4. Verification: Laravel’s VerifyCsrfToken middleware checks that the header matches the encrypted cookie.

If you fail to send the X-XSRF-TOKEN header on a POST request, Laravel will return a 419 Authentication Timeout error. This is your signal that the security layer is doing its job.

Handling Sensitive Data Headers

Beyond CORS and CSRF, you must control what information your API leaks. Sensitive data often finds its way into logs or response headers.

Stripping Unnecessary Headers

By default, some servers or frameworks add headers like X-Powered-By: PHP/8.x. This is "security through obscurity," but it reduces your attack surface. You can remove these in your AppServiceProvider or via your web server configuration (Nginx/Apache).

PHP
#6A9955">// app/Providers/AppServiceProvider.php
public function boot(): void
{
    $this->app['events']->listen(\Illuminate\Routing\Events\ResponseSending::class, function ($event) {
        $event->response->headers->remove('X-Powered-By');
    });
}

Security Headers

Ensure your API sends modern security headers. You can use a dedicated middleware to inject these into every response:

  • Strict-Transport-Security (HSTS): Forces browser to use HTTPS.
  • X-Content-Type-Options: Prevents MIME-sniffing.
  • Referrer-Policy: Controls how much referrer information is passed.

Hands-on Exercise

Your task is to harden the project board API:

  1. Update config/cors.php to restrict allowed_origins to your specific local development domain (e.g., http://localhost:3000).
  2. Ensure supports_credentials is set to true.
  3. In your frontend client, implement a request interceptor (using Axios or Fetch) that reads the XSRF-TOKEN cookie and attaches it to the X-XSRF-TOKEN header.

Common Pitfalls

  • Wildcard CORS: Using ['*'] in production is a major security risk. Always whitelist specific domains.
  • Ignoring 419 Errors: A 419 error is not a bug; it means your CSRF token is missing or expired. Do not disable CSRF protection just to make the error go away.
  • Insecure Cookies: Always ensure SESSION_SECURE_COOKIE is set to true in your .env file when running in production to ensure cookies are only transmitted over HTTPS.

Recap

Secure API design requires a multi-layered approach. We've ensured that only authorized origins can talk to our API via CORS, verified stateful requests using Sanctum's CSRF protection, and sanitized our response headers to limit information leakage. These steps, combined with API security: decoupling field-level authorization from controllers, provide a robust foundation for your project board.

Up next: We will dive into Event Sourcing Concepts to understand how to handle complex state changes in our application.

Similar Posts