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

288

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(),
    );
Share:
288
userRM
Author by

userRM

Updated on December 31, 2022

Comments

  • userRM
    userRM over 1 year

    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 request headerspostman 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&amp;X-Goog-Credential=interviews%40interviews-317011.iam.gserviceaccount.com%2F20210803%2Fauto%2Fstorage%2Fgoog4_request&amp;X-Goog-Date=20210803T082850Z&amp;X-Goog-Expires=900&amp;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.

  • userRM
    userRM almost 3 years
    thanks, but I'm using a pre-signed URL that does not require Auth.