disable csrf in laravel for specific route

PhpLaravelLaravel 5Laravel 5.1

Php Problem Overview


I've a payment system, where data is submitted to 3rd party site and than hauled back...

When data returns it hits specific url lets say /ok route. $_REQUEST['transaction'].

But because of laravel middleware I'm getting token mismatch. There is no way 3rd party payment API can generate token, so how I disable it? only for this route?

or is there a better option?

Route::get('/payment/ok',   'TransactionsController@Ok');
Route::get('/payment/fail', 'TransactionsController@Fail');

public function Ok( Request $request )
{
    $transId = $request->get('trans_id');

    if ( isset( $transId ) )
    {
       
		return $transId;
        
    }

}

Php Solutions


Solution 1 - Php

Since version 5.1 Laravel's VerifyCsrfToken middleware allows to specify routes, that are excluded from CSRF validation. In order to achieve that, you need to add the routes to $except array in your App\Http\Middleware\VerifyCsrfToken.php class:

<?php namespace App\Http\Middleware;

use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;

class VerifyCsrfToken extends BaseVerifier
{
  protected $except = [
    'payment/*',
  ];
}

See the docs for more information.

Solution 2 - Php

Since Laravel 7.7 you can use method withoutMiddleware eg:

Route::get('/payment/ok',   'TransactionsController@Ok')
    ->withoutMiddleware([\App\Http\Middleware\VerifyCsrfToken::class]);

Route::get('/payment/fail', 'TransactionsController@Fail')
    ->withoutMiddleware([\App\Http\Middleware\VerifyCsrfToken::class]);

Solution 3 - Php

The technique described by @jedrzej.kurylo works well for excluding one or two pages.

Here's a different technique if you need to exclude lots of pages from CSRF validation, with more future-proofing.

You can segment your routes, and apply different middleware to each. So you can put your payment routes into a separate route groups, and not apply VerifyCsrfToken to them. Here's how.

1. Create a routes file

You'll notice in your routes directory, you have the following tree:

  • routes/
  • routes/api.php
  • routes/web.php

Create a new file here, routes/payment.php, and add your routes above to it:

<?php
use Illuminate\Support\Facades\Route;

Route::get('/payment/ok',   'TransactionsController@Ok');
Route::get('/payment/fail', 'TransactionsController@Fail');

2. Process the route with the RouteServiceProvider

In Laravel, Routes are processed by app\Providers\RouteServiceProvider.php. You'll notice these functions: map() and mapWebRoutes(). Add to this file accordingly (I've excluded the stock comments for brevity).

    public function map()
    {
        $this->mapApiRoutes();
        $this->mapWebRoutes();
        $this->mapPaymentRoutes(); // <---- add this line
    }

    protected function mapWebRoutes()
    {
        Route::middleware('web')
             ->namespace($this->namespace)
             ->group(base_path('routes/web.php'));
    }

    protected function mapPaymentRoutes()  // <--- Add this method
    {
        Route::middleware('payment')       // <--- this line is important
             ->namespace($this->namespace)
             ->group(base_path('routes/payment.php'));
    }

Notice we've added a new middleware layer. This is important for the next step.

3. Add a new middleware layer

Your middleware for your route groups are defined in App\Http\Kernel.php.

Update the $middlewareGroups property, and add a middle entry for 'payment'. It can be exactly the same as web, but without the VerifyCsrfToken line.

    protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            \Illuminate\Session\Middleware\AuthenticateSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
            \App\Http\Middleware\NoClickjack::class,
            \App\Http\Middleware\SecureReferrerPolicy::class,
            \App\Http\Middleware\NoXssScripting::class,
        ],

        // ********** Add this *******************
        'payment' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            \Illuminate\Session\Middleware\AuthenticateSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,

// This is the line you want to comment-out / remove
//            \App\Http\Middleware\VerifyCsrfToken::class,     

            \Illuminate\Routing\Middleware\SubstituteBindings::class,
            \App\Http\Middleware\NoClickjack::class,
            \App\Http\Middleware\SecureReferrerPolicy::class,
            \App\Http\Middleware\NoXssScripting::class,
        ],

        'api' => [
            'throttle:60,1',
            'bindings',
        ],
    ];

ļŽ‰

Now whenever you add new routes that need to be excluded from the CSRF Token check, add them to the routes/payment.php file.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser796443View Question on Stackoverflow
Solution 1 - Phpjedrzej.kuryloView Answer on Stackoverflow
Solution 2 - PhpGetoXView Answer on Stackoverflow
Solution 3 - PhphazView Answer on Stackoverflow