Giter Site home page Giter Site logo

Comments (8)

tafelnl avatar tafelnl commented on September 24, 2024 3

Well, yes and no. It's complicated and I am not a native developer. But I will do my best to explain:

Android vs iOS

First of all we have to distinguish between Android and iOS.

On Android everything works just fine, with only one caveat:

Android cookies will work just fine as long as you have your webview server running on http://localhost and you have your backend hosted on a secure (SSL) endpoint. There is a little bug with the persisting of cookies when you close the app quickly after booting up. But there is a simple fix available. See: #3012

On iOS, cookies do not work at all or not correctly (dependent on your setup and use).

Therefore, the rest of this comment considers iOS.

Client vs Server side

Next we need to distinguish between client side and server side cookies.

In an ideal world cookies would work as follows:

Client side cookies can be set by: document.cookie = 'somecookie=yummy;'. And you can get them by const cookies = document.cookie.

Server side cookies will be set by making use of Headers:
E.g.: Set-Cookie: <cookie-name>=<cookie-value>; Domain=<domain-value>; Secure; HttpOnly

If you use the flag HttpOnly;, you will not be able to get and use them from JavaScript. But otherwise you will also be able to get these cookies by running const cookies = document.cookie.

Now, as we know, cookies unfortunately do not behave like this on iOS. This is probably because of the fact that a custom scheme is used (capacitor://).

So the next step is to discover how they exactly do behave.

When do Client side cookies work on iOS?

The answer is quite simple: never.

It's easy to reproduce this. Try running document.cookie = 'somecookie=yummy;'; const cookies = document.cookie;. And you will see that cookies has a value of "". (see: ionic-team/capacitor#1373 (comment))

When do Server side cookies work on iOS?

When you have your app configured as follows:

  "server": {
    "url": "http://example.com"
  }

It will work exactly the same as if you would visit http://example.com in Safari on your Mac or iPhone.

But since such a configuration is only for development purposes you config would probably look like this:

  "server": {}

This configuration makes your app launch from capacitor://localhost. But the URL's you will be calling from for example the fetch API, will probably be just a 'normal' URL (e.g.: https://example.com). Now, normally (like on Android with their http://localhost), this wouldn't be a problem. Just as long as you set the right flags (Secure and SameSite=None) (see also: ionic-team/capacitor#3418 (comment)).

But (understandably) iOS does not consider capacitor://localhost to be a Secure Context. And it is not likely that they will accept this sometime in the future. So therefore all URLs called from within that capacitor://localhost will not be able to set cookies.

What is remarkable is that iframes that are secure (e.g.: https://tr.snapchat.com for tracking) within the webview also seem to be considered insecure by iOS. Because they are also not able to retrieve cookies through a fetch request.

So how to fix all of this?

How to fix the Client side cookies on iOS?

This is pretty straight forward. As explained in my other comment (ionic-team/capacitor#1373 (comment)) we will have to proxy the document.cookie. This way we can override the normal behaviour of the setter and getter. The only thing that is needed for that fix to be implemented is a synchronous way to call native API's. See my feature request here: ionic-team/capacitor#3675.

So not to worry about client side cookies, they can be fixed pretty easily.

How to fix the Server side cookies on iOS?

On to Server side cookies.

Again I am not a native developer. But I did some digging and came up with a few ideas.

The most straight forward (and also the worst) solution is by using a config similar to the following:

  "server": {
    "hostname": "subdomain.example.com"
  }

With subdomain.example.com being your main domain used for API calls and Authentication. Somehow this tricks the WKWebView into thinking that it is running on https://subdomain.example.com (as far as I understand at least). This way cookies from https://subdomain.example.com are accepted. But all other cookies from other domains are still ignored.

This is of course not a viable solution in any way. It has many defects and use cases where this is not a working fix.

So what to do now?

I've got some (still vague) ideas about how to fix this:

A possible solution would be to add afterhooks to both the XMLHttpRequest and fetch API's. In those afterhooks you then read out all the cookie headers and finally set them manually by calling (the fixed) document.cookie = . This is almost perfect (besides the fact that it is hacky in my opinion). Only cookies with the HttpOnly; flag set will not be fixed with this (as JavaScript does not have access to them).

Another solution would be to add beforehooks to both the XMLHttpRequest and fetch API's. In those beforehooks you redirect all them requests to the Capacitor.Plugins.Http API. This would be very nice, but also very tricky. There are a lot of variables to be considered. And the Plugins.Http API might not be able to support all of them.

Last solution I had in mind, was to intercept all XMLHttpRequest and fetch calls within the WKWebView. But I'm not sure if that would be possible. If it's possible, I think this would by far be the best solution; no weird hacky proxies for the JavaScript API's; just one simple interceptor in the native Swift code to read out all the cookie headers and set them in a way that they can be read out again by JavaScript.

Also worth noting is that the Cordova community is bothered by the same issues. A lot of information can be found there. See for example this library: https://github.com/CWBudde/cordova-plugin-wkwebview-inject-cookie. Although I do not understand what problem this library is trying to solve in what way exactly. It might be worth looking at.

from http.

maartenmensink avatar maartenmensink commented on September 24, 2024 2

Is there any update on this topic. Or is Set-Cookie a lost cause for iOs?

from http.

mlynch avatar mlynch commented on September 24, 2024

Just making sure you're awaiting the promise?

It's possible the cookies are "sandboxed" somehow. Would need to dig in but if anyone else has ideas please chime in

from http.

smoosh911 avatar smoosh911 commented on September 24, 2024

I have this same issue.

Here are my dependencies:
"@capacitor-community/http": "^0.2.1",
"@capacitor/core": "^2.1.0",
"@capacitor/ios": "^2.4.4",

The code I'm using:

const cook1 = await Http.setCookie({
  url: '/',
  key: '_ga_F1R0Z1HBV5',
  value: 'GS1.1.1607469233.18.1.1607469258.0'
});

const cook2 = await Http.setCookie({
  url: '/',
  key: '_ga',
  value: 'GA1.1.172759051.1550597580'
});

const cook3 = await Http.setCookie({
  url: '/',
  key: 'dogy',
  value: 'dog world'
});

const getCookies = async () => {
  const ret = await Http.getCookies({
    url: '/'
  });
  console.log('Got cookies', ret);
  return JSON.stringify(ret.value);
};

const result = await getCookies();

console.log('getCookies :>> ', result);

From what I can tell there are no errors, it simply doesn't work on the iOS device and on the iOS simulator. This code does work on Web.

from http.

imhoffd avatar imhoffd commented on September 24, 2024

@tafelnl Is this an issue your implementation would fix?

from http.

thomasvidas avatar thomasvidas commented on September 24, 2024

I'm closing this issue for now because this is mainly an issue with Capacitor Core. The team is aware and actively working on solutions, but for now it is outside the scope of this plugin due to limitations set by Apple with Third Party cookies

from http.

thomasvidas avatar thomasvidas commented on September 24, 2024

On second thought, I'll leave it open, but label it appropriately

from http.

thomasvidas avatar thomasvidas commented on September 24, 2024

This is fixed as best as it can be in this plugin. The issue is open in core, but with the recent 1.0 release of this plugin you can specify the domains you need cookies from and it may fit your use case.

Alternatively you can change the hostname in your capacitor config to allow your cookies to become first party cookies, but as we state in the Capacitor config dogs, it is recommended to keep that value as localhost as it allows the use of Web APIs that would otherwise require a secure context such as navigator.geolocation and MediaDevices.getUserMedia.

from http.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.