Sometimes you may need to protect files on your cloud storage to not be accessible by public. In another tutorial, I had written how to upload file to a Google Cloud Storage bucket, where the uploaded file can be accessible by public. Now, I’m going to show you how to make a file private and how to get signed URL to access the file.

In the previous post, the uploaded file is accessible by public because we intentionally make it public by calling file.makePublic. Actually without file.makePublic, the uploaded file will be private. But if a file currently has public permission and you want to change it to private, you can do it with the following code

As we use @google-cloud/storage library, first we have to call the constructor. Create a new helper file which calls the constructor.

helpers/google-cloud-storage.js

  const GoogleCloudStorage = require('@google-cloud/storage');
  
  const GOOGLE_CLOUD_PROJECT_ID = 'gcs-demo-123456'; // Replace with your project ID
  const GOOGLE_CLOUD_KEYFILE = 'path-to-the-private-key'; // Replace with the path to the downloaded private key
  
  const storage = GoogleCloudStorage({
    projectId: GOOGLE_CLOUD_PROJECT_ID,
    keyFilename: GOOGLE_CLOUD_KEYFILE,
  });

Here is the code to make a file private. Add the code below to the helper file.

helpers/google-cloud-storage.js

  /**
   * Make a file private.
   *
   * @param {string} bucketName
   * @param {string} gcsFileName
   * @return {Promise.}
   */
  exports.makeFilePrivate = (bucketName, gcsFileName) => {
    const bucket = storage.bucket(bucketName);
    const file = bucket.file(gcsFileName);
  
    return file.makePrivate();
  };

Below is the example usage of the function above.

example.js

  const gcsHelpers = require('./helpers/google-cloud-storage');

  gcsHelpers.makeFilePrivate('the-bucket-name', 'something.jpg');

Simply by calling file.makePrivate, the file permission will change to private. The next question is how to access a file with private permission. You need to generate a signed URL in order to do so. Basically, the private URL has the similar format as public URL, added with query string with paramters consisting of GoogleAccessId, Expires and Signature. Here is how to do it using Node.js. Add the following on the helper file.

helpers/google-cloud-storage.js

  /**
   * Get private url of a private file in GCS.
   * By default, the private link is for read action and it will expire in 1 day.
   *
   * @param {string} bucketName
   * @param {string} gcsFileName
   * @param {Object} [config]
   * @return {Promise.}
   */
  exports.getPrivateUrl = (bucketName, gcsFileName, config) => new Bluebird((resolve, reject) => {
    config = config || {};
  
    // If you don't pass config, it will set read as the default action and 1 day from current time as the expiry time.
    _.defaults(config, {
      action: 'read',
      expires: moment().add(1, 'day').format(),
    });
  
    const bucket = storage.bucket(bucketName);
    const file = bucket.file(gcsFileName);
  
    file.getSignedUrl(config, (err, res) => {
      if (err) {
        return reject(err);
      }
  
      resolve(res);
    });
  });

Below is the example usage of the function above.

example.js

  const gcsHelpers = require('./helpers/google-cloud-storage');

  gcsHelpers.getPrivateUrl('the-bucket-name', 'something.jpg', { action: 'write', expires: '2018-01-01' });
.then(console.log);

There are two required config attributes, action and expires. Value of action must be one of the followings:

  • read (HTTP: GET) – to view/download the file
  • write (HTTP: PUT) – to write to the file
  • delete (HTTP: DELETE) – to delete the file

The other required attribute, expires, as the name suggests, is used to determine the limit until when the signed URL will still valid. It won’t be usable after the expiration time.