DEV Community

BERAT DİNÇKAN
BERAT DİNÇKAN

Posted on

The Solution to the Issue of Signed URL for an S3 Object Expiring Before the Desired Time

In my current project, my team was instructed to create a signed URL for an s3 object created programmatically so that they were able to download the s3 object without any AWS account.

Writing The Code

We created a lambda function. This lambda function used typescript and javascript aws sdk v3.

import { Context } from "aws-lambda";
import {
  GetObjectCommand,
  PutObjectCommand,
  S3Client,
  S3ClientConfig,
} from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
export const lambdaHandler = async (event: object, context: Context) => {
  const maxExpireTime = 604800; //7 days maximum expire time
  const region = "us-west-2";
  const s3client = new S3Client({
    region,
  } as S3ClientConfig);
  const bucketName = "my-bucket-name";
  const key = "my-key";
  const body = "my-body";

  const putObjectCommand = new PutObjectCommand({
    Bucket: bucketName,
    Key: key,
    Body: body,
  });
  await s3client.send(putObjectCommand);

  const getObjectCommand = new GetObjectCommand({
    Bucket: bucketName,
    Key: key,
  });
  const signedURL = await getSignedUrl(s3client, getObjectCommand, {
    expiresIn: maxExpireTime,
  });
  return {
    statusCode: 200,
    body: {
      signedURL,
    },
  };
};
Enter fullscreen mode Exit fullscreen mode

According to this link, the max expiration time is 604800 seconds which means 7 days.

The Problem

So far so good. Lambda worked properly and gave us the signed URL but after 12 hours the signed URL for the s3 object expired and threw an error like below.
S3 signed url expired error

After investigating, we found out that if the token expires the signed URL expires.

The Solution

if you want a token that expires in 7 days which means more than 12 hours you need to use IAM user credentials with signature version 4.

We created IAM user access keys using the AWS console and implemented these keys with signature version 4 in our lambda function.

import { Context } from "aws-lambda";
import {
  GetObjectCommand,
  PutObjectCommand,
  S3Client,
  S3ClientConfig,
} from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
export const lambdaHandler = async (event: object, context: Context) => {
  const maxExpireTime = 604800; //7 days maximum expire time
  const region = "us-west-2";

  const accessKeyId = "MY_ACCESS_KEY_ID";
  const secretAccessKey = "MY_SECRET_ACCESS_KEY";

  const s3client = new S3Client({
    region,
    credentials: {
      accessKeyId,
      secretAccessKey,
    },
    signatureVersion: "v4",
  } as S3ClientConfig);
  const bucketName = "my-bucket-name";
  const key = "my-key";
  const body = "my-body";

  const putObjectCommand = new PutObjectCommand({
    Bucket: bucketName,
    Key: key,
    Body: body,
  });
  await s3client.send(putObjectCommand);

  const getObjectCommand = new GetObjectCommand({
    Bucket: bucketName,
    Key: key,
  });
  const signedURL = await getSignedUrl(s3client, getObjectCommand, {
    expiresIn: maxExpireTime,
  });
  return {
    statusCode: 200,
    body: {
      signedURL,
    },
  };
};
Enter fullscreen mode Exit fullscreen mode

The Result

After using the IAM user access keys with signature version 4, the generated signed URL didn't expire after 12 hours as expected.

The Sources

Contact me:

Top comments (0)