What happens when you want to share a file only for the next 24 hours? Or when you want to send someone a picture but only let them see if for the next 20 minutes?

You can do that with the files in your storage bucket, with the help of Firebase’s admin SDK.

The Firebase Storage package lets you create signed URLs with a custom expiration date, the admin SDK can only be used server-side, and that’s where Cloud Functions come to the rescue.

If you don’t know what they are, or how to initialize them, I recommend you go through this article first.

Once you have functions initialized, you need to create a new function in the index.ts file. For this example, we’re going to use an HTTP function so that you can call it from your application or from whatever else you need.

The first thing you need to do is to import everything you’ll need and to create the shell of the function:

import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
admin.initializeApp();

const storage = admin.storage();

exports.createAssetDownloadURL = functions.https.onRequest(
  (req: functions.https.Request, res: functions.Response<any>) => {}
);

We’re importing the functions and the admin package because we need those to create the function and access the SDKs.

Then we’re initializing the admin and creating a variable to hold the storage SDK.

Then we’re going to create our function, let’s call it createAssetDownloadURL.

It’s an HTTP function that takes a request and a response as parameters.

After that, you want to get the properties out of the body, for our function to work, we need to send it the path of the file in the storage bucket, and the expiration time in minutes.

import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
admin.initializeApp();

const storage = admin.storage();

exports.createAssetDownloadURL = functions.https.onRequest(
  (req: functions.https.Request, res: functions.Response<any>) => {
    const filePath = req.body.filePath;
    const expirationTimeInMinutes = req.body.expirationTimeInMinutes || 15;
  }
);

Note that we’re adding a default of 15 minutes if the user doesn’t send the value.

After that, we’re going to use the storage SDK to create a signed URL with a custom expiration date:

import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
import { generateResponse } from './utilities';
import { HttpCodes } from './models/http-errors';
admin.initializeApp();

const storage = admin.storage();

exports.createAssetDownloadURL = functions.https.onRequest(
  (req: functions.https.Request, res: functions.Response<any>) => {
    const filePath = req.body.filePath;
    const expirationTimeInMinutes = req.body.expirationTimeInMinutes || 15;

    try {
      const signedUrlResponse: string[] = await storage
        .bucket()
        .file(filePath)
        .getSignedUrl({
          action: 'read',
          expires: new Date(Date.now() + expirationTimeInMinutes * 60000),
        });

      const assetUrl: string = signedUrlResponse[0];

      return res.status(200).send(assetUrl);
    } catch (error) {
      return res.status(500).send(error);
    }
  }
);

The getSignedUrl() function takes one parameter, an object with a few properties, we’re going to focus on 2, action, and expires.

The action property tells you what the user can do with that link. We’re setting it to read telling our function that the user can only read the file, they can’t modify it.

The expires property tells you when the link expires. In our case, we’re setting it to 15 minutes from now, but you can send a specific date there if you want, if, for example, you’d like all your links valid until the end of the month or something like that.

And lastly, the function will return either the assetUrl with a status of 200 or status of 500 and the error that it sends us.

If you have any questions, do let me know 😃