AWS S3 Signed url to fetch private file

Viewed 1956

Problem:
Users will upload a file and fetch it later on.The Bucket and objects will be private. To upload a file, I'm using s3 pre-signed url. Front end will get this url and upload the file to this url. Now issue is related to fetching the file. To fetch the file, I'm creating a presigned url and storing it in database during upload procees.

    
    const params = {
        Bucket: process.env.DEFAULT_TENANT_BUCKET,
        Key: filePath,
        Expires: expiryTime
    };

    const s3 = new AWS.S3();
    let uploadURL =  s3.getSignedUrl('putObject', params);
    return uploadURL;

    const s3 = new AWS.S3();
    let uploadURL =  s3.getSignedUrl('getObject', params);
    return getURL; // This will be stored in database

But signed url will expire after some time even if we dont specific any expiry time. so I cannot store this presigned url in database.

Another Approah:
Instead of storing the getUrl in database, store the filePath, and create the signed url fetch when front end will fetch this data.
Issue with above approach:

  1. If user list is download in excel format and it contains the url to the file, that url will also be invalid after some period of time.
  2. When users list is large, create signed url can takes time.

Is there any better approach to this problem?

2 Answers

When using pre-signed URLs the best approach is to sign the URL at the time of request. That avoids the timeout issue. The question becomes a question of why are you using a pre-signed URL to begin with? They are great for uploads, and they have their place for downloads, but it seems like you aren't wanting to make the links private, you just don't want to expose the bucket. In that case the best option would be to use CloudFront. Your CloudFront distribution can point to the S3 bucket that is still private. You use the pre-signed URLs for the uploads but links to the files go through CloudFront, so they don't have to be signed.

One way to solve this problem is to build server-side code that can vend pre-signed URLs to authenticated clients on demand.

What you would do is to store a given, fixed URL for each object in your database. That's easy to create, for example: https://api.myserver.com/short-uuid. That's the URL you initially make available to the client. When clients want to fetch a private file, they invoke an HTTP GET of that URL.

You would implement server-side code that responds to these GET requests. You could use a simple API Gateway and Lambda project to do this. The client has the fixed URL, GETs that URL with the relevant authentication token(s), your server-side app authenticates the client, does a quick lookup on the short-uuid parameter provided in the URL, retrieves the associated S3 object's bucket and key, pre-signs a URL, and returns it to the client in an HTTP 302 redirect. The client redirects to the requested pre-signed S3 URL and downloads the file.

Related