title: NodeJS getSignedUrl from Google Cloud Storage - for upload (write) via AngularJS client
body: <p>I am trying to upload a file to Google Cloud Storage through an AngularJS App. </p>
  
  <p>I want to use a Signed URL (so GCS Authentication details are not stored within the client side AngularJS App). </p>
  
  <p><strong>NodeJS Server Side</strong></p>
  
  <p>The follow code does return a Signed URL from GCS to the client.</p>
  
  <pre><code>var gcloud = require('google-cloud');
  var storage = gcloud.storage;
  var gcs = storage({
    projectId: 'Google Cloud Project ID',
    keyFilename: __dirname + '/Google Cloud Project Keys.json'
  });
  var bucket = gcs.bucket('Google Cloud Bucket Name');
  
  router.get('/uploadurl', function(req, res) {
    var file = bucket.file('test.jpg');
  
    var config = {
      action: 'write',
      expires: '03-17-2025',
      cname: 'Google Cloud Bucket CName'
    };
  
    file.getSignedUrl(config, function(err, url) {
      if (err) {
        deferred.resolve(err);
      } else {
        deferred.resolve(url);
      }
    });
  
  })
  </code></pre>
  
  <p><strong>AngularJS Client Side</strong></p>
  
  <p>Client Side, using the Signed URL (uploadURL) I try to upload to GCS.</p>
  
  <pre><code>angular.module('admin').controller('appendProjectCtrl', function($scope, $http, Upload){
  
        $scope.$watch('projectImages', function () {
          $scope.upload($scope.projectImages, "projectImages");
        });
  
        $scope.$watch('file', function () {
          if ($scope.file != null) {
            $scope.files = [$scope.file];
          }
        });
  
        $scope.upload = function (files, uploadType) {
          console.log("files: ", files);
          if (files &amp;&amp; files.length) {
            for (var i = 0; i &lt; files.length; i++) {
              var file = files[i];
              if (!file.$error) {
                $http.get('/api/storage/uploadurl')
                  .success(function(result) {
                    var uploadURL = result;
  
                    Upload.upload({
                      url: uploadURL,
                      file: file
                    }).then(function (resp) {
                      console.log("image upload: ", resp);
                    }, null, function (evt) {
                      console.log("evt: ", evt);
  
                      var progressPercentage = parseInt(100.0 *
                        evt.loaded / evt.total);
                      console.log(progressPercentage);
  
                      $scope.log = 'progress: ' + progressPercentage +
                        '% ' + evt.config.file.name + '\n' +
                        $scope.log;
                    });
  
                  })
              }
            }
          }
        };
  });
  </code></pre>
  
  <p>However the following error is returned:</p>
  
  <pre><code>&lt;?xml version='1.0' encoding='UTF-8'?&gt;
  &lt;Error&gt;
      &lt;Code&gt;InvalidAuthentication&lt;/Code&gt;
      &lt;Message&gt;The provided authentication header is invalid.&lt;/Message
      &lt;Details&gt;Cannot use Query String params with form POST.&lt;/Details&gt;
  &lt;/Error&gt;
  </code></pre>
  
  <p>I understand from utilising Signed URLs in S3 (and others) that I should not need any further Authentication for the client other than pushing the file to the URL within the allocated timeframe.</p>
  
  <p>I have checked CORS on Google Cloud Storage, and there does not appear to be an issue there either.</p>
  
  <pre><code>[{
     "maxAgeSeconds": 3600, 
     "method": ["GET", "HEAD", "POST", "DELETE", "PUT"], 
     "origin": ["https://regulardomain.com", "http://localhost:8199"],
     "responseHeader": ["*"]
  }]
  </code></pre>
  
  <p>Any thoughts??</p>