Dio dart/Flutter get and set cookie - flutter

I would like to do a set cookies, do a get request and after get the cookies.
In python it will be this:
> import requests cookies = {'status': 'working','color':'blue'}
> response = session.get('https://google.com/', cookies=cookies)
> print(session.cookies.get_dict())
Do you know how to flutter it? I tried something like this but it doesn't seem to have a cookie in the response and the cookie doesn't seem to be sent
Map<String, String> headers = {
"status":"working",
"color":"blue"
};
final BaseOptions dioBaseOptions = BaseOptions(
baseUrl: 'https://google.com',
headers: {
'Cookie': headers,
},
);
dio = Dio(dioBaseOptions);
var cookieJar=CookieJar();
dio.interceptors.add(CookieManager(cookieJar));
var response = await dio.get('https://google.com/');

Cookie is set by a server in a response header and a browser sends it back in a request header.
After receiving an HTTP request, a server can send one or more Set-Cookie headers with the response. The browser usually stores the cookie and sends it with requests made to the same server inside a Cookie HTTP header.
See Using HTTP cookies for details.
CookieManager does this for dio and Flutter.
To access Cookies in a dio response
final cookies = response.headers['set-cookie']

Related

Flutter post request headers do not appear on Google Cloud Function

I am doing a post request in flutter to a google cloud function:
final uri = Uri.parse(
'https://example.cloudfunctions.net/send_to_queue');
final bearer = 'Bearer ${await user.getIdToken()}';
final response = await http.post(uri, body: json.encode(data),
headers: {HttpHeaders.authorizationHeader: bearer, 'Content-Type': 'application/json'});
In the Google Cloud I print(request.headers) I see a bunch of headers but no Authorization or Content-Type headers.
What should I do?
P.S. Same issue in here Flutter calling firebase cloud function admin.auth.updateUser but I don't want to use a callable function
The browser was sending an OPTIONS request (preflight) before the POST.
I needed to change the Google Cloud Function to handle this:
def main(request):
# Set CORS headers for the preflight request
if request.method == 'OPTIONS':
# Allows GET requests from any origin with the Content-Type
# header and caches preflight response for an 3600s
headers = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
'Access-Control-Max-Age': '3600'
}
return ('', 204, headers)
# Get token from request
token = request.headers.get('Authorization').split('Bearer ')[1]
etc..

Autorization using bearer token failing

Friends
I am accessing an API using bearer token authorization and getting HTTP status 401.
The problematic code is Dart code (in a Flutter app). I have Swift code that accesses the same API so I can check the headers I am passing.
The Dart code:
var client = http.Client();
var url = Uri.https(<site>, <path>);
Map<String, String> body = {
<Hash entries to define request>
};
var headers = <String, String>{
"Content-Type" : "application/x-www-form-urlencoded; charset=UTF-8",
"Accept" : "application/json, text/javascript, */*; q=0.01",
"Authorization" : "Bearer <Hex token>",
};
var response = await client.post(url, headers: headers, body: body);
http is from: import 'package:http/http.dart' as http;
The hex token is taken from a successful login. It is the same as I see after a successful login with the Swift app.
The "Accept" and "Content-Type" are also the same as the Swift app.
In result the statusCode is 401 and reasonPhrase is "Unauthorized"
The Swift app is working perfectly
This was not the problem I thought.
The Authorization header is ignored by the server and it does some cookie magic to authorise.
In Swift the cookies were set without my intervention. So I never understood that the Bearer.... authorization was ignored.

Works via Postman but not in Flutter: API call with GCS pre-signed URL

I'm trying to upload a video file to GCS using a pre-signed url. I've managed to create the url via Google but now I am facing a problem using it.
Upload works in Postman, got response 200.
postman body, postman params
Code copied from Postman results in 403 Forbidden (SignatureDoesNotMatch):
Future<http.StreamedResponse> uploadVideo(
{required String uploadURL, required String filePath}) async {
var headers = {'Content-Type': 'application/octet-stream'};
var request = http.MultipartRequest('PUT', Uri.parse(uploadURL));
request.files.add(await http.MultipartFile.fromPath('file', filePath));
request.headers.addAll(headers);
http.StreamedResponse response = await request.send();
if (response.statusCode == 200) {
print(await response.stream.bytesToString());
} else {
print(response.reasonPhrase);
}
return response;
}
This is the error I am getting from Google:
<?xml version='1.0' encoding='UTF-8'?><Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.</Message><StringToSign>GOOG4-RSA-SHA256
20210803T082850Z
20210803/auto/storage/goog4_request
6d513846a3db49f949b0d2eea8f04b90f918b3b94588c3ed55ed3620b7d7e1f6</StringToSign><CanonicalRequest>PUT
/phonedo-interviews/app-test/007/2.mp4
X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=interviews%40interviews-317011.iam.gserviceaccount.com%2F20210803%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20210803T082850Z&X-Goog-Expires=900&X-Goog-SignedHeaders=content-type%3Bhost
content-type:multipart/form-data; boundary=dart-http-boundary-6w1yq6BQN3EkGBrhHZnwidOXZsBecsgSwTT3nBjB9vQCToHt0cg
host:storage.googleapis.com
content-type;host
UNSIGNED-PAYLOAD</CanonicalRequest></Error>
Note: I needed Content-Type to be application/octet-stream so I disabled that header in Postman's automatic headers and added Content-Type manually. When I didn't do that I also got 403.
The solution was to send the file in binary.
Here is the working code:
Future<http.Response> uploadVideo(
{required String uploadURL, required String filePath}) async {
var response = await http.put(
Uri.parse(uploadURL),
headers: {'content-type': 'application/octet-stream'},
body: File(filePath).readAsBytesSync(),
);
In your Postman headers, a Token is given to GCS (first line). Given that you need authorization, Postman probably has this Token saved somewhere application-wise.
In this flutter code, the headers you're giving do not include an Auth token and therefore you're receiving a 403 error.

Token is generated at the endpoint but does not arrive on the page

I want to create a website with Svelte/Kit and use JWT.
I have found instructions on the internet, for example:
Svelte JWT Authentication https://morioh.com/p/1d95522418b2
SvelteKit Session Authentication Using Cookies https://www.youtube.com/watch?v=bG7cxwBMVag
But unfortunately no instructions for Svelte Kit and JWT. So I tried it myself.
The token is generated at the endpoint, but does not arrive on the page (or is not callable). I suspect that some setting in the headers is wrong, but can't figure out what is wrong. This is my highly simplified test environment:
(1) I call the endpoint login.js from the page index.svelte. For testing, I omit checking email and password and send JWT right back. Data arrives, but I don't see the JWT.
(2) The JWT should be sent to another endpoint. What is the best way to do this?
The "page" index.svelte (simplified):
<script>
let email="", password="";
const doLogin = async () => {
const response = await fetch("/auth/login", {
method: 'POST',
headers: {
"Content-Type": "application/json",
},
credentials: 'include',
body: JSON.stringify({
email,
password
})
});
if (response.status == 200) {
const { done, value } =
await response.body.getReader().read();
await console.log("done, value=", done,
JSON.parse(new TextDecoder("utf-8").decode(value)));
await console.log("headers=", response.headers);
}
}
</script>
<h1>Welcome to MyAuth</h1>
<input type=email bind:value={email}/><br/>
<input type=password bind:value={password}/><br/>
<button on:click={doLogin}>Submit</button>
The "endpoint" login.js (simplified):
import jwt from "jsonwebtoken";
export function post(request, context) {
const token = jwt.sign({
data: { text: "test" },
"topsecret",
});
const response = {
status: 200,
headers: {
'content-type': 'application/json',
'Authorization': `Bearer ${token}`,
},
body: {
passwordOk: true,
}
};
return response;
}
The console shows:
done, value= false {passwordOk: true}
index.svelte:59 headers= HeadersĀ {}
index.svelte:44 Fetch finished loading: POST "http://localhost:3000/auth/login".
doLogin # index.svelte:44
I think you are mixing up the two major parts to authentication:
Requesting/sending credentials.
Using those credentials to access protected content.
Authorization: Bearer ${token} is normally sent from the (browser) client to the server to request access to protected content. So right now, your server is asking the client for permission. This doesn't make sense.
Instead, the login endpoint should send the token via:
Set-Cookie header in the login endpoint.
The body of the response (where passwordOk is).
Set-Cookie causes the browser to send this value as a cookie with every future request. The server can check for this cookie value before serving protected content. This can be more secure because you can send an HTTP only cookie.
If the token is sent in the body of the response to login the client should send the token in future requests with the Authorization: Bearer ${token} header. The server can then check for this header before serving protected content.

How i can get Token from headers?

I did authorization via http. post, send a JSON Body with username and password, in the response I get a Header, the Header has a token, it is stored in 'set_cookie: Authorization=token', how do I get it and write it to the storage?
You can get the cookie from the response of login request using the following code
HttpClient _httpClient = new HttpClient();
HttpClientRequest request = await _httpClient.postUrl(Uri.parse(url));
request.headers.set('content-type', 'application/json');
request.add(utf8.encode(json.encode(jsonMap)));
HttpClientResponse response = await request.close();
print(response.cookies); // this is a List<Cookie>, you can iterate and find the required cookie
Now you can store the cookie using shared_preference plugin, and use it in your all the future requests.
HttpClient client = new HttpClient();
HttpClientRequest clientRequest =
await client.getUrl(Uri.parse("http: //www.example.com/"));
clientRequest.cookies.add(Cookie("sessionid", "asdasdasqqwd"));
You can also explore dio library and use AuthInterceptor to add the token for all the requests for you.