4

I'm working on Flutter an app which will use Express based REST api. While implementing Cookie based sessions, I wanted to retrieve cookies from app with basic auth request but somehow I can't retrieve cookies in response. When I make the same request from Postman, there is no problem, cookies are setted automatically.

I am using HTTP package to make request and code is quite straightforward as below.

void login(String username, String password) async {
var url = 'http://$username:$password@111.222.333.444:3333/auth';
var response = await http.get(url);
print('Response header: ${response.headers}');
print('Response status: ${response.statusCode}');
print('Response body: ${response.body}');
}

There is no cookie in header or body of response.

btutal
  • 115
  • 2
  • 7
  • Could help - https://stackoverflow.com/questions/52241089/how-do-i-make-an-http-request-using-cookies-on-flutter – Hasanuzzaman Rana Oct 15 '19 at 06:45
  • @HasanuzzamanRana https://stackoverflow.com/questions/64691179/flutter-does-not-return-set-cookie-header-from-basic-auth-in-chrome-web --> can you help with this one? similar – Llama Nov 05 '20 at 04:30
  • 1
    don't know the reason but HTTP lib did not return all the cookies, so try https://pub.dev/packages/dio it will return all set-cookies.it works for me – yatin deokar Feb 20 '21 at 14:51

5 Answers5

1

If you want to get cookie values from HTTP response in flutter

String rawCookie = response.headers['set-cookie']!;
int index = rawCookie.indexOf(';');
String refreshToken = (index == -1) ? rawCookie : rawCookie.substring(0, index);
int idx = refreshToken.indexOf("=");
print(refreshToken.substring(idx+1).trim());
saif aly
  • 545
  • 7
  • 8
0

Cookies always come with response headers. If the cookie is set by the backend.

If you wanted to check whether cookies came with a response or not then print like this.

print(response.headers.keys.toList());
print(response.headers.values.toList());
print(response.headers['set-cookie']);

If you want cookies separately as cookie type. You can use this sweet_cookie_jar package.

You can get Cookie like this

Response response=await http.get(Uri.parse('https://catfact.ninja/fact'));
SweetCookieJar sweetCookieJar=SweetCookieJar.from(response: response);
Cookie cookie=sweetCookieJar.find(name: 'XSRF-TOKEN');
print(cookie.name);
print(cookie.value);
print(cookie.expires);

PS: I also have the same doubt as, Why there is no getter available for cookies. If I find the answer, I will update this answer.

MSARKrish
  • 3,355
  • 4
  • 30
  • 43
0

Depending if you use flutter web or mobile there different ways to get cookies

for flutter web you just have to:

  • set credentials to true
  • check whether origin from your server match with your host:port on front

you can define a specific port when launching the app "flutter run -d chrome --web-port 5555"

but for mobile you have to make some tricks

I use Dio package to easily define an onResponse/onRequest function and a conditional import to avoid compilation fail. (withCredential option is available only on web unfortunately.

NetworkConfig.dart

import 'package:dio/dio.dart';

import '../../../constants/url_paths.dart';
import 'get_net_config.dart'
    if (dart.library.io) 'mobile_net_config.dart'
    if (dart.library.html) 'web_net_config.dart';

class NetworkConfig {
  final _client = getClient()
    ..options = BaseOptions(
      baseUrl: url,
      connectTimeout: const Duration(seconds: 5),
      receiveTimeout: const Duration(seconds: 6),
    );

  Dio get client => _client;

  final Map<String, String> headers = <String, String>{
    'Content-Type': 'application/json'
  };
}

I use another class to do my get, post... which extends NetworkConfig

get_network_config.dart

import 'package:dio/dio.dart';

    Dio getClient() => throw UnsupportedError('[Platform ERROR] Network client');

web_network_config.dart

import 'package:dio/browser.dart';
import 'package:dio/dio.dart';

Dio getClient() =>
    Dio()..httpClientAdapter = BrowserHttpClientAdapter(withCredentials: true);

mobile_network_config.dart

import 'dart:io';
import 'package:<projet_name>/data/data.dart';
import 'package:dio/dio.dart';

// CLIENT
Dio getClient() => Dio()
  ..interceptors.add(InterceptorsWrapper(
    onRequest: (options, handler) async {
      final cookie = await localData.read('cookie');

      options.headers['cookie'] = cookie;

      return handler.next(options);
    },
    onResponse: (response, handler) {
      response.headers.forEach((name, values) async {
        if (name == HttpHeaders.setCookieHeader) {
          final cookieMap = <String, String>{};

          for (var c in values) {
            var key = '';
            var value = '';

            key = c.substring(0, c.indexOf('='));
            value = c.substring(key.length + 1, c.indexOf(';'));

            cookieMap[key] = value;
          }

          var cookiesFormatted = '';

          cookieMap
              .forEach((key, value) => cookiesFormatted += '$key=$value; ');

          await localData.write('cookie', cookiesFormatted);

          return;
        }
      });

      return handler.next(response);
    },
  ));

localData is my wrapper for flutter_secure_storage (to persiste cookies locally)


if you use the default Client() class you can also set credentials like this

import 'package:http/http.dart';

Client getClient() => BrowserClient()..withCredentials = true;
bk3
  • 41
  • 3
-1

You have to call 'set-cookie' in header:

var cookies = response.headers['set-cookie'];
hoangquyy
  • 1,893
  • 2
  • 14
  • 29
  • 2
    Doesn't work. Response headers don't have a value for `set-cookie` at all even though it can be seen in the network logs on Chrome. – Rohan Taneja Feb 25 '20 at 16:53
  • agreed. tried both in dio and http packages in flutter web. no set-cookie in the header shows up. but in android and postman for example, set-cookie shows up. – chitgoks Jun 25 '20 at 08:31
  • 1
    @RohanTaneja this looks like a bug in flutter. i confirm that in the network tab in dev console, set-cookie is visible but the output in dart code in flutter web doesnt include it. weird. already tried 3 libs : dio, http and default HttpClient. same result. – chitgoks Jun 26 '20 at 03:34
  • @chitgoks any resolution here? I can see my cookie returned in the browser as well but when I print the headers in the flutter console, it does not show the cookie – Llama Nov 05 '20 at 04:04
  • same question https://stackoverflow.com/questions/64691179/flutter-does-not-return-set-cookie-header-from-basic-auth-in-chrome-web – Llama Nov 05 '20 at 04:31
  • hi, yes i got it to work but i am not working in the project anymore so i have lost track of it. – chitgoks Nov 05 '20 at 06:20
-2

http package get and post actions are sending the request without cookies so you should put the cookies manually like this:

Response response = await get(url, headers: {'cookie': 'session_id=ufe1nfq69mdi67pnql6n1cs3cv; path=/; HttpOnly='});

But there is an easy way to do that without putting cookies manually by requests package

import 'package:requests/requests.dart';
// ...

// For example post some login request
  var url = "http://yourApilink";
  var body = Map<String, dynamic>();
  body["username"] = username;
  body["password"] = password;
  var request = await Requests.post(url, body: body);
  request.raiseForStatus();
  if(request.statusCode==200) {
    //Successful
    var statusJson = json.decode(utf8.decode(request.bytes()));
//....

// Example for get some other actions
  var url = "http://yourApilink";
  var request = await Requests.get(url);
  request.raiseForStatus();
  print(request.json()['userid']);
  if(request.statusCode==200) {
    //Successful
    var statusJson = json.decode(utf8.decode(request.bytes()));
//....
wahid anvary
  • 392
  • 3
  • 11