Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot read set-cookie from response header in Flutter Web #1027

Closed
yerim1210 opened this issue Jan 12, 2021 · 42 comments
Closed

Cannot read set-cookie from response header in Flutter Web #1027

yerim1210 opened this issue Jan 12, 2021 · 42 comments

Comments

@yerim1210
Copy link

According to #585, cookies are automatically managed by the browser, but they are not in Flutter Web. (They works well in Android/iOS). I can see a set-cookie value from the response header in the browser dev tap, but they are not saved in Cookies Storage and not appeared on the console when I print all the headers from the response, it only shows like the below.
[Response Headers] {cache-control: no-cache, no-store, max-age=0, must-revalidate, content-type: application/json; charset=utf-8, expires: -1, pragma: no-cache}

I also tried the this code from @whimthen but it is not working for me.

There are quite many people experiencing this issue and no certain workaround. I'd appreciate there would be an exact workaround.

@joo
Copy link

joo commented Mar 10, 2021

I'm facing the same issue.

@gbloggs
Copy link

gbloggs commented Mar 28, 2021

We are seeing the same issue, using dio 3.0.10. Interestingly we have a header that the srver responds with, X-Authentication that we can see in the network tab of chrome is in the response but the header does not show up in the response headers in dio. Is there a white list of headers we need to add to to allow this header to be made available to us?

I've read somewhere that chrome is consuming the set-cookie header and it is managing the cookie, which makes some sense, but does not explain why this X-Authorisation header is being consumed. Any ideas?

@xia-weiyang
Copy link

我也遇到了同样的问题

@sivaram16
Copy link

sivaram16 commented Apr 12, 2021

Having the same problem any update?

@CZXBigBrother
Copy link

I'm facing the same issue.

@ibrahimsoliman97
Copy link

Facing the same issue, any solution?

@cws-alb
Copy link

cws-alb commented Apr 20, 2021

Just an update on this...

dio 4.0.0
Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel stable, 2.0.5, on Microsoft Windows [Version 10.0.19042.928], locale en-GB)
[√] Android toolchain - develop for Android devices (Android SDK version 30.0.2)
[√] Chrome - develop for the web
[√] Android Studio (version 4.1.0)
[√] Android Studio
[√] Connected device (4 available)

Running on web, hitting the same endpoint as an the android app. Both generated from the same flutter codebase generate these headers in response to the exact same RESTful call:

Web:

headers: {cache-control: [no-cache,  no-store,  max-age=0,  must-revalidate], expires: [0], pragma: [no-cache]}
Android:
I/flutter (16944): headers: {connection: [keep-alive], cache-control: [no-cache, no-store, max-age=0, must-revalidate], set-cookie: [var1=122d; Domain=localhost; Expires=Thu, 20-May-2021 17:56:54 GMT; Path=/a/b], date: [Tue, 20 Apr 2021 17:56:54 GMT], vary: [Origin, Access-Control-Request-Method, Access-Control-Request-Headers], x-frame-options: [DENY], pragma: [no-cache], x-xss-protection: [1; mode=block], x-variable: [Bearer eyxxxxx], x-content-type-options: [nosniff], server: [nginx/1.18.0 (Ubuntu)], expires: [0]}

@nelsonesser
Copy link

I'm facing the same issue too :(

@stale
Copy link

stale bot commented Jun 4, 2021

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If this is still an issue, please make sure it is up to date and if so, add a comment that this is still an issue to keep it open. Thank you for your contributions.

@stale stale bot added the stale label Jun 4, 2021
@mxkdev
Copy link

mxkdev commented Jun 16, 2021

I just ran into the same issue with http-only cookies not beeing saved. My fix was to first configure my Flask backend to support credentials. My flutter dev instance is running in chrome on port 1234.

app = Flask(__name__)
app.config.from_object(Config)
CORS(app, origins=["http://localhost:1234"], supports_credentials=True)

I then added an interceptor with options.extra["withCredentials"] = true to my dio object:

   dio.interceptors.add(InterceptorsWrapper(onRequest: (options, handler) async {
      options.extra["withCredentials"] = true; 
      return handler.next(options);
   });

I found this solution by looking throught the dio source and found this in browser_adapter.dart:

/// Whether to send credentials such as cookies or authorization headers for
/// cross-site requests.
///
/// Defaults to false.
///
/// You can also override this value in Options.extra['withCredentials'] for each request
bool withCredentials = false;

@stale stale bot removed the stale label Jun 16, 2021
@anikket786
Copy link

I'm facing the same issue does anybody found a workaround?

@tl-vt
Copy link

tl-vt commented Jun 26, 2021

facing the same problem.

@superluo
Copy link

superluo commented Jul 4, 2021

facing the same issue.
env:

Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 2.2.3, on Linux, locale en_US.UTF-8)
[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
[✓] Chrome - develop for the web


Desc:

if set Credentials =false
=> response headers just include:content-type: application/json.
else set Credentials=true
=>
Flutter throw ERROR:
Error: DioError [DioErrorType.response]: XMLHttpRequest error.
dart-sdk/lib/_internal/js_dev_runtime/patch/core_patch.dart 909:28 get current
packages/dio/src/dio_mixin.dart 819:20 assureDioError
packages/dio/src/dio_mixin.dart 678:13 _dispatchRequest
dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 60:31

@probepark
Copy link

I got same problem..

@supermuesli
Copy link

Same here. Using Dio in Flutter Web, there seems to be no way to receive HTTP headers other than content-length and content-type. This is not an issue when using Dio in Android or IOS.

@sinoory
Copy link

sinoory commented Aug 1, 2021

same issue in web . set cookie can be found in browser net response, but can't get it from code response.headers

1 similar comment
@09094080-Tao-Jiao
Copy link

same issue in web . set cookie can be found in browser net response, but can't get it from code response.headers

@anikket786
Copy link

@supermuesli @sinoory, This is more of a browser related issue. The below explanation is all what you need to know,

  • Cookies that do not specify a SameSite attribute will be treated as if they specified SameSite=Lax, i.e. they will be restricted to first-party or same-site contexts by default.

  • Cookies that are intended for third-party or cross-site contexts must specify SameSite=None and Secure.

The header cookies from your server probably doesn't contain SameSite attribute and that's why the header cookies are not accepted by the browser. So to make it work either we have to add SameSite=None attribute in response header at server side or The web app needs to be hosted on the same domain as the server from which response is coming.

@sinoory
Copy link

sinoory commented Aug 19, 2021

@anikket786 seems true when run in web. But when run it on android phone , still can not find cookie from response.headers

@mludovico
Copy link

mludovico commented Sep 7, 2021

I have just faced this issue and after making the same call repeatedly I've noticed that in the response object, sometimes this header is present and sometimes not.

image
Set-Cookie missing
image
Set-Cookie present

Achieved running locally on MacOS

@scaleflake
Copy link

I'm facing the same issue. In my case I want to retrieve custom 'X-After-Cursor' header, but I can get only 2 headers: 'Content-Length' and 'Content-Type'

@djks74
Copy link

djks74 commented Oct 7, 2021

same here and I also got refuse to set header "cookies" in console chrome/firefox.

anyone know the solution? thanks

@weysler
Copy link

weysler commented Oct 19, 2021

I'm facing the same issue trying to retrieve a custom header from the response. Any workaround?

@jgoyvaerts
Copy link
Contributor

Not being able to read all headers when doing a cross domain request is a browser security feature related to CORS. This is not a dio bug. If you google some articles about CORS and headers, you will find the explanation how to access the headers you're looking for.

@weysler
Copy link

weysler commented Oct 19, 2021

Hi @jgoyvaerts, really helpful mate, thanks a lot! I got this issue from ISTIO https://discuss.istio.io/t/configuring-cors/7458/6 didn't check for all the CORS headers in my response and was expecting the impossible to happen.

@insinfo
Copy link

insinfo commented Feb 4, 2022

for those who are not able to read custom headers, the server just sends the header "Access-Control-Allow-Headers: *" so that Dio can see all headers.

https://developer.mozilla.org/pt-BR/docs/Web/HTTP/Headers/Access-Control-Allow-Headers

@toplinuxsir
Copy link

I faced the same issues for flutter web!

@toplinuxsir
Copy link

Any one resolved it ? Thanks!

@faFrafa
Copy link

faFrafa commented Mar 30, 2022

Same problems here. I can access the 'set-cookie' header from any platform and REST client but not from Flutter on Chrome.
This prevents users to get their session token, and as a result they cannot use the web app.

And yes, in the response the server API adds * to the access-control-allow-header.

Debugging the app in Chrome, no set-cookie in the API response headers
Screenshot 2022-03-30 at 11 20 43

When debugging the same app on iOS, the set-cookie is present in the API response headers.
Same with iOS and Android emulators and any REST client.

This is so frustrating.

@boziyoung
Copy link

boziyoung commented Apr 11, 2022

Hi, guys! i am facing the same problem. what should i do ?

my back : django , i have set up "django-cors-headers";
i have set up chrome "--disable-web-security" and started it;
but i print it , it still ddin't have "set-cookie".
it is
allow: POST allow: OPTIONS content-length: 50 content-type: application/json date: Mon date: 11 Apr 2022 09:00:05 GMT referrer-policy: same-origin server: WSGIServer/0.2 CPython/3.10.0 vary: Accept vary: Cookie vary: Origin x-content-type-options: nosniff x-frame-options: DENY

but i can see "set-cookie" in the chrome dev tab.
image

@charcoast
Copy link

charcoast commented Apr 21, 2022

I had the same problem that has been reported by several people here and I found a solution.

First, it was necessary to add the code below, because without it the browser does not create the cookies that come in the Set-Cookie response header that comes from another domain. Read more here.

Dio _dio = Dio(options);
BrowserHttpClientAdapter adapter = BrowserHttpClientAdapter();
adapter.withCredentials = true;
_dio.httpClientAdapter = adapter;

The code above was taken from this comment.

Check if your cookies were created at: Dev Tools > Application > Cookies.

I tested many settings in the Flask-CORS library I use in my backend, but I never got a return other than content-length and content-type in response.headers.

As I realized that getting the Set-Cookie header would be too difficult, I googled and found that the dart:html library allows us to get cookies in an simple way 😃

import 'dart:html' as html;
var cookies = html.window.document.cookie;

That way, non-HttpOnly cookies will be accessible

@makoru-hikage
Copy link

makoru-hikage commented Aug 15, 2022

@charcoast , you can still use httpOnly cookies.

The httpOnly Cookies never appear on "Dev Tools > Application > Cookies." Dev Tools act like a frontend app. Try document.cookies in the Console and nothing shall appear.

Instead, look at the browser settings. There I found my httpOnly cookies.

Also, make sure to follow this guide: https://stackoverflow.com/questions/46288437/set-cookies-for-cross-origin-requests

@Harrisonnguyen1210
Copy link

Hi @makoru-hikage , I am having the same problem and can't get the cookie saved in Application tab. As you said, it's httpOnly cookies and can be seen from browser settings. But I wonder how can I have access to these cookies, for further request, because when user is authenticated, these cookies should be tagged along with other request.

@NicolasLaube
Copy link

Here is an interesting article on medium: https://medium.com/swlh/flutter-web-node-js-cors-and-cookies-f5db8d6de882

@djks74
Copy link

djks74 commented Sep 6, 2022 via email

@Riadloc
Copy link

Riadloc commented Oct 28, 2022

I find the answer.

BaseOptions(extra: {"withCredentials": true}));

@sun-jiao
Copy link
Contributor

sun-jiao commented Feb 8, 2023

BaseOptions(extra: {"withCredentials": true}));

That is not enough for me.

Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: *
Access-Control-Allow-Origin: http://[address]:[port]
Set-Cookie: session=[session_id]; Expires=[expire_time]; Secure; SameSite=None

this works fine.

@ottokafka
Copy link

ottokafka commented Feb 19, 2023

I had the same problem with Flutter Web.

Heres what I did in my Node.js backend to solve the problem.

 app.use(cors({
    exposedHeaders: ['my-custom-header']
}));

app.options('*', cors());

Now i'm able to use the custom header in my app.

@lickos
Copy link

lickos commented May 25, 2023

Is there any update to this? i stille can't get the set-cookie

@Buenaventura-Celine
Copy link

Buenaventura-Celine commented Jun 13, 2023

I am experiencing this issue while running on localhost as well. I have tried troubleshooting it, but I haven't been able to find a solution.

@sweatfryash
Copy link

I add this to server's response headers and solved: Access-Control-Expose-Headers: xxx(the header name you want to expose).
And maybe need to add the Access-Control-Allow-Headers,I'm not sure this one,but worth to try.

@luatvudinh
Copy link

@supermuesli @sinoory, This is more of a browser related issue. The below explanation is all what you need to know,

  • Cookies that do not specify a SameSite attribute will be treated as if they specified SameSite=Lax, i.e. they will be restricted to first-party or same-site contexts by default.
  • Cookies that are intended for third-party or cross-site contexts must specify SameSite=None and Secure.

The header cookies from your server probably doesn't contain SameSite attribute and that's why the header cookies are not accepted by the browser. So to make it work either we have to add SameSite=None attribute in response header at server side or The web app needs to be hosted on the same domain as the server from which response is coming.

Require to pass above issue first. Then this is full code from my side.

Step 1: Prepare 2 files. One for web and one for mobile.
Special note: CookieAbstract would be defined in file cookies.dart on next step. Please calm with warnings (my structure might be not good enough, leave a comment).
file cookie_web.dart

import 'dart:html';

import 'cookies.dart';

class CookieClass extends CookieAbstract {
  @override
  String getCookies() {
    return document.cookie ?? '';
  }
}

file cookie_mobile.dart (is just dummy in my case. Define any logic you would like to use)

import 'package:game8bet/data/api/cookies.dart';

class CookieClass extends CookieAbstract {
  @override
  String getCookies() {
    return '';
  }
}

Step 2: Create bridge file which is quite confuse with usage purpose (for import command)
file cookie_bridge.dart

import 'cookies.dart';

class CookieClass extends CookieAbstract {
  @override
  String getCookies() {
    // dummy
    throw UnimplementedError();
  }
}

Step 3: The final file cookies.dart (I define CookieAbstract here)

import 'cookie_bridge.dart'
    if (dart.library.io) 'cookie_mobile.dart'
    if (dart.library.html) 'cookie_web.dart';

abstract class CookieAbstract {
  String getCookies();
}

class CookieHandler {
  static String getCookies() {
    return CookieClass().getCookies();
  }
}

Finally, you can use by using this (ONLY MY USE CASE):

import 'dart:io';
import 'package:flutter/foundation.dart';
import 'cookies.dart';

String cookie = headers.map["set-cookie"]; // this is my method in somewhere code
if (kIsWeb) {
  cookie = CookieHandler.getCookies();
}

As I said I used with my case. You can simply use by call CookieHandler.getCookies() which auto switch to use by mobile or web as we did setup.

Happy coding!!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests