I see sometimes in logs TokenMismatchException and I noticed that this exception is thrown only for mobile users (Android, iOS) or Google Bot.
I set in meta tag csrf token and when the page is loaded I make a post ajax request. I set header in that request like that:
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
but this token is other that the one saved on the session.
Unforunately I would be able only once to reproduce this error myself on iPhone. When I loaded the page again everything was ok (even when I deleted all browser data).
Does anyone know what is wrong?
from your question my guess is it is happening because you kept the page open till the session expiry time which you defined in /app/config/session.php
'lifetime' => 480,
Related
I've recently started using Postman and I am testing an API where I get a CSRF token and then login but I always get a CSRF token mismatch. I am including X-XSRF-TOKEN header but I think the issue is around the cookies not being stored correctly.
I am calling a Laravel Sanctum endpoint to get a CSRF token and when I look in the in the console I can see Set-Cookie response headers
However, when I look in the cookies tab it says no cookies were received from the server
However, when I look at the cookies store they are listed for my test domain (home.local)
Due to this issue, when I send a request to the login, the session cookies are not sent in the request as shown in the console on the request to the login endpoint
I can do this fine using Insomnia.Rest client so I know the API is working as expected - I am however trying to replace Insomnia with Postman.
I've tried Google, but I've only found some bugs that were introduced that seemed to cause something similar back in 2016
Update
I managed to Postman working with production fine using a pre-request script to get the CSRF token and set the environment variable using the below:
const url = pm.environment.get('base_url');
const referer = pm.environment.get('Referer');
pm.sendRequest({
url: `${url}/sanctum/csrf-cookie`,
method: 'GET',
}, function (err, response, {cookies}) {
if (!err) {
console.log("cookies", cookies);
pm.environment.set('xsrf_token', cookies.get('XSRF-TOKEN'))
}
});
Although this worked on production and successfully did the POST request, on my local dev PC, I was still getting the CSRF mismatch.
Although the request/response looked the same between dev/and prod I for some reason had the idea to change my dev URL from my-app.home.local to my-app.home.com and now the cookies are received and send in the next request to login without getting a CSRF token mismatch.
There's clearly an issue with postman here but not sure if it's something I'm doing or a bug in Postman. Does .local mean something different?
my client side react app is running on http://localhost:3000 and my node js server is running on http://localhost:8080. When client url is loaded, it sends GET /auth/user 304 0.494 ms - - fetch ajax request to load user(on react componentDidMount function). Problem is, when typing 'l' on Safari browser and url is autofilled with 'http://localhost:3000', it is confirmed that my server get the same request as GET /auth/user, before I even press enter key and before the client page is loaded. In Chrome it doesn't. Why Safari browser sends ajax request when user didn't visit the page and just typed part of its url? Is it a designed behavior?
As a result of tracking the reason for 6 hours. I figured out Safari implements cached ajax request differently from other web browsers. When Safari has client url data which has records of requesting ajax to external api, Safari sends the same ajax request just before user visits the client url page(when url is being typed and auto-suggested) to check if the response is 200(different) or 304(same). If the response is 304(same) and client page is loaded actually, Safari doesn't send ajax request again. This can be very annoying in the user login process, because the user data is loaded before actual authentication process is complete(user data response is 304), so client app remains unauthenticated when browser is authenticated. The solution I landed was adding an extra query parameter when fetching user data( '${root}/auth/user?' + 'nocache= new Date.getTime()' ) to prevent Caching AJAX in Safari browser. Hope it helps someone who faces the same problem.
I've been using the same code for years and things have been working very well on every browser so far:
$.ajax({
url: '/test.php',
data: parameters,
dataType: 'html',
type: 'post'
})
However, since my users started to upgrade to iOS 11.4, those who use the Private mode of Safari are having an issue with "being disconnected" from my website.
This is because ajax POST requests aren't sending any Cookies, apparently. A whole new session is created as part of that POST request (new cookies created, etc).
However, that doesn't affect anything on the GET requests themselves. They stay with the same cookies (and therefore same session), even though new cookies were set as part of the ajax POST request. It's like those ajax POST requests are "sandboxed", not affecting anything else.
Any ideas? Is this a bug on Safari on iOS 11.4 ?
We worked through a similar issue and figured out that it was actually related to Service Workers. From what I can tell, it's a bug in the latest version of Safari's implementation of Service Workers that causes some cookies not to be passed on POST in Private mode. For now, we have disabled our Service Worker and site functionality has returned to normal for those users.
Not sure if this is your problem or not, but it sounds very similar. Hope this helps!
Making Successive Requests for Data
TL;DR
After authentication, I cannot request data from my app's Front-End -- but only through server-side views and Postman can I make subsequent requests for data after logging in, or by authenticating my user in Postman and then making the data request in my app.
First off, I'm a newbie on the server-side.
I've a SailsJS backend which I'm using for REST. Creating and authenticating a user, using LocalStrategy, works fine -- and really, even making subsequent requests for data works fine -- but not via AJAX from my app.
I can use Postman or server-side views to access data, such as /list; making requests after authentication in my app doesn't work -- UNLESS I jump back into Postman and login, then jump back to my app and remake the request.
I do notice that my set-cookie's in my app are different between the first authentication request and the request for /list.
If necessary, I can show some code, but this seems I'm missing a very high-level, basic concept in making authenticated AJAX requests.
EDIT:
My front-end is on a different domain -- Sails runs on localhost:1337 while my UI runs on localhost:8100.
Here's what my /api/config/cors.js looks like:
module.exports.cors = {
allRoutes: true,
origin: '*',
credentials: true,
// methods: 'GET, POST, PUT, DELETE, OPTIONS, HEAD',
// headers: 'content-type'
};
I'm using angular on the front-end, and the subsequent requests are using withCredentials: true -- do I need to add this to the login request too? Must I send the username/email along in the request also?
How do I allow all my subsequent requests for data authenticated after login?
If your frontend application has as a different origin than your backend application the AJAX requests will not include the session cookie by default.
If you are using jQuery:
$.ajax({
url: a_cross_domain_url,
xhrFields: {
withCredentials: true
}
});
This option has to be used for all AJAX requests, so the server can treat them as belonging to the same session.
You also have to configure the server side to allow CORS requests.
I'm working on a mobile web-app using sencha touch, HTML5 and phonegap as a wrapper.
I'm using PHP-Authentication (Cookie) and ajax-requests. Everything works fine on safari or chrome, but after the deployment with phonegap (webview) it does't work anymore...
Any help would be appreciated :)
Some more details:
All data for my app is loaded via ajax requests to my server component "mobile.php".
I use basic PHP-Auth to autenticate the user:
AJAX-Request [username, password] -> mobile.php
-> Session established (cookie)
All other requests if auth was successful
What's the difference between a normal safari website and the webview?
i figured it out:
you have to change the phonegap_delegate.m file and add the following to the init method:
- (id) init
{
/** If you need to do any extra app-specific initialization, you can do it here
* -jm
**/
//special setting to accept cookies via ajax-request
NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage
sharedHTTPCookieStorage];
[cookieStorage setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyAlways];
return [super init];
}
it enables webview to accept cookies from ajax requests
If your Phonegap AJAX requests are not firing callbacks like they're supposed to, this may be the reason.
If the response you're getting attempts to set cookies and you haven't done Michael's fix then your (jquery) AJAX request will fail quietly -- neither success: nor error: callbacks will fire despite the fact that the server actually received the request and sent a response. It appears you must do this even if you don't care about the cookies.
I hope this helps someone.
I didn't care about the cookies but just spent a few hours trying to figure out why the callbacks didn't fire!
There is a solution that works on android too:
Install plugin https://github.com/wymsee/cordova-HTTP to perform arbitrary HTTP(S) requests.
Replace XMLHttpRequest with the plugin alternative (cordovaHTTP.get or cordovaHTTP.post):
cordovaHTTP.post("https://example.com/login", {email: 'xyz#example.com', passwd: "s3cr3t"}, {}, function(response) {
console.log('success');
console.log(response);
}, function(response) {
console.log('failure');
console.log(response);
});
The response will contain status, data and response.headers["Set-Cookie"], that can be parsed for name, value, domain, path and even HttpOnly flags ;-)
Said cookie can be saved in LocalStorage and sent in subsequent requests (see cordovaHTTP.setHeader() or header parameter of .get/.post methods) to simulate an authenticated user on a desktop browser.
Best ways to store get and delete cookie its working fine in my app which is on live
To store value in cookie
window.localStorage.setItem("key", "value");
To Get value in cookie
var value = window.localStorage.getItem("key");
To Delete cookie value
window.localStorage.removeItem("key");
window.localStorage.clear();