AWS
S3
SDK
JavaScript
tutorial

How to Get Signed S3 Url in AWS-SDK JS Version 3?

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

In AWS SDK for JavaScript v3, you generate a signed S3 URL with getSignedUrl from the request presigner package. The key pieces are an S3Client, the command you want to authorize, and an expiration time that controls how long the URL stays valid.

Install the Required Packages

For a basic S3 presigning setup, install the S3 client and the presigner helper.

bash
npm install @aws-sdk/client-s3 @aws-sdk/s3-request-presigner

Your code also needs working AWS credentials through the usual SDK resolution chain, such as environment variables, an IAM role, or a shared credentials file.

Generate a Signed URL for Downloading

The most common case is a signed GET URL for downloading an object.

javascript
1import { S3Client, GetObjectCommand } from "@aws-sdk/client-s3";
2import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
3
4const client = new S3Client({ region: "us-east-1" });
5
6const command = new GetObjectCommand({
7  Bucket: "my-bucket",
8  Key: "reports/summary.pdf"
9});
10
11const url = await getSignedUrl(client, command, {
12  expiresIn: 60 * 15
13});
14
15console.log(url);

That returns a URL clients can use for temporary access without exposing your AWS secret key.

Generate a Signed URL for Uploading

The same pattern works for uploads, but the command changes to PutObjectCommand.

javascript
1import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
2import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
3
4const client = new S3Client({ region: "us-east-1" });
5
6const command = new PutObjectCommand({
7  Bucket: "my-bucket",
8  Key: "uploads/photo.jpg",
9  ContentType: "image/jpeg"
10});
11
12const url = await getSignedUrl(client, command, {
13  expiresIn: 60 * 10
14});
15
16console.log(url);

A client can then send an HTTP PUT to that URL. The request headers must match the headers that were part of the signed command, especially things such as Content-Type.

Why v3 Looks Different from v2

In SDK v2, many examples used methods attached directly to the S3 service object. In v3, the SDK is more modular. You create command objects and then presign those commands.

That change is why v3 examples usually look like this sequence:

  1. Create S3Client.
  2. Create GetObjectCommand or PutObjectCommand.
  3. Pass both into getSignedUrl.

Once you know that pattern, generating signed URLs becomes predictable.

Controlling Expiration

The expiresIn option is measured in seconds.

javascript
const url = await getSignedUrl(client, command, {
  expiresIn: 3600
});

Shorter expiration times are usually better for security. Signed URLs should be valid only as long as the user or client actually needs them.

For S3 presigned URLs using Signature Version 4, the maximum practical lifetime is typically seven days.

Server-Side Utility Example

In an application, you usually wrap presigning in a small helper rather than scattering it through route handlers.

javascript
1import { S3Client, GetObjectCommand } from "@aws-sdk/client-s3";
2import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
3
4const client = new S3Client({ region: process.env.AWS_REGION });
5
6export async function createDownloadUrl(bucket, key) {
7  const command = new GetObjectCommand({ Bucket: bucket, Key: key });
8  return getSignedUrl(client, command, { expiresIn: 900 });
9}

That keeps presigning logic consistent and makes it easier to change expiration policy in one place.

Common Pitfalls

A common mistake is installing only @aws-sdk/client-s3 and forgetting @aws-sdk/s3-request-presigner, which is where getSignedUrl lives in v3.

Another pitfall is signing a PutObjectCommand with headers such as ContentType, then sending an upload request that omits or changes those headers. The signature may fail because the actual request no longer matches what was signed.

Region mismatches also cause confusion. If the bucket is in a different region than the client configuration, the signed URL can fail even though the code looks correct.

Finally, do not generate signed URLs from unvalidated user input without checking bucket and key rules. Presigning is authorization, so your application should decide what objects a caller is allowed to access before generating the URL.

Summary

  • In SDK v3, signed S3 URLs are created with getSignedUrl and an S3 command object.
  • Install both @aws-sdk/client-s3 and @aws-sdk/s3-request-presigner.
  • Use GetObjectCommand for downloads and PutObjectCommand for uploads.
  • Keep expiresIn short unless there is a real reason to extend it.
  • Make sure the signed command, region, and actual HTTP request headers all line up.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.