Nodejs-storage: Cloud functions. The request signature we calculated does not match the signature you provided

Created on 5 Mar 2018  Â·  9Comments  Â·  Source: googleapis/nodejs-storage

Copied from original issue: https://github.com/GoogleCloudPlatform/google-cloud-node/issues/2807

@alexanderkhitev
March 4, 2018 12:30 PM

I had a task, after registering users in the application (registering through facebook) to keep facebook avatar in firebase storage, as facebook links have a limited period of work. I implemented the function I'll write below, but I get the following error The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method, when I try to use a link to an image. Please tell me how it can be fixed?

const functions = require('firebase-functions');
const admin = require('firebase-admin');
const gcs = require('@google-cloud/storage')({keyFilename: "service-account-credentials.json"});
const uuid = require('uuid');
const imageDownloader = require('../lib/Images/image-manager.js');
const path = require('path');
const timestamp = require('unix-timestamp');

module.exports = functions.https.onRequest((req, res) => {
    const token = req.header('X-Auth-MyApp-Token');
    const imageURL = req.body.imagePath;
    const bucketName = functions.config().googlecloud.defaultbacketname;
    const bucket = gcs.bucket(bucketName);

    var userID = '';
    const shortID = uuid.v1();
    const filename = shortID + '.jpg';
    var profileImagePath = '';

    return admin.auth().verifyIdToken(token).then(decodedToken => {
        userID = decodedToken.uid;

        return imageDownloader.downloadImageToLocalDirectory(imageURL, filename)
    }).then(localImagePath => {

        profileImagePath = path.normalize(path.join('userImages', userID, 'profileImages', filename));
        const uploadProm = bucket.upload(localImagePath, {
            destination: profileImagePath,
            uploadType: "media",
            metadata: {
                contentType: 'image/jpeg'
            }
        });

        return uploadProm;
    }).then(() => {
        console.log('success uploaded');
        const config = {
            action: 'read',
            expires: '03-01-2400',
            contentType: 'image/jpeg'
        };

        const userRefPromise = admin.database().ref()
            .child('users')
            .child(userID)
            .once('value');

        const profileImageFile = bucket.file(profileImagePath);

        return Promise.all([profileImageFile.getSignedUrl(config), userRefPromise])
    }).then(results => {
        const url = results[0][0];
        const userModel = results[1].val();
        const userCheckID = userModel['id'];

        console.log("get url", url);

        // save to database

        const userImagesRef = admin.database().ref().child('userImages')
            .child(userID)
            .child('userProfileImages')
            .push();

        const timeStamp = timestamp.now();
        console.log('timeStamp', timeStamp);
        const imageModelID = userImagesRef.key;
        const userImagesRefPromise = userImagesRef.update({
            'path': url,
            'id': imageModelID,
            'fileName': filename,
            'timeStamp': timeStamp
        });

        const userRef = admin.database().ref()
            .child('users')
            .child(userID)
            .child('currentProfileImage');
        const userRefPromise = userRef.update({
            'path': url,
            'id': imageModelID,
            'fileName': filename,
            'timeStamp': timeStamp
        });

        return Promise.all([userImagesRefPromise, userRefPromise]);
    }).then(() => {
        const successJSON = {};
        successJSON["message"] = "Success operation";
        return res.status(200).send(successJSON);
    }).catch(error => {
        console.log(error);
        const errorJSON = {};
        errorJSON["error"] = error;
        return res.status(error.code).send(errorJSON);
    });
});
storage question

Most helpful comment

@alexanderkhitev I am experiencing the same issue, how did you resolve? Same issue reported in a few places, including here https://github.com/firebase/functions-samples/issues/360 , and here https://github.com/GoogleCloudPlatform/google-cloud-node/issues/1976

My URL works for a few days, and then seems to expire with "SignatureDoesNotMatch" 403 response. So, does not seem to be a matter of including/excluding content-type or using the same request method. The URL just simply ceases to work using the same exact request and conditions.

The relevant query parameter, as an example: '...&Expires=16730323200&Signature=...'

For reference, here is a repo of relevant code:

https://github.com/colinjstief/getSignedUrl-example

All 9 comments

const config = {
  action: 'read',
  expires: '03-01-2400',
  contentType: 'image/jpeg'
};

From the signed URL docs:

If you provide a content-type, the client (browser) must provide this HTTP header set to the same value.

Is that happening?

(related: https://github.com/GoogleCloudPlatform/google-cloud-node/issues/1976)

hi @stephenplusplus I'm sorry I wrote it here. No, this problem does not happen anymore, I solved this problem with the Firebase support team. Thank you

Oh, great to hear! Thanks for letting me know.

@alexanderkhitev I am experiencing the same issue, how did you resolve? Same issue reported in a few places, including here https://github.com/firebase/functions-samples/issues/360 , and here https://github.com/GoogleCloudPlatform/google-cloud-node/issues/1976

My URL works for a few days, and then seems to expire with "SignatureDoesNotMatch" 403 response. So, does not seem to be a matter of including/excluding content-type or using the same request method. The URL just simply ceases to work using the same exact request and conditions.

The relevant query parameter, as an example: '...&Expires=16730323200&Signature=...'

For reference, here is a repo of relevant code:

https://github.com/colinjstief/getSignedUrl-example

Same issue here.

I'm having the same problem. My Firebase Storage download URLs fail after three days, saying that the signatures don't match. The expiration dates are good. I don't specify contentType when I upload the files to Storage. When I tried specifying contentType the download URLs immediately failed, with the same error message. Google's documentation says it should be Content_Type, or maybe Content-Type, not contentType.

I have the same issue. I am also not providing a contentType.

I just wrote a long answer on Stack Overflow:

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


Thomas David Kehoe

LanguageTwo.com

On May 6, 2019 at 10:18 AM Thomas Anderl notifications@github.com wrote:

I have the same issue. I am also not providing a contentType.

—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub https://github.com/googleapis/nodejs-storage/issues/144#issuecomment-489680714 , or mute the thread https://github.com/notifications/unsubscribe-auth/ABIJAYYMTAM6JVMJNKXPVZLPUBK4HANCNFSM4ETWEDOQ .

I also had the same issue but I wasn't setting contentType field for the sign url options which perplexed me and I realised in Postman or my client I had to also set Content-Type as nothing, left it blank and it started working!

Was this page helpful?
0 / 5 - 0 ratings