Laravel-datatables: 401 Unauthorized

Created on 3 Sep 2015  ·  15Comments  ·  Source: yajra/laravel-datatables

I updated today to 5.11.7 version and I am having some randomly unauthorized error from the ajax when I enter to the page where I have Datatables component.
My code is like this

    public function anyData()
    {
      $Patient = Patient::select('*')->withTrashed();
      return \Datatables::of($Patient)->make(true);
    }

and the datatable declaration is

$(document).ready(function() {
    $('#dataTables-patients').DataTable({
      responsive: true,
      processing: true,
      serverSide: true,
      ajax: base_url+'/patient/data',
      language:{
        url:base_url+'/js/dataTables.Spanish.json'
      },
      columns:[
        {data:'dni', name:'dni'},
        {data:'first_name', name:'first_name'},
        {data:'last_name', name:'last_name'},
        {data:'birthday', name:'birthday'},
        {data:'id', name:'id'},
        {data:'active', name:'active'},
      ],
      "columnDefs": [{
        "targets": 4,
        "data": "id",
        "render": function ( data, type, row ) {
          if(row.active=="0"){
            return '<a class="btn btn-primary" href="'+base_url+'/patient/show/'+data+'">'+patient.view+'</a>'+
                   '<a class="btn btn-success respatient" data-id="'+data+'" href="#" >'+patient.restore+'</a>';
          }else{
            return '<a class="btn btn-primary" href="'+base_url+'/patient/show/'+data+'">'+patient.view+'</a>'+
                   '<a class="btn btn-danger delpatient" data-id="'+data+'" href="#" >'+patient.delete+'</a>';
          }
        }

      },
      { "orderable": false, "targets": [ 4 ] },
      { "bSearchable": false, "aTargets": [ 5 ] },
      { "visible": false,  "targets": [ 5 ] }
      ]
    });

});

when Unauthorized explodes, I have to re login on the app. and it happens randomly: I can reload 6 times the page and happens nothing, and sometimes I enter two times and unauthorized happens.

Most helpful comment

Reading the comments,
I solved the problem well.
in the view
var token = '{{ csrf_token() }}';

ajax: { url:'$url', type:'post', data: { '_token': token } },

`var table = $('#myTable');

        oTable = table.dataTable({
            processing: true,
            serverSide: true,
            order: [[1, 'desc']],
            buttons: [
                { extend: 'print',  className: 'btn dark btn-outline'       },
                { extend: 'copy',   className: 'btn red btn-outline'        },
                { extend: 'pdf',    className: 'btn green btn-outline'      },
                { extend: 'excel',  className: 'btn yellow btn-outline'     },
                { extend: 'csv',    className: 'btn purple btn-outline'     },
                { extend: 'colvis', className: 'btn dark btn-outline', text: 'Columns'}
            ],
            ajax: {
                url:'$url',
                type:'post',
                data: {
                    '_token': token
                }
            },
            $col,
            \"oLanguage\": {
                \"sEmptyTable\":   \"No se encontraron resultados\",
                \"sInfo\":         \"Mostrando _START_ a _END_ de _TOTAL_ filas\",
                \"sInfoEmpty\":    \"No se encontraron resultados\",
                \"sInfoFiltered\": \"(Filtrado de _MAX_ total de filas)\",
                \"sLengthMenu\":   \"Ver _MENU_ filas\",
                \"sSearch\":       \"Buscar:\",
                \"sZeroRecords\":  \"No se encontraron resultados\"
            },
            \"aoColumnDefs\": [
                { \"bSortable\": false, \"aTargets\": [ 0,-1 ] }

,
{ \"iDataSort\": 1, \"aTargets\": [ 0 ] },

                { \"sWidth\": \"20px\",   \"aTargets\": [ 0,-1 ]  },


            ]
        });


        table.on(\"keyup\", \"input[type=search]\", function () {
            /* Filter on the column (the index) of this element */
            oTable.fnFilter(this.value, $(\"thead input\").index(this));
        });

        $('#sample_1_tools > li > a.tool-action').on('click', function() {
            var action = $(this).attr('data-action');
            //console.log(action);
            oTable.DataTable().button(action).trigger();
        });

`

All 15 comments

@mantrax314, this is one ghost bug that is really hard to debug. Several users already reported the same issue and can't find anything causing this. I can't even reproduce the same error on my local machine. It would be great and appreciated if you could help and provide a PR if possible to fix this issue once and for all. Thanks!

Hello,
I've encountered this issue and tried to debug for hours but to no avail.
It seems that one workaround is to set your ajax as a POST request instead of GET
This worked for me and i tested by refreshing my page 50 times without getting kicked out to the login page

The workaround is based on this issue
https://github.com/yajra/laravel-datatables/issues/19

Same with @Xyten I solved this by using POST request but I get error with CSRF token when using POST.. any suggestion for that? thanks btw.

@mrofi, follow the docs for token issue. http://laravel.com/docs/5.1/routing#csrf-x-csrf-token

I just read issue https://github.com/Chumper/Datatable/issues/170 on Chumper Datatable and might be applicable to us.

mgsmus commented on Sep 16, 2014
I've had this problem. I was using PHP's built in web server via "artisan serve". I switched to Apache and the problem is solved. I guess the reason is multi-threading that built-in server doesn't support.

Does any of you guys using "artisan serve"?

I am using "artisan serve". Well note. Using built in server is easy enough but it can't represent the real environment, I will consider to use Apache instead after this..

Thanks, @yajra . btw I solved the csrf token problem by your suggestion. I missed that documentation from Laravel. Where I can find the way to change ajax request type in html builder?

@mrofi, thanks for confirming. This issue maybe really due to "artisan serve".

For ajax, you can send an array parameter to it like below.

->ajax([
  'url' => 'url',
  'type' => 'post'
])

Several users confirmed that issue was due to "artisan serve". Using apache/nginx will fix the issue. Thanks!

I'm using apache on a Fedora machine, using locally via the hosts file and i'm having this exact same issue. Any ideas?

I solved this little problem as follows
replaces: ajax: 'resource',

by:
ajax: {
url: 'resource',
headers: {'X-CSRF-TOKEN': token},
dataType: 'JSON',
beforeSend: function (xhr) {
xhr.setRequestHeader('Authorization');
}
},

Some tips
1) Ajax maybe call doing POST or GET so you need configure your route in ANY
```
Route::any('campos/data','CamposController@data')->name('campos.data');

2) Dont forget add the token before the ajax calling (in my case is Laravel)

$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': '{{csrf_token()}}'
}
});

3) I have that issue in using php artisan on Windows. If you use on Linux or Apache you wont have errors. 
4) Error 401 is becouse the session was expired. You need a login again. You could handler the error and take some action

"ajax": "/resource",
"error": function(reason) {
console.log("error encountered ! ");
// process reason here to know the type of the error
// and then take appropriate action
}
```

Reading the comments,
I solved the problem well.
in the view
var token = '{{ csrf_token() }}';

ajax: { url:'$url', type:'post', data: { '_token': token } },

`var table = $('#myTable');

        oTable = table.dataTable({
            processing: true,
            serverSide: true,
            order: [[1, 'desc']],
            buttons: [
                { extend: 'print',  className: 'btn dark btn-outline'       },
                { extend: 'copy',   className: 'btn red btn-outline'        },
                { extend: 'pdf',    className: 'btn green btn-outline'      },
                { extend: 'excel',  className: 'btn yellow btn-outline'     },
                { extend: 'csv',    className: 'btn purple btn-outline'     },
                { extend: 'colvis', className: 'btn dark btn-outline', text: 'Columns'}
            ],
            ajax: {
                url:'$url',
                type:'post',
                data: {
                    '_token': token
                }
            },
            $col,
            \"oLanguage\": {
                \"sEmptyTable\":   \"No se encontraron resultados\",
                \"sInfo\":         \"Mostrando _START_ a _END_ de _TOTAL_ filas\",
                \"sInfoEmpty\":    \"No se encontraron resultados\",
                \"sInfoFiltered\": \"(Filtrado de _MAX_ total de filas)\",
                \"sLengthMenu\":   \"Ver _MENU_ filas\",
                \"sSearch\":       \"Buscar:\",
                \"sZeroRecords\":  \"No se encontraron resultados\"
            },
            \"aoColumnDefs\": [
                { \"bSortable\": false, \"aTargets\": [ 0,-1 ] }

,
{ \"iDataSort\": 1, \"aTargets\": [ 0 ] },

                { \"sWidth\": \"20px\",   \"aTargets\": [ 0,-1 ]  },


            ]
        });


        table.on(\"keyup\", \"input[type=search]\", function () {
            /* Filter on the column (the index) of this element */
            oTable.fnFilter(this.value, $(\"thead input\").index(this));
        });

        $('#sample_1_tools > li > a.tool-action').on('click', function() {
            var action = $(this).attr('data-action');
            //console.log(action);
            oTable.DataTable().button(action).trigger();
        });

`

@jarm-mcs thanks for the solution, it work :)

Hi, I had this problem too and I solved it using axios headers on the Ajax configuration. I'm using Laravel Passport, I don't know if it's related, because with a simple axios call it works

my bootstrap.js

window.axios = require('axios');

window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';

/**
 * Next we will register the CSRF Token as a common header with Axios so that
 * all outgoing HTTP requests automatically have it attached. This is just
 * a simple convenience so we don't have to attach every token manually.
 */

let token = document.head.querySelector('meta[name="csrf-token"]');

if (token) {
    window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
} else {
    console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
}

my DataTables script

$(function() {
            $('#users-table').DataTable({
                processing: true,
                serverSide: true,
                ajax: {
                    'url':'{!! route('api.games.index') !!}',
                    'headers':window.axios.defaults.headers.common
                },
                columns: [
                    { data: 'id', name: 'id' },
                    { data: 'name', name: 'name' },
                    { data: 'created_at', name: 'created_at' },
                    { data: 'updated_at', name: 'updated_at' }
                ]
            });
        });

Reading the comments,
I solved the problem well.
in the view
var token = '{{ csrf_token() }}';

ajax: { url:'$url', type:'post', data: { '_token': token } },

`var table = $('#myTable');

        oTable = table.dataTable({
            processing: true,
            serverSide: true,
            order: [[1, 'desc']],
            buttons: [
              { extend: 'print',  className: 'btn dark btn-outline'       },
              { extend: 'copy',   className: 'btn red btn-outline'        },
              { extend: 'pdf',    className: 'btn green btn-outline'      },
              { extend: 'excel',  className: 'btn yellow btn-outline'     },
              { extend: 'csv',    className: 'btn purple btn-outline'     },
              { extend: 'colvis', className: 'btn dark btn-outline', text: 'Columns'}
          ],
            ajax: {
                url:'$url',
                type:'post',
                data: {
                    '_token': token
                }
            },
            $col,
            \"oLanguage\": {
              \"sEmptyTable\":   \"No se encontraron resultados\",
              \"sInfo\":         \"Mostrando _START_ a _END_ de _TOTAL_ filas\",
              \"sInfoEmpty\":    \"No se encontraron resultados\",
              \"sInfoFiltered\": \"(Filtrado de _MAX_ total de filas)\",
              \"sLengthMenu\":   \"Ver _MENU_ filas\",
              \"sSearch\":       \"Buscar:\",
              \"sZeroRecords\":  \"No se encontraron resultados\"
          },
          \"aoColumnDefs\": [
              { \"bSortable\": false, \"aTargets\": [ 0,-1 ] }

,
{ "iDataSort": 1, "aTargets": [ 0 ] },

              { \"sWidth\": \"20px\",   \"aTargets\": [ 0,-1 ]  },


            ]
        });


        table.on(\"keyup\", \"input[type=search]\", function () {
          /* Filter on the column (the index) of this element */
          oTable.fnFilter(this.value, $(\"thead input\").index(this));
      });

        $('#sample_1_tools > li > a.tool-action').on('click', function() {
            var action = $(this).attr('data-action');
            //console.log(action);
            oTable.DataTable().button(action).trigger();
        });

`

thx for the solution.

Was this page helpful?
0 / 5 - 0 ratings