Pathros
Pathros

Reputation: 10720

Failed CSRF check! in postman when trying POST method (API with slim 3)

I am working with a Slim 3 project and I installed the CSRF package ("slim/csrf": "^0.8.2",)

In order to make POSTs request I am using postman. When sending the action I get the following error:

Failed CSRF check!

Here are my API routes (in this case, focus on the POST route):

<?php

/* RESTful endpoints or routes */

use App\Controllers\api\users\UserController;

    $app->group('/api',function () use ($app){
        $app->group('/users', function () {
            $this->get('', UserController::class.':index');
            $this->get('/{id}', UserController::class.':show');
            $this->post('', UserController::class.':store');
        });
    });

Here is the controller supposed to get the info from the POST request where I get the error:

//Save a user via API
    public function store($request,$response,$args)
    {
        //todo: validation!
        var_dump($request->getParams());//todo: CSRF check failed!
        die();
    }

Here is where I registered the CSRF component:

//Register the CSRF Component
$container['csrf'] = function ($container){
    return new \Slim\Csrf\Guard();
};

I tried this solution: https://stackoverflow.com/a/48266488/1883256 but it didn't work.

Is there any workaround to make it work? How do I prevent the CSRF to run on my API routes?

* Solved *

As Zamrony P. Juhara suggested, I decided to apply CSRF to the web routes except for the APIs routes.

Grouping all my web routes:

    $app->group('',function ()use($app,$container){
        /* ******* H O M E ********** */
        require __DIR__ . '/web/home/home.php';
        /* ********** T O P I C  s ********** */
        require __DIR__ . '/web/topics/topics.php';

        /* ********** C O N T A C T *********** */
        require __DIR__ . '/web/contact/contact.php';

/* And so on and etcetera ....*/
        /* ********************************************************************************* */
    })->add($container->get('csrf'));//Adding CSRF protection only for web routes

And, for example, inside the topics.php routes file I have:

$app->group('/topics',function(){
    $this->get('',TopicController::class.':index');
    $this->get('/{id}',TopicController::class.':show')->setName('topics.show');
});

And as for the API routes, they stay the same.

Finally, inside my container I commented the following:

//$app->add($container->get('csrf')); //I've commented this line in order to add CSRF for specific routes (all except APIs ones)

Upvotes: 0

Views: 1712

Answers (1)

Zamrony P. Juhara
Zamrony P. Juhara

Reputation: 5262

You need to make sure that you add Slim\Csrf\Guard middleware to route or application (if you want to apply csrf for all routes). For example

To apply csrf middleware to all routes

$csrf = $container->csrf;
$app->add($csrf);

or to apply for certain routes only

$csrf = $container->csrf;
$app->group('/api',function () use ($app, $csrf){
    $app->group('/users', function () {
        $this->get('', UserController::class.':index')
             ->add($csrf);
        $this->get('/{id}', UserController::class.':show');
        $this->post('', UserController::class.':store')
             ->add($csrf);
    });
});

You also need to make sure that there are Csrf token name/value data passed with request. When you use Postman, you need to find a way to obtain token name key/value pair before execute POST.

Following code is excerpt from Slim Csrf Readme.

// CSRF token name and value
$nameKey = $this->csrf->getTokenNameKey();
$valueKey = $this->csrf->getTokenValueKey();
$name = $request->getAttribute($nameKey);
$value = $request->getAttribute($valueKey);

// Render HTML form which POSTs to /bar with two hidden input fields for the
// name and value:
// <input type="hidden" name="<?= $nameKey ?>" value="<?= $name ?>">
// <input type="hidden" name="<?= $valueKey ?>" value="<?= $value ?>">

Read Slim Csrf Readme for more information.

Upvotes: 1

Related Questions