I'm having trouble with an AJAX POST request in Laravel 5.2. I'm passing a valid CSRF token in my AJAX request.

Opening and closing the form using Laravel Collective HTML package form tags, which automatically adds a hidden _token input with the CSRF token. Rendered HTML:

<form method="POST" action="http://www.example.com/admin/products/search" accept-charset="UTF-8" id="product-search-form"> <input name="_token" type="hidden" value="mOaBxU1sVUsRX1KkuAeVhSDSxj0LKT8DDxl9USQc"> <div> <label for="keywords" class="required">Keywords</label> <input id="keywords" placeholder="Enter keywords" name="keywords" type="text"> </div> <div> <label for="category" class="required">Category</label> <select id="category" name="category"> <option selected="selected" value="">Choose a category...</option> <option value="category-1">Category 1</option> <option value="category-2">Category 2</option> <option value="category-3">Category 3</option> </select> </div> <div> <button id="search-product-submit" type="submit">Search</button> </div> </form>

Using Fetch API and FormData to do AJAX request:

function $(id) { return document.getElementById(id); } var searchProductSubmitButton = $("search-product-submit"); function fetchStatus(response) { if (response.status >= 200 && response.status < 300) { return Promise.resolve(response); } else { return Promise.reject(new Error(response.statusText)); } } function fetchJson(response) { return response.json(); } function searchProducts(evt){ var keywords = $("keywords").value, categorySelect = $("category"), category = categorySelect.options[categorySelect.selectedIndex].value, csrfToken = document.getElementsByTagName("meta")["csrf-token"].getAttribute("content"), productSearchForm = $("product-search-form"), formData = new FormData(productSearchForm); evt.preventDefault(); if(keywords !== "" && category !== ""){ fetch("/admin/products/search", { method: "POST", body: formData, headers: { "X-CSRF-TOKEN": csrfToken } }) .then(fetchStatus) .then(fetchJson) .then(function(products) { console.log("The operation was a complete success"); }).catch(function(error) { console.log("Request failed", error); }); } } searchProductSubmitButton.addEventListener("click", searchProducts, false); searchProductSubmitButton.addEventListener("keypress", searchProducts, false);

The CSRF token and form data are in the request payload:

------WebKitFormBoundaryQFECPn7xpptqi076 Content-Disposition: form-data; name="_token" mOaBxU1sVUsRX1KkuAeVhSDSxj0LKT8DDxl9USQc ------WebKitFormBoundaryQFECPn7xpptqi076 Content-Disposition: form-data; name="keywords" dsafafa ------WebKitFormBoundaryQFECPn7xpptqi076 Content-Disposition: form-data; name="category" DVD ------WebKitFormBoundaryQFECPn7xpptqi076--

The _token input in the request payload and the x-csrf-token header are the same as the token seen in View Source.

Route is using web middleware:

Route::group(['prefix' => 'admin', 'middleware' => 'web'], function () { Route::post('products/search', [ // == "admin/products/search" with prefix 'as' => 'products.search', 'uses' => 'ProductsController@search' ]); });

Controller: