Ashkru
Ashkru

Reputation: 1635

Sending Ajax requests with Laravel

I am trying to learn how I can pass a csrf token (I am using Laravel) with an ajax request as my ajax url returns 500 because it hasn't been given the csrf token.

Is it less secure to use a get request? can people spoof the requests from an external site? I'm just looking for the best way to do this without any security holes really.

Here is my ajax code:

saveHousekeepingNotes();

function saveHousekeepingNotes() {
    $.ajax({
        url: "/ajax/save-notes",
        type: "POST",
        data: 'Here we have some data.',
        beforeSend: function(xhr) {
            $('.notes-status-holder').html('Saving...');
        },
        success: function(data) {
            var jqObj = jQuery(data);
            var d = new Date();
            $('.notes-status-holder').html('autosaved ' + d.toLocaleTimeString());

            setInterval(function() {
                saveHousekeepingNotes();
            }, 5 * 1000);
        },
    });
}

In my blade file:

<script>$.ajaxSetup({ headers: { 'csrftoken' : '{{ csrf_token() }}' } });</script>

In my routes:

Route::group(['middleware' => 'ajax', 'prefix' => 'ajax'], function() {
            Route::any('/save-notes', 'AjaxController@saveNotes');
        });

In my ajax controller:

<?php

namespace App\Http\Controllers\Admin\Admin;

use Illuminate\Http\Request;
use Cache;
use Auth;
use App\Database\Website\User\Roleplay;

class AjaxController
{
    public function saveNotes()
    {
        if (!Auth::guest()) {
            $roleplay = Roleplay::where('user_id', Auth::user()->id)->first();
            $roleplay->housekeeping_notes = 'We saved it:) ' . rand(10,40);
            $roleplay->save();
        }
    }
}

My ajax middleware just checks if $request->ajax() to verify its a ajax call. So what I am basically asking is how can I pass the csrf token securely? Does Laravel handle that? or is there a better way of doing this..

Upvotes: 1

Views: 2825

Answers (3)

Shady Keshk
Shady Keshk

Reputation: 570

If you want to pass the csrf the way you are currently doing you have to tell htaccess to pass this header to your script and also modify it's name

<IfModule mod_rewrite.c>
<IfModule mod_negotiation.c>
    Options -MultiViews
</IfModule>

RewriteEngine On

# Handle Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]


# Handle custom csrf Header
    RewriteCond %{HTTP:csrftoken} .
    RewriteRule .* - [E=X-XSRF-TOKEN:%{HTTP:csrftoken}]
</IfModule>

Put remember @AfikDeri solution is more portable.and cleaner

Upvotes: 0

Advaith
Advaith

Reputation: 2580

Just use this.

_token: '{{ csrf_token() }}'

It is because ajax request is also sending the name of the field.
Normally if you create a csrf_field, you can find it with a name _token, just use that here.

$.ajax({
    url: "/ajax/save-notes",
    type: "POST",
    data: {
        _token: '{{ csrf_token() }}',
        // rest data here
    },
    beforeSend: function(xhr) {
        $('.notes-status-holder').html('Saving...');
    },
    success: function(data) {
        var jqObj = jQuery(data);
        var d = new Date();
        $('.notes-status-holder').html('autosaved ' + d.toLocaleTimeString());

        setInterval(function() {
            saveHousekeepingNotes();
        }, 5 * 1000);
    },
});

Upvotes: 1

AfikDeri
AfikDeri

Reputation: 2109

well, according to Laravel Docs you better store your csrf token in a meta tag, like so:

<meta name="csrf-token" content="{{ csrf_token() }}">

Then inside your main javascript file include this header with every request (please note that the header name you provided was wrong):

$.ajaxSetup({
    headers: {
        'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
    }
});

Then it should work :)

Upvotes: 2

Related Questions