6

The Flutter Web application send a HTTP REST API POST request and gets back a JSON response and a cookie in the Set-Cookie header as follows.

(Flutter (Channel beta, 1.22.0, on Microsoft Windows)

Set-Cookie header

When the cookie is extracted, the response does not seem find the header value. The call and extraction code is:

var response = await http.post(url, headers: {"Content-Type": "application/json"}, body: jsonEncode(data));

if (response.statusCode == 200) {
  var cookie = response.headers['set-cookie'];
  print('cookie: $cookie');
}

The console result is:

cookie: null

The server side runs on ASPNet.Core 3.1 in a Docker container, however it should not be an issue, since the cookie is there in the header. So, how can I extract it in Flutter Web?

Actually my final goal is to send the cookie back with every other request. But it does not seem to happen automatically in the browser. So it is also a good solution if someone could point out the proper way of handling this scenario.

Any help is appretiated. Thanks.

3 Answers 3

16

The question was asked a month ago but my answer might be helpful for someone else. Cookies in Flutter Web are managed by browser - they are automatically added to requests (to Cookie header), if the cookie was set by Set-Cookie previously - more precisely, it works correctly when you do release build. In my case it didn't work during dev builds. My solution:

On server set headers:

Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: http://localhost:61656

// port number may be different

In flutter: class member:

final http.Client _client = http.Client();

// example

Future<String> getTestString() async {
    if (_client is BrowserClient)
      (_client as BrowserClient).withCredentials = true;
    await _client.get('https://localhost/api/login');
    await _client.get('https://localhost/api/login');
    return 'blah';
  }

http.Client() creates an IOClient if dart:io is available and a BrowserClient if dart:html is available - in Flutter Web dart:html is available. Setting withCredentials to true makes cookies work.

Run your app:

flutter run -d chrome --web-port=61656

// the same port number that on server

Remember that in Flutter Web network requests are made with browser XMLHttpRequest.

Sign up to request clarification or add additional context in comments.

11 Comments

Thanks for the answer. I have solved my problem already by using bearer tokens as a workaround but next time I will use this solution.
BrowserClient is not defined, Which package provided it?
I tried these steps (Chrome release mode, setting server headers, using http.Client and enabling withCredentials), but no luck. Still no cookies.
withCredentials didn't helped. Still response.headers['set-cookie'] is not set.
Needs to bold this text Cookies in Flutter Web are managed by browser. I realized I don't need to access cookies at all.
|
2

The reason your Flutter Web request isn’t sending cookies is because, by default, Dio/HTTP on Web does not include cookies unless you explicitly tell it to, and the server must also allow it via CORS.

mostly withCredentials = true flag for browser builds. On Flutter Web, this setting is only available if you cast httpClientAdapter to BrowserHttpClientAdapter.

I use dio, so after initializing Dio() make sure to

 (dio.httpClientAdapter as BrowserHttpClientAdapter).withCredentials =
          true;

example function

class APIMethod {
  var dio = Dio();
Future Get({var param, var endpoint}) async {
    try {
     (dio.httpClientAdapter as BrowserHttpClientAdapter).withCredentials =
          true; // this will attach cookies automatically with request
      print('responsecasdf');
      print(BaseUrl.baseurl + endpoint);
      print(BaseUrl.baseurl + endpoint + "?$param");
      final response = await dio.get(
        "${BaseUrl.baseurl + endpoint}?$param",
        options: Options(
          headers: {
            'Accept': 'application/json',
            // 'apptoken': BaseUrl.apptoken, // uncomment if needed
            // 'storetoken': BaseUrl.storetoken, // uncomment if needed
          },
        ),
      );
      print('responsecasdf $response');

      if (response.statusCode == 200) {
        return response;
      }
    } catch (e) {
      log(
        e.toString(),
        error: e,
        name: 'Error Get',
      );
      return onError(e);
    }
  }
}

fastapi middleware setup

app.add_middleware(
    CORSMiddleware,
    allow_origins=["http://localhost:58000",  # your server
        "http://127.0.0.1:58000"],  # Allow all origins (you can restrict to specific domain later)
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)
app.add_middleware(SessionMiddleware, secret_key='some-secret-key')

this is the example route to setup cookie on flutter from the Fastapi backend :

@app.post("/login")async def login(request: Request, response: RedirectResponse):    session_id = request.session["session_id"] = create_random_session_string()    request.session["token_expiry"] = some_expiry_time  # Token expiry logic    response.set_cookie(key="Authorization", value=session_id)    return {"message":"hello"}

1 Comment

This solved my problem
1

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 production for me. 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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.