phonegap: cookie based authentication (PHP) not working [webview] - ajax

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();

Related

NodeJS|SailsJS|PassportJS AJAX Authentication: Making Successive Requests for Data

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.

Send cookies with ajax call from chrome extension content script

I'm making a chrome extension for a site which provides api to check if user is signed in or not. The api is for a GET request. So when i'm, not singed in it gives.
{ status: "ok", authenticated: false}
When i'm signed in it gives me
{status : "ok", authenticated: true, id: 123}
This works fine on browser, chrome extensions like Postman and advanced Rest Client. But when i use it in my chrome extension background it always says i'm not a authenticated user. I figured out that the ajax call i make does not send cookies for the domain, but the chrome extension like Postman or Advanced REST client do send cookies along with XHR request.
Any idea how can i make ajax to send cookies along with it.
here is my ajax call from chrome extension
$.ajax({
method:"GET",
// xhrFields: {
// withCredentials: true
// },
// crossDomain: true,
url:"http://test-staging.herokuapp.com/user/details",
success: function(result){
if(result.status=="ok"){
alert(JSON.stringify(result));
cb(result.authenticated);
}
},
error: function(err){
alert("unable to authenticate user "+JSON.stringify(err))
}
})
UPDATE 1:
I'm able to get the domain cookies details from the background script. Now i'm looking how i can send the cookies with the ajax call?
If the content script is injected into a page with an origin
(protocol, host and port combination) different from the API origin:
Cookies could be blocked by the third-party cookie blocking feature.
Check if it is enabled: chrome://settings/content/cookies.
Background scripts are not affected by it (as of Chrome 81).
Either set withCredentials: true (credentials: 'include' for fetch)
or add the origin into the permissions section of manifest.json.
To receive the response, correct CORS headers are required in either case.
Prefer moving API calls into a background script and passing data to the
content script with sendMessage to circumvent the third-party cookie blocking,
CORB and CORS restrictions. If you choose to do so, add the API origin into the
permissions section of manifest.json.
This is an old question, but what did it for me had to do with setting a couple flags on my cookies.
According to this blog post: https://www.gmass.co/blog/send-cookie-cross-origin-xmlhttprequest-chrome-extension/
You need to have the samesite: None flag set for this to work. This seems kind of obvious, but wasn't mentioned on most other resources for some reason. In addition, if you want samesite = None, you also need the Secure; flag on the set-cookie: response header so that Chrome will actually listen to it.
For me, and likely for you, this means messing around in your API to have those flags set correctly. For me it even meant I had to make HTTPS work on my localhost server I was developing on, so that chrome would trust me that the cookie was secure. In addition, you need credentials: 'include' as the earlier poster said.
For anyone using flask, this looked like:
app.config['SESSION_COOKIE_SAMESITE'] = "None"
app.config['SESSION_COOKIE_SECURE'] = True
plus debugging with Https (export FLASK_RUN_CERT=adhoc) on the command line.
This is a complex one that took me a long time, but the blog post linked above was a huge help.

How to get cookies from Ajax / xmlhttprequest call's response

My application is making a network call using xmlHttpRequest. In the response i am getting Set-Cookie header (verified with fiddler). I need to access these cookies from javasript. I tried with XmlHttpRequest.getAllResponseHeaders(), it is returning all headers except Set-Cookie.
Is there a way to access these cookies from javascript? If yes, please provide some example.
My application is running on Webbrowser control (IE10), Windows Phone 8.
Thanks in advance.
While awaiting a more specific answer, you can instead send all the cookies set from the server through a post response, then set it locally, as so (using jQuery to make it easier):
// Client
var cookie;
$.post('example.com',{'stuff':'data'},function(data){
cookie = data;
});
// Server
if(isset($_POST['stuff'])) echo WhateverTheCookieWouldBe;
Actually cookies can be accessed via
document.cookie // this will return a string contains all cookie values separated by semicolon
This is actually not true since because of the async nature of request
// Client
var cookie;
$.post('example.com',{'stuff':'data'},function(data){
cookie = data;
});
alert(cookie); // undefined

How to catch AJAX requests in Webbrowser

How can I catch all the AJAX requests that a page makes with a Webbrowser / EmbeddedWB? BeforeNavigate2 unfortunately isn't fired for AJAX requests.
For example: requests which are made when you type in google search bar.
If the environment is under your control. you can use a custom HTTP proxy (based on Indy for example).
See: Indy's TIdHTTPProxyServer: How to filter requests?
Ajax requests can be detected based on their specific header:
How to differentiate Ajax requests from normal Http requests?
Update: this question on the Microsoft web forum has an accepted answer:
AJAX detection in WebBrowser control
If I were you, I would've injected my own script into every page after it's been loaded. This a script that captures all AJAX requests and informs the application.
Using the following code, you may capture every AJAX request made by jQuery (Haven't tried, but I don't think it works for non-jQuery AJAX requests).
$.ajaxSetup({
beforeSend: function() {
// before sending the request
},
complete: function() {
// after request completion
}
});
It's not even a code, but it can give you a clue for what you want to do.
Surely using this method, you're gonna need to somehow communicate with your application. For instance, I'd use my made up protocol and a new window command so that my Delphi component will be able to capture and parse the event.
As I said there are plenty options here and I'm just giving a clue.

Cookie Access over JSONP

I have a page in domain.com that makes a JSONP ajax request (using jQuery's .getJSON() function) to a URL in anotherdomain.com. I thought (read: assumed) that the resource in anotherdomain.com would have server-side access to any cookies set in that domain, but that doesn't seem to be the case?
The ajax call is being done specifically to access a particular cookie, do some data manipulation and return a rich set of information keyed by the cookie value. The original domain doesn't have direct access to the cookie value, so I thought that an ajax request would maintain the state I need.
Which pivotal piece of information about cookies am I overlooking? I'm exhausted and I'm just not seeing it.
Thanks.
UPDATE
I found a way of doing it, but it looks like JSONP to my eye, so I'm wondering why this way works while the Ajax version doesn't. Is the request just disconnected from the browser session so that no cookies are accessible?
<script type="application/x-javascript" src="<?php echo $service_url . '&callback=interests' ?>"></script>
<script type="text/javascript">
function interests( data ) {
$( function() {
var c_behaviors = data.length;
var ids = [];
for( var i = 0; i < c_behaviors; i++ ) {
ids.push( data[i].behavior_id );
}
$('body').append( '<p><label>Returned:</label> ' + ids.join( ', ' ) + '</p>' );
});
}
</script>
The same origin policy applies to all ajax requests, so if the domain being accessed in an ajax call is different than the domain loaded in the browser (document.host), all cookies associated with the domain in the requested url will not be sent up. Therefore, the JSONP approach works because it writes out a new script tag in the window, which will behave like any resource request a browser could make to an external domain (hence passing all the cookies associated with the domain in the url). I have also confirmed this by simply calling $.post("http://atdmt.com") from my chrome console, while on stackoverflow.com in the browser (the only other domain that had cookies in my browser, while writing up the answer) and it did not send up any cookies in the request headers.
Another solution to get around the problem of maintaining state for anotherdomain.com would be to have anotherdomain.com set a first party cookie (by not setting the domain attribute of the cookie) and when an ajax/json request is made to anotherdomain.com access those cookies via javascript and push them up the request using standard HTTP params.
Hope I have helped.
I have encountered the same problem before. The issue I found is that most browsers won't let you ESTABLISH a session (i.e. set a session cookie) when the same origin policy isn't being met.

Resources