Thomas David Kehoe
Thomas David Kehoe

Reputation: 10930

getSignedURL() in Google Cloud Function produces link that works for several days, then returns "SignatureDoesNotMatch"

My Firebase Storage getSignedUrl() download links work for a few days, then stop working. The error message is

SignatureDoesNotMatch
The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.

Last summer there was a long discussion of this on GitHub but I don't see that a solution was reached.

I'm thinking of using getDownloadURL() from the front end instead of using getSignedUrl() from the back end. Is getDownloadURL() less secure then getSignedUrl()?

Here's my code, which is mostly copied from the documentation:

let audioType = 'mp3';
const {Storage} = require('@google-cloud/storage');
const storage = new Storage();
const bucket = storage.bucket('my-app.appspot.com');
var file = bucket.file('Audio/' + longLanguage + '/' + pronunciation + '/' + wordFileType);

  // Firebase Storage file options
  var options = {
    metadata: {
      contentType: 'audio/' + audioType,
      metadata: {
        audioType: audioType,
        longAccent: 'United_States',
        shortAccent: 'US',
        longLanguage: 'English',
        shortLanguage: 'en',
        source: 'Oxford Dictionaries',
        word: word
      }
    }
  };

  const config = {
    action: 'read',
    expires: '03-17-2025',
    content_type: 'audio/mp3'
  };

  function oedPromise() {
    return new Promise(function(resolve, reject) {
      http.get(oedAudioURL, function(response) {
        response.pipe(file.createWriteStream(options))
        .on('error', function(error) {
          console.error(error);
          reject(error);
        })
        .on('finish', function() {
          file.getSignedUrl(config, function(err, url) {
            if (err) {
              console.error(err);
              return;
            } else {
              resolve(url)
            }
          });
        });
      });
    });
  }

Upvotes: 10

Views: 18447

Answers (3)

David D.
David D.

Reputation: 153

The presigned URL will expire at the date you provide with the expires field.

However, the issue you are seeing here is that KMS keys for the admin SDK are rotated every 7 days. So if you create the presignedURL using the auto-provisioned storage() library, once the keys rotate your presigned URL will no longer be valid (because the key used to sign it is no longer valid). So your URL will be valid for less than or equal to 7 days depending on the age of the key.

Instead you need to not use the admin SDK and instead use the Google Cloud Storage npm module and initialize it with a service account json.

const storage = new Storage({keyFilename: "key.json"});

or

`const storage = new Storage({credential: require("key.json")});

Upvotes: 8

Thomas David Kehoe
Thomas David Kehoe

Reputation: 10930

I've written a long answer to this question: [Get Download URL from file uploaded with Cloud Functions for Firebase. This question can be marked as a duplicate.



  [1]: https://stackoverflow.com/questions/42956250/get-download-url-from-file-uploaded-with-cloud-functions-for-firebase

Upvotes: 0

Peter Fortuin
Peter Fortuin

Reputation: 5228

The maximum duration of a Google Cloud Storage Signed URL is 7 days. But it can also be shorter. Never longer. I guess the Firebase Storage has the same limit.

Upvotes: 7

Related Questions