TokenMismatchException during AJAX polling in Laravel - ajax

In my Laravel application, I have a notification system. This is run using AJAX polling techniques (i.e. a ajax post function is run every 5 seconds or so) similar to:
$.ajaxSetup({
headers: {
'X-CSRF-Token': CSRF_TOKEN
}
});
(function pollForNewNotifications() {
setTimeout(function () {
$.ajax({
type: 'POST',
url: 'http://example.com/get-notifications',
dataType: 'json',
data: {
// data that is sent
},
success: function (data) {
// add new notifications if data is not empty logic
pollForNewNotifications();
}
})
.fail(function (xhr, status, err) {
console.error(xhr.responseText)
});
}, 5000);
})();
Now this works most of the time.
However, the issue is that I sometimes find that over long period of inactivity I get a TokenMismatchException in VerifyCsrfToken.php error and automatically logged out.
I believe that this is the case because the CSRF token changes or longer is valid (I may be wrong).
How can I solve this issue?

Change the session's lifetime:
https://github.com/laravel/laravel/blob/a282304/config/session.php#L32

You can remove token check to this particular url so it can make request without checking csrf token. Go to app/Http/Middleware/VerifyCsrfToken.php
place this
protected $except = [
'get-notifications',
];

Related

Laravel Broadcast using pusher. ToOthers not working

$.ajaxSetup({
headers:{
'X-Socket-Id': Echo.socketId()
}
});
I also tried
var socket_id= Echo.socketId();
var CSRF_TOKEN = $('meta[name="csrf-token"]').attr('content');
$.ajax({
/* the route pointing to the post function */
url: '/event',
headers: { 'X-Socket-Id': socket_id }
type: 'POST',
/* send the csrf-token and the input to the controller */
data: {
_token: CSRF_TOKEN,
message: 'a message'
},
//dataType: 'JSON',
/* remind that 'data' is the response of the AjaxController */
success: function (data) {
$(".writeinfo").append(data.msg);
}
});
also laravel is supposed to add the x-socket-id header if im not mistaken without me doing it manually. according to this site
https://github.com/laravel/echo/blob/master/src/echo.ts
it contains this
registerjQueryAjaxSetup(): void {
if (typeof jQuery.ajax != 'undefined') {
jQuery.ajaxPrefilter((options, originalOptions, xhr) => {
if (this.socketId()) {
xhr.setRequestHeader('X-Socket-Id', this.socketId());
}
});
}
}
Also in my broadcast i made sure i used ->toOThers()
it works fine on vue its, in blade where it does not want to work, it sends to everyone on the channel. I was thinking its because im using ajax i needed to add a header with socket ID but no im not so sure.

Laravel ajax post not working even though CSRF token included

I am having difficulty getting an ajax post to work with laravel v5.5.24. Here is what my ajax call looks like:
var CSRF_TOKEN = $('meta[name="csrf-token"]').attr('content');
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
$.ajax({
url: "/postCustomer?XDEBUG_SESSION_START=19683",
type: 'POST',
data: {_token: CSRF_TOKEN, message:myData, "_method": 'POST'},
dataType: 'JSON',
success: function (data) {
console.log('call to postCustomer successful');
}
});
Here is my route:
Route::post('/postCustomer','AdminUserController#store');
The interesting thing about this problem is that when all the post's are changed to get's (both in the ajax call and in the route) the request arrives and is handled correctly. The debug is triggered, and all is well. However, iof the route and the ajax call is set to POST, the debug is never triggered, and the request does not appear to make it. Naturally this smells like a CRSF issue, but I am including the CRSF token in the header.
if the javascript code inside .blade.php file try this
data: {_token:'{{ csrf_field() }}', message:myData, "_method": 'POST'},
hope its help
Try this,
<meta name="_token" content="{!! csrf_token() !!}"/>
$.ajaxSetup({
headers:
{'X-CSRF-TOKEN': $('meta[name="_token"]').attr('content')}
});
$.ajax({
url: "/postCustomer?XDEBUG_SESSION_START=19683",
type: 'POST',
data: {message:myData, "_method": 'POST'},
dataType: 'JSON',
success: function (data) {
console.log('call to postCustomer successful');
}});
No need to pass token in ajax data again.
Heartfelt thanks to everyone who responded. A couple of things helpled in fuguring this thing out. First of all, I consolidated the CSRF token mentions,
and confined what I was sending as data to just that - no need to include the CSRF token in the data if you do it in the ajaxSetup. The second thing wasn't visible from my post, but I was encountering a race condition involving the button that triggered the ajax transaction. The button was causing a page reload before ajax could do its thing, and this is why occasionally the thing would appear to work, but mostly not. So the return false is necessary to prevent that - probably not in both places, but certainly after the ajax transaction has been invoked and we are waiting for the callback. The code which works can be found below. I hope it will prevent somebody else from spending a night going mad trying how to figure out what their POST's aren't working. Take away points: handle your CSRF in an ajaxSetup call, and return false from the whole business.
Thanks again to everybody.
-George Pipkin
Afton, Virginia
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
$.ajax({
/* the route pointing to the post function */
url: "/postCustomer?XDEBUG_SESSION_START=19159",
type: 'POST',
/* send the csrf-token and the input to the controller */
data: {message:myData},
dataType: 'json',
/* remind that 'data' is the response of the AjaxController */
success: function (data) {
$("#success_msg").show();
return false;
}
});
return false;
You should have to pass the _token inside the data object.
data: {_token:'{{ csrf_token() }}',, message:myData, "_method": 'POST'},

Ajax GET for external api without CSRF checking

In my laravel 5.3 application I have enable CSRF checking globally for all ajax requests.
$.ajaxSetup({
headers: { 'X-CSRF-Token' : $('meta[name=_token]').attr('content') }
});
But I have an ajax GET request for an external api as follows.
$.ajax({
url: "https://api.xxxxxxxxxxx/v1/" +code+ "?api_key="+API_KEY,
type: "GET",
dataType: "text",
success: function (data) {
},
error: function (msg) {
}
});
I need to avoid CSRF checking here. I have tried two ways but nothing works for me. In VerifyCsrfToken.php
1st way
class VerifyCsrfToken extends BaseVerifier
{
protected $except = [
'https://api.xxxxxxxxx/v1/*'
];
}
2nd way
class VerifyCsrfToken extends BaseVerifier
{
if ( ! $request->is('https://api.xxxxxxxxx/v1/*'))
{
return parent::handle($request, $next);
}
return $next($request);
}
Please figure it out, how to solve this issue.
Finally, I figured out a way within javascript. We can delete the particular header before ajax call, then reassign the header again.
delete $.ajaxSettings.headers["X-CSRF-Token"];
$.ajax({
url: "https://api.xxxxxxxxxxx/v1/" +code+ "?api_key="+API_KEY,
type: "GET",
dataType: "text",
success: function (data) {
},
error: function (msg) {
}
});
$.ajaxSettings.headers["X-CSRF-Token"] = $('meta[name=_token]').attr('content');
You can override the ajaxSetup in that ajax call like this.
$.ajax({
url: "https://api.xxxxxxxxxxx/v1/" +code+ "?api_key="+API_KEY,
type: "GET",
dataType: "text",
headers : {},
success: function (data) {
},
error: function (msg) {
}
});
Although, you shouldn't use ajaxSetup.
The settings specified here will affect all calls to $.ajax or Ajax-based derivatives such as $.get(). This can cause undesirable behavior since other callers (for example, plugins) may be expecting the normal default settings. For that reason we strongly recommend against using this API. Instead, set the options explicitly in the call or define a simple plugin to do so. : https://api.jquery.com/jquery.ajaxsetup/
This should help
$.ajax({
type:'GET',
url:"https://api.xxxxxxxxxxx/v1/" +code+ "?api_key="+API_KEY,
data:{_token: "{{ csrf_token() }}",
},
success: function( msg ) {
}
});

How to show AJAX response message in alert?

I am sending username and password as request parameter to the server in AJAX and trying to show the response message. But not able to showing the response message.In fiddler it is showing the response message. But while on the browser screen it is not showing.PLEASE somebody help me out where i am wrong or need to change anything..
I have written like this-
$(document).ready(function () {
$("#btnCity").click(function () {
$.ajax({
type: "POST",
url: "http://test.xyz.com/login",
crossDomain: true,
contentType: "application/json; charset=utf-8",
data: { username: "abc", password: "1234" },
dataType: "JSONP",
jsonpCallback: 'jsonCallback',
async: false,
success: function (resdata) {
alert(resdata);
},
error: function (result, status, err) {
alert(result.responseText);
alert(status.responseText);
alert(err.Message);
}
});
});
});
TL;DR: I guess the problem is on the server side of your code (that we don't know yet).
At first: I don't know why it fails for you. I've taken your code and ran it against a public available JSONP API, that returns the current IP of your system and it worked.
Please try yourself using the URL: http://ip.jsontest.com/.
So most probably, the server doesn't return the right response to the JSONP request. Have a look at the network tab in developer tools. With your current code, the answer of the server should be something like:
jsonCallback({'someResponseKeys': 'someResponseValue'});
Note: The header should contain Content-Type:application/javascript!
BTW, even if this doesn't for now solve your problem - here are some tweaks, I'd like to advice to you:
Don't set async to false, at the documentation of jQuery.ajax() says:
Cross-domain requests and dataType: "jsonp" requests do not support synchronous
operation.
You don't need to set a jsonpCallback, because jQuery will generate and handle (using the success function a random one for you. Quote from the docs:
This value will be used instead of the random name automatically generated by jQuery. It is preferable to let jQuery generate a unique name as it'll make it easier to manage the requests and provide callbacks and error handling.
So here comes my code:
$(document).ready(function () {
$("#btnCity").click(function () {
$.ajax({
type: "POST",
url: "http://ip.jsontest.com/",
crossDomain: true,
data: { username: "abc", password: "1234" },
dataType: "JSONP",
success: function (resdata) {
console.log("success", resdata);
},
error: function (result, status, err) {
console.log("error", result.responseText);
console.log("error", status.responseText);
console.log("error", err.Message);
}
});
});
});
A working example can be found here.
Another solution, like Yonatan Ayalon suggested, can be done with a predefined function and then setting the jsonpCallback explicitly to the function that should be called.
if you see the response in Fiddler, it seems that the issue is in the callback function.
you are doing a jsonP call - which means that you need a callback function to "read" the response data.
Do you have a local function that calls "jsonCallback"?
this is a simple jsonP request, which initiates the function "gotBack()" with the response data:
function gotBack(data) {
console.log(data);
}
$.ajax({
url: 'http://test.xyz.com/login' + '?callback=?',
type: "POST",
data: formData,
dataType: "jsonp",
jsonpCallback: "gotBack"
});
You can try with the following methods and close every instance of chrome browser in task manager, then open browser in web security disable mode by the command "chrome.exe --disable-web-security"
success: function (resdata) {
alert(resdata);
alert(JSON.stringify(resdata));
},
And the better option to debug the code using "debugger;"
success: function (resdata) {
debugger;
alert(resdata);
alert(JSON.stringify(resdata));
},

How to include header in ajax request?

I need to include a header with a refresh token in an ajax call to the YouTube api. I am trying to send a delete request, to delete a movie I have on my account. This is my ajax call that fire on button click
jQuery.ajax({
type: 'DELETE',
// must set api key
url: 'https://www.googleapis.com/youtube/v3/videos?id='+ thisUniqueID + '&key=904907387177-qe517sq5dmmpebckjbmrhv4gvac9e2d1.apps.googleusercontent.com',
success: function() {
alert('your video has been deleted');
},
error: function() {
alert('error processing your requst');
}
});
I am receiving a 401 (unauthorized) erorr on return and it seems that I need to include my access token in the call. I was playing around with the google api playground looking at the request and response and this is what shows as the 'Request' being sent out
DELETE https://www.googleapis.com/youtube/v3/videos?id=3242343&key={YOUR_API_KEY}
Authorization: Bearer "access token"
X-JavaScript-User-Agent: Google APIs Explorer
Now from that request it looks like the there are headers that are being sent with the request, which hold the access token. This must be why I am getting a 401 error. How can I include those headers into my ajax request, so that my access token is passed along with the request? Thanks
I was able to pass along a header using this code below:
jQuery.ajax({
type: 'DELETE',
// must set api key
url: 'https://www.googleapis.com/youtube/v3/videos?id='+ thisUniqueID +'&key=api_key_here',
beforeSend: function(xhr){xhr.setRequestHeader('Authorization', 'Bearer access_token_here');},
success: function() {
alert('your video has been deleted');
},
error: function() {
alert('error processing your request');
}
});
You can use beforeSend method and request.setRequestHeader. Take a look at the official documentation here.
P.S. should I post it as a comment?
Try add the paramenter data.
jQuery.ajax({
type: 'DELETE',
data: 'key=' + {YOUR_API_KEY},
// must set api key
url: 'https://www.googleapis.com/youtube/v3/videos?id='+ thisUniqueID + '&key=904907387177-qe517sq5dmmpebckjbmrhv4gvac9e2d1.apps.googleusercontent.com',
success: function() {
alert('your video has been deleted');
},
error: function() {
alert('error processing your requst');
}
});

Resources