Can't Access Cookie in HTTP Response with Flutter
Asked Answered
L

5

6

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:[email protected]: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.

Lefler answered 14/10, 2019 at 14:34 Comment(2)
Could help - #52241589Seldon
don't know the reason but HTTP lib did not return all the cookies, so try pub.dev/packages/dio it will return all set-cookies.it works for meOverstock
M
2

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;
Modulus answered 27/4, 2023 at 14:44 Comment(2)
I would love to see this marked answer - I have seen it working in my case.Carree
BrowserHttpClientAdapter(withCredentials: true) did the magic for meParcae
C
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());
Commemorate answered 18/4, 2022 at 9:1 Comment(0)
L
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.

Lipscomb answered 2/4, 2023 at 8:8 Comment(0)
M
0

There is no need to handle cookies in flutter web. Each api request from browser it will automatically added to header. If you use cross origin (app server domain and frondend domain are different), you need to configure your app server like node/express js

const cors = require('cors');

app.use(cors({
   origin: ["https://yourapidomain.com"],
   methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
   credentials : true // allows cookies
}));

In flutter, use http plugin like below

import 'package:http/browser_client.dart';

class ApiService {

   Future<Response> fetchRequest(
      {required String url, required Map<String, dynamic>? data}) async {
     Client client = BrowserClient()..withCredentials = true;
     return await client.post(Uri.parse(url), body: data);
   }

}

BrowserClient uses XMLHttpRequest. its working fine in flutter web in production. Make sure your cookie value is below format

NAME=w&ddsfsfsfgretdv464565yfbr555yhf; Domain=.yourapidomain.com; Path=/; Expires=Thu, 01 Aug 2024 01:00:00 GMT; HttpOnly
Mireille answered 8/8 at 9:56 Comment(0)
O
-1

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

var cookies = response.headers['set-cookie'];
Obelize answered 15/10, 2019 at 6:39 Comment(4)
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.Sorkin
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.Motorcycle
@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.Motorcycle
hi, yes i got it to work but i am not working in the project anymore so i have lost track of it.Motorcycle

© 2022 - 2024 — McMap. All rights reserved.