I have a phonegap app which connects to a web service and authenticates using http basic authentication. It is built using phonegap build and targets Android and iOS.
On a login view, an ajax request fires against the remote server to check if credentials are correct, then if so, logs the user in to the main application.
This completes successfully in ripple emulator on desktop pc and when also when deployed onto an Android device.
However, when the app is deployed onto an iOS device (ipod touch) the authentication request simply does not ever complete. Using phonegap remote debugger I can see that the ajax request starts but never completes. It is always in a pending state. I use jquery ajax success, error and complete handlers for the request, but none of them are ever hit so I don't get the chance to see any error messages returned from the server. The request never seems to complete.
I have tried making ajax requests to other remote web sites to test that my app can communicate and they succeed, so it doesn't seem as though I have white-listing issues.
Any ideas of what the issue could be?
Please read the update to this answer at bottom.
Original answer
I have found what the issue is and managed to get basic authentication working.
The issue was that the web server was expecting basic authentication details to be preemptively sent with the request.
To do this use the 'headers' property of jquery ajax as shown below:
$.ajax
({
type: "GET",
url: "https://webserver/authenticate",
headers: {
"Authorization": "Basic " + btoa(USERNAME + ":" + PASSWORD)
}
})
.done(function(){
alert('Authenticated!')
})
.fail(function(){
alert('Error!')
});
See related answer:
https://stackoverflow.com/a/11960692/1463497
Update
I found in the end that there is no reliable way of using basic authentication in a web view in iOS. I.e everything is fine if correct credentials are entered but when they are not and the 401 challenge response comes along, iOS web view can't seem to handle it.
In the end, the web service authentication was implemented by simply passing 'username' and 'password' parameters as part of the url:
url: "https://webserver/authenticate?username=abc&password=123"
This is the only consistent way I found of getting authentication to work across iOS and Android in a web view (by getting rid of basic authentication altogether). This of course meant updating the web service itself to accept authentication in this way.
Related
I have a mobile app that is using ODIC authorization code flow. Our server implementation is using Identity Server 4.
The mobile app opens a browser window and I can login to a 3rd party provider just fine, it then redirects to /signin-adfs on our identity server, which sets some idsrv.external cookies and returns a 302 to /External/Callback. The browser redirects to /External/Callback but doesn't send any of the idsrv.external cookies with it so Identity Server throws an exception because the result from HttpContext.AuthenticateAsync is not successful.
I'm kind of stuck at this point because I'm not a mobile developer. I deployed and have customized Identity Server slightly in other areas but not this part of the code.
I believe the mobile app is opening a Safari session to do the auth. Is this an issue with the cookies that the browser doesn't like (domain, path, https, secure)? or something else? The cookie size is chunked to 4KB a piece. I'm not sure what could be causing this issue.
To make things even weirder... if the browser is refreshed (/External/Callback) then the request works and the iOS app gets the code and can make the follow up request to get the token.
Was digging through the IS4 source and saw a link to this issue on github. Looks like it was fixed in source but hasn't been released yet. There are some workarounds in the github issue if you need it sooner than the release. The problem is specific to iOS 12.
I am using the Ionic framework to build an html5 app that is then deployed to an iOS device with PhoneGap. Everything was working great, then we switched some server addresses that were being used to get data to include a port number in the address and the HTTP method was switched from a GET to a POST. After the switch we tested locally in the browser and it was pulling data with no problems. When we deployed to the device we saw nothing in the logs when the request was executed, and the success or error handler was never reached. In the code below only "HERE1" is printed and everything stops.
console.log("HERE1");
$http.post("http://XX.XX.XX.XX:81/api/Authenticate", null ,{ headers: {'Authorization': 'Basic ' + encodedNamePw} })
.success(function (data, status, headers, config) {
console.log("HERE2");
})
.error(function (data) {
console.log("HERE3");
});
I then tried to perform a GET to the same address and I got a response, saying that I obviously had the incorrect method. I then tried a POST to the address without a port and I got response, which was again an error, but at least I got a response. So to summarize it works locally in browser, it works on the iOS device with a GET request and a PORT, but it does not make any request when I use the POST method. I did try to escape the colon but that did not help. I'm pretty baffled by this one so any thoughts are appreciated. Thanks!
After much pain an agony I found the issue and the options available. The issue was that we were getting a 401 response and a www-authenticate http header. When this is sent by the server apparently iOS tries to pop a login dialog, which is blocked by PhoneGap. Instead of hitting the error callback method it just eats it and you never get any feedback that the request has completed.
The best solution requires you to have access to the server you are calling. If you do, and you can update the response to not send a www-authenticate header for 401 responses then you are golden and it works as expected. If you can't then you have the option to set the async option to false on the request. This approach will block at the UI, which is not ideal, but may be acceptable if it is just a login request. Best of luck.
I'm developing an app using Phonegap and it implements a Facebook login to save some data using the user_id as a reference. I'm using OAuth.io library to implement the login dialog and everything runs smoothly in the web browser and in Android but when I test the app in XCode and I tap the login button the following error appears.
Cannot find hostname in file:/// from static
code: InvalidHeader
message: Cannot find hostname in file:/// from static
My guess is that it has something to do with phonegap not making an external request since the app is not actually hosted in a domain but running locally... any thoughts?
Seems like you are using oauth.js library instead of phonegap version
In your main page "index.html" add reference to the correct js file
<script src="oauth-phonegap.js"></script>
Then follow the instructions here to build your application
I had a simular issue using oauth.io. Turns out it was my Ajax prefilter changing the REQUEST to Facebook(it was adding parameters to the header for each request). Wether this is your issue or not, what you need to do is compare a successful REQUEST to Facebook to an unseccussful one, that will show you where things go wrong. Alternativly a blank phonegap app with no extra code other then the required oauth code should work and will be a Good starting point to isolate your issue.
I have been using Phonegap 2 years before.Though I didn't connect to facebook before,I connected to other website by OAuth.I can show you my solution.
Firstly,you should know how OAuth works.You can read OAuth 2.0 from facebook developer website or other websites.
Secondly,you should know your target:token,uid,expires_time.The most important thing is token.
Thirdly,just do it.In 2010,I solve this problem by using Phonegap Childbrowser plugin(now Phonegap have a inAppBrowser) and a light server.
Why I should use a light server?The server can help me to handle the redirecting in OAuth service and do cache.
Step 1 : I wrote script to connect with my server,and my server connect to OAuth Service(facebook).
Step 2 : OAuth Service(Facebook) do response and redirect to Facebook login page.
Step 3 : After input username and password,OAuth Service(Facebook) will redirect to another url and do a callback with some code or token.
Step 4 : If you get the token,save it and use it to connect OAuth Service(Facebook) if you want.
When I saw "Cannot find hostname in file:/// from static " in your description,I know that maybe you get confuse in OAuth.Now,I suggest you some server side code to handle it and make your OAuth process possible.
My organization had a web app that worked perfectly in iOS 6. You'd visit the website, the website would tell you to add the page to your homescreen, and boom, a nice HTML5 web app was added to the home screen.
Because we're processing sensitive data, the web app used HTTP authentication (via the native WebKit auth dialog) to authenticate user/passes. It worked without a hitch until iOS 7. Now when someone tries to summon the HTTP auth dialog, nothing happens. It's clearly trying to load something, as the spinner in the status bar appears, but no dialog ever pops up, essentially breaking the "app."
Has anyone else run into this? Is this something you'd consider to be a bug on Apple's end? Any workaround?
My company ran into this last fall, starting with iOS 6, and what we have been able to ascertain is that it is a genuine Apple Safari bug as part of its security "enhancements". No real explanation from them for rationale, but here is what we see in the debug and packet sniffers.
In normal operation, the Safari browser will request a page (or an object in the page) from the server on a GET. If that asset is protected with an Access Control List, in our case Apache Basic Auth, and it is the first request on that host in the session, the server will respond with a 401 HTTP response header indicating to the client (the browser) that it needs to request again, this time adding a basic auth header that has authorization credentials. The browser then presents a login dialog to the user, where they can enter user and pass credentials, and either submit or cancel the request. On submit, the client re-requests with those credentials in the auth header.
Assuming the credentials are accepted on the second GET request, the proper asset will be returned on the response, and the document in the browser will proceed with loading the rest of the page (assuming it was a page you requested). If you have embedded assets that reside on a different host, and that host requires authentication for that asset, the process is repeated as the page loads.
Here's where it gets broken. If you embed calls to objects from more than 2 hosts total on the same page, which require basic authentication, the 3rd authentication prompt on that page is suppressed, so the browser spins forever waiting for you to enter credentials on a prompt that you never see. Your Safari browser is now hung up on that stalled authentication prompt, on this and any other tab, even on a reload, and you will not get another prompt unless and until you hard-close your browser or restart your device.
This does not affect Chrome, just Safari, and it is both on an iPhone and an iPad with iOS 6 or later. I have the latest iOS version as of this writing (7.0.6), and the problem is still there.
We had a workaround last year, where we would create an internal page that had an array of each of the embedded hosts, which we would then loop through with an iframe embedding a call to the favicon.ico at that host's location. That worked until recently, where now, perhaps because of the iOS 7 feature of freezing background tabs, the auth prompts are frozen up again.
Here was the JavaScript sample:
hosts=["store","profile","www","secure-store","images","m","modules"];
devhost=location.hostname;
var i=0;
while (hosts[i])
{
newhost=devhost.replace('store.mydomain',hosts[i]+'.mydomain');
document.write("<iframe Xhidden seamless=seamless width=0 height=0 src=http://"+newhost+"/favicon.ico><img height='16' width='20' alt='NOT' title='NOT AUTHENTICATED' src=http://"+newhost+"/favicon.ico> Authenticated on "+newhost+"</a></br></iframe>");
document.write("<img height='16' width='20' alt='NOT' title='NOT AUTHENTICATED' src="+(newhost.indexOf('secure')>0?'https://':'http://')+newhost+"/favicon.ico> Authenticated on "+newhost+"</a></br>");
i++;
}
The second set in the document.write would give a visual indication of which hosts have been authenticated, as their favicon is now displayed. It also lets you know which host might be stalled, as its icon is missing.
Since this workaround stopped working on iOS 7, the only cumbersome solution we have is to pre-open a separate tab for each of the favicons (directly in the URL), enter the auth, go back, go to the next one in the list, and repeat until you have cached all of the auth credentials for all of the hosts used on the page. At that point, you can load the original page since your creds are now cached. Cruddy, and completely unreasonable for an end consumer, but is what we need to do for testing sites that are behind a public CDN, as we need to protect assets on that development site with an ACL.
As of today, we are still figuring out a better workaround. Not an issue on Android, Windows, or any other iOS.
Sure worked better when Jobs was alive.
Hope some of this helps.
I have the exact same problem. Basic authentication worked with previous iOS versions but not with iOS 7 in combination with web apps added to the home screen. I think this may be related to the dialog problem described here.
Standard dialogs are not working at all, such as alert, confirm or prompt.
The login prompt that is shown to authenticate the user is probably blocked (does not work or is not visible) and that is why the web app does not pass through the authentication phase.
I suppose Apple will have to fix this bug in a future release.
Edit: After upgrading to iOS 7.0.3 basic authentication suddenly started to work again also in home screen web app mode. Login prompt is displayed and everything works as expected.
I have a BlackBerry java-based app that works with salesforce data and uses oauth 2 for authentication. It has been working fine until recently when users have been complaining that once they get to the accept/deny salesforce oauth page, clicking on Accept button displays a salesforce 404 page.
I attached a debugger to the bb simulator (OS7) and found that everything was working fine up to the point where a POST is made to salesforce on pressing the ACCEPT button in the final stage of authentication/authorisation via salesforce oauth2 user agent flow. At this point, the post would succeed and the response body would contain some markup with a small JavaScript block that just performs a document.location.href assignment to force the browser to navigate to a new URL. I noticed that the URL was not what I was expecting - I was expecting to see the redirect_uri callback address + the access token etc data appended to the end of it (as per the sf oauth2 documentation). What I saw instead was a URL that when navigated to leads the user back to a login page with a message saying that they are attempting to access a resource that requires authentication.
If I perform the same flow in say chrome the URL after the post is what I expect. This all used to work just fine so I am confused as to why it would stop working all of a sudden. I've heard that Salesforce changed their oauth 2 implementation back in late 2011 slightly so I wonder if this has broken my client although I don't see how.
As an experiment I removed all of my code except for an embedded BrowserField and made it navigate to the oauth URL as constructed by combining consumer key and various other values as per the documentation and it still fails with a 404 page at the point of clicking on the accept button after a successful login.
If I try the same bootstrap oauth URL in the built in bb browser the full authentication flow works fine and I am eventually redirected to the final callback URL with access token information appended.
Has anyone else out there had trouble with oauth2 user agent flow on BrowserField (from field2 package)?
Have you tried using the "scope=mobile" parameter? This parameter puts you into a very simplified oauth flow that is optimized for blackberry...we've found they generally have trouble getting through the richer flows designed for iOS/Android. That said, I haven't heard of them having issues on BB7...only the 5 and sometimes 6 series
If that fails, could you open a support case with us?
Try also "display=mobile" and "scope=api web" (with a space), depending on what you are trying to access after OAuth.