iOS11 causing CORS Issues in all mobile browsers - ios

We were testing our website on iOS devices with iOS11, and noticed that it was breaking, as the browser would not accept responses from our API. Using the remote debugger, we were able to determine that we were getting a CORS permission error, and the response body and HTTP Headers were being stripped. This seemed to be occurring on all mobile iOS browsers (Chrome/Safari), and continued to occur even after I changed the CORS response header to a wildcard value. However, every other browser/OS/version of iOS is working perfectly. I have attached the network response from our API, the response headers for our API, and the error we are getting from the console.
Is there something about iOS11 that might be causing this, or failing that, is there any way I can get further diagnostics?

We had a similar situation with a form hosted on domain A and posting the data to an API on domain B.
The POST request from domain A contained the header "x-api-key" that is not relevant for domain B
The response to the preflight OPTIONS request to the API contained the headers
Access-Control-Allow-Origin:https://domainA
Access-Control-Allow-Headers:*
Access-Control-Allow-Methods:*
That worked fine for all browsers except those on iOS.
As we finally found out, specifying the wild card * for Access-Control-Allow-Headers
does not work for iOS browsers. In the response to the OPTIONS request you need to specify all the headers that are present in the POST request, even if some headers are not relevant for the server on domain B.
Only then will iOS send the POST request.
Changing the response header to
Access-Control-Allow-Headers:Accept,Content-Type,X-Requested-With,x-api-key
did it (even if the header x-api-key is not processed on server B)

In our case, we were able to solve the problem by adding additional http header information when making an OPTIONS preflight request from our API. It appears that Safari does not like wild cards entries in CORS requests, and additionally, needs every header specified in the Access-Control-Allow-Header value, even 'standard' ones that would not be necessary in other browsers. By adding the following headers to all preflight requests, we were able to get X-Domain requests between our site and our api working again.
<!-- headers for preflight CORS response-->
<add key="Access-Control-Allow-Origin" value="<exact name of site>" />
<add key="Access-Control-Allow-Methods" value="POST, GET, OPTIONS, DELETE" />
<add key="Access-Control-Allow-Credentials" value="true" />
<add key="Access-Control-Allow-Headers" value="Accept,Origin,Content-Type,X-LS-CORS-Template,X-LS-Auth-Token,X-LS-Auth-User-Token,Content-Type,X-LS-Sync-Result,X-LS-Sequence,token" />

iOS 11 has introduced some new tracking protection which block some sites/URL
You can disable this in Settings -> Safari -> Prevent Cross-Site Tracking.
Maybe that is your problem ?
I have the same problem, this works - but I would like a way about without our users have to do this.
source: https://www.macrumors.com/how-to/safari-ios-11-tracking-prevention/

I faced the same issue.
The problem in my case was that nginx was not letting the file upload go because the body was too large and nginx did not let that request pass to the application and just killed the connection. I changed the client_body_max_size 10M and it just worked. Look into your nginx error log!
Took me about whole day to figure out.

Related

Safari Web Extension background request CORS issue

I am working on Safari Web Extension on on iOS 15, everything seems smooth so far except one thing:
The fetch request from background.js will always fail since it is cross origin and hence throws CORS error.
If I add the "Access-Control-Allow-Origin: *" in server, the request is completed without any error. However, we are reluctant to allow all origins.
Solutions tried
Access-Control-Allow-Origin: safari-web-extension://<guid>
Access-Control-Allow-Headers:< some request header we sent >
This didn't work because the GUID changes every-time the app is installed.
Any advice to resolve this?
Thanks a lot

Ionic app on iOS requires turning off Safari setting "prevent cross-site tracking"

We have an Ionic 4 (Cordova/Angular) app that makes requests to a REST API backend with HttpClient, using cookies for authentication.
The app runs fine on Android (which apparently proves that we've configured CORS correctly). We are now in the process of adapting it for iOS. We have found that when the Safari setting "prevent cross-site tracking" is turned on (which it is by default), WkWebView ignores the Set-Cookie header that is sent by the backend in response to a successful login request, causing all subsequent requests to fail.
Is there a way to avoid the problem without requiring all users to turn off this setting (which is definitely not an option)? We have considered switching to JWT authentication, but I'm afraid that it won't solve the problem, as our backend expects JSON, and according to the docs, "Content-Type: application/json" headers also cause the request to be considered as a CORS request.
Additionaly, we have come across another problem which seems to be related. The app won't run on the iOS simulator on macOS - the Set-Cookie headers are ignored, even if we switch the above setting off! Meaning we can debug the app only on a physical device, which is quite a hindrance.
After several hours of searching on the web, and not finding any similar complaints, I have the feeling that I'm missing something obvious.
This library has come to my rescue: ionic-native-http-connection-backend
Quoting from the docs:
This library adds #ionic-native/http (when available) as a connection backend to Angular's Http and HttpClient
Motivation
Now that Apple promotes/requires the use of WKWebView instead of the deprecated UIWebView, Ionic has switched newly created apps over via their cordova-plugin-ionic-webview (and Cordova offers it via their cordova-plugin-wkwebview-engine). That causes requests that used to work just fine to fail with CORS errors.
The real solution of course is to fix the CORS issues server side - but this may not be possible with e.g. 3rd party APIs.
Even though there is a way to solve CORS issues without changing server's response header by using #ionic-native/http, this only works on device and doesn't provide all the power of Angular's Http and HttpClient.
How it works
The library provides a HttpBackend interface for Angular's HttpClient
This HttpBackend interface tries to use #ionic-native/http whenever it is possible (= on device with installed plugin)
If HttpBackend finds it impossible to use #ionic-native/http, it falls back to standard Angular code (HttpXhrBackend, which uses XmlHttpRequest)
This strategy allows developers to use Angular's HttpClient transparently in both environments: Browser and Device.
Although I still find it strange, that the developer only mentions the library's intended use for situations where CORS can't be configured server-side, but not the 2 problems that it solves for me, namely 1) having to require all users to allow cross-site tracking, and 2) not being able to use the simulator.

Cookies not being set on iOS using identityserver

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.

Axios : Authorization Bearer not sent on iOS

I attach on every outgoing request an Authorization header whose value is 'Bearer {access_token}' with the following command : window.axios.defaults.headers.common['Authorization'] = 'Bearer ' + localStorage.getItem('access_token');
This works fine everywhere except on iOS where the header is not attached to the request.
I also tried to attach it on a single request, and same issue.
The header is not present in the request and the server returns a 401 Unauthorized error.
The bug happens whatever the browser is on iOS : Safari, Chrome, Firefox. It is really specific to iOS (my version is 11.3.1). No problem on Android or on Desktop (MacOS, Windows).
I made some debugging with the iOS Simulator (where the problem also happens) : there is an item named access_token in the localStorage so the problem is not related to that.
What is happening??
thanks
As you mentioned, this bug seems to happen only on iOS/Safari. We're also facing this issue with axios in our React Native app.
It happens only with GET requests (authorization token gets sent alright with POST and PUT requests).
So you have two options:
Use a different header key, e.g. Authorization-Fake-X as suggested here.
Change the type of your requests (e.g. POST or PUT) if this issue occurs only with GET requests. This is an ugly option because you'll break the REST API behaviour.
Update:
The issue seems to have been fixed in October 2021, according to this SO answer. Still, we have to fix it for people using older versions of Safari and iOS.

Ionic - No response from $http on basic login

We are creating a Ionic app with a Symfony api and we have a problem with $http when login on iOS. When login or password are not corrects, $http never received response from the api and timeout 30seconds later with status 0, althought everything works fine on Android with the same code (api responses are the same regardless of the platform). We tries a lot of different things but it seems like iOS refuses to receive the response for this particular request. Other requests works normally, response and status are received as expected. Below is the login request code
$http.defaults.headers.common.Authorization = 'Basic ' + Base64.encode(user + ':' + password);
$http.get("https://myserver.com/api/login")
.success(function(data, status) {
console.log("success");
})
.error(function(error, status) {
console.log("error");
});
Do somebody has ever encounter this kind of problem with iOS or even know how to fix it (or at least to debug it !)?
I don't know what code can make you help us so let me know !
EDIT:
Not found the solution yet but now I understand the problem !
When http basic response's status is 401, it set a header named WWW-Authenticate. But Cordova don't like this header (probably because of the "" in the header value) so didn't send the response to the app ...
The apache issue:
https://issues.apache.org/jira/browse/CB-2415
Another SO post related:
Handling HTTP 401 with WWW-Authenticate in Cordova / Ionic iOS application
So now my problem has changed : How can I remove a header from Symfony Http Basic Authentification's response ?
It's a bit hard to debug without an error to look at but you could try:
Assuming your url is not https based, your error is most likely due to ios blocking non http requests. It can be fixed by adding this cordova hook
Try adding your domain to the whitelist in config.xml like this <allow-navigation href="https://myserver.com/*"/>

Resources