Skip to main content
The AWS SDK for JavaScript v3 provides several packages for signing requests without making an API call. Use these to create time-limited URLs you can hand to clients, browsers, or third-party services.

S3 request presigner — @aws-sdk/s3-request-presigner

Generates presigned URLs for any S3 operation using Signature Version 4.
npm install @aws-sdk/s3-request-presigner @aws-sdk/client-s3

getSignedUrl(client, command, options?)

import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
import { S3Client, GetObjectCommand } from "@aws-sdk/client-s3";

const client = new S3Client({ region: "us-east-1" });

const url = await getSignedUrl(
  client,
  new GetObjectCommand({ Bucket: "my-bucket", Key: "my-object.png" }),
  { expiresIn: 3600 }
);
// url is valid for 1 hour
client
S3Client
required
An initialized S3Client instance. The signer inherits its region, credentials, and endpoint configuration.
command
S3Command
required
Any S3 command instance: GetObjectCommand, PutObjectCommand, DeleteObjectCommand, HeadObjectCommand, etc.
options.expiresIn
number
default:"900"
Number of seconds until the URL expires. Maximum is 604800 (7 days) for IAM role credentials.
options.signingDate
Date
Override the date used for signing. Defaults to now.
options.signingRegion
string
Override the signing region. Defaults to the client’s region.
options.signableHeaders
Set<string>
Headers to enforce as required in the presigned request. Useful for non-x-amz-* headers like content-type.
options.unhoistableHeaders
Set<string>
Force x-amz-* headers to remain as request headers rather than being moved to query parameters. Required when signing headers like x-amz-checksum-sha256.
options.hoistableHeaders
Set<string>
Override the default behavior and move specific x-amz-* headers into query parameters. Useful for SSE headers.
Returns: Promise<string> — the presigned URL.

Examples

import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
import { S3Client, GetObjectCommand } from "@aws-sdk/client-s3";

const client = new S3Client({ region: "us-east-1" });

const downloadUrl = await getSignedUrl(
  client,
  new GetObjectCommand({
    Bucket: "my-bucket",
    Key: "reports/january.pdf",
  }),
  { expiresIn: 3600 } // 1 hour
);

S3RequestPresigner class

For presigning arbitrary HttpRequest objects without constructing S3 commands:
import { S3RequestPresigner } from "@aws-sdk/s3-request-presigner";
import { Hash } from "@aws-sdk/hash-node";

const s3Client = new S3Client({ region: "us-east-1" });

// Reuse the config from an existing client
const presigner = new S3RequestPresigner({ ...s3Client.config });

const presignedRequest = await presigner.presign(httpRequest);

S3 presigned POST — @aws-sdk/s3-presigned-post

Generates a URL and form fields for browser-based POST uploads directly to S3. Unlike presigned GET/PUT URLs, presigned POST allows attaching upload policies (size limits, key prefixes, ACLs).
npm install @aws-sdk/s3-presigned-post @aws-sdk/client-s3

createPresignedPost(client, options)

import { createPresignedPost } from "@aws-sdk/s3-presigned-post";
import { S3Client } from "@aws-sdk/client-s3";

const client = new S3Client({ region: "us-west-2" });

const { url, fields } = await createPresignedPost(client, {
  Bucket: "my-bucket",
  Key: "uploads/${filename}", // ${filename} is replaced by the browser
  Conditions: [
    { acl: "bucket-owner-full-control" },
    ["content-length-range", 0, 10 * 1024 * 1024], // max 10 MB
    ["starts-with", "$Content-Type", "image/"],
  ],
  Fields: {
    acl: "bucket-owner-full-control",
  },
  Expires: 600, // 10 minutes
});
client
S3Client
required
An initialized S3Client instance.
options.Bucket
string
required
Target S3 bucket name.
options.Key
string
required
Object key or key prefix. Use ${filename} as a placeholder for the original filename.
options.Conditions
array
Array of POST policy conditions. Supported formats:
  • Exact match: { "fieldName": "value" }
  • Starts-with: ["starts-with", "$fieldName", "prefix"]
  • Range: ["content-length-range", minBytes, maxBytes]
options.Fields
Record<string, string>
Key-value pairs to include as hidden form fields. Values must satisfy the conditions in Conditions.
options.Expires
number
default:"3600"
Seconds until the presigned POST expires.
Returns: Promise<{ url: string; fields: Record<string, string> }>

Examples

<!-- Use url and fields returned by createPresignedPost() -->
<form action="https://my-bucket.s3.amazonaws.com/" method="POST" enctype="multipart/form-data">
  <!-- Render each field as a hidden input -->
  <input type="hidden" name="key" value="uploads/photo.jpg" />
  <input type="hidden" name="AWSAccessKeyId" value="AKIAIOSFODNN7EXAMPLE" />
  <input type="hidden" name="policy" value="eyJleHBpcmF0aW9uIjoiMjAy..." />
  <input type="hidden" name="signature" value="BASE64_SIGNATURE" />
  <!-- File input must be last -->
  <input type="file" name="file" />
  <button type="submit">Upload</button>
</form>

CloudFront signer — @aws-sdk/cloudfront-signer

Signs CloudFront URLs and generates signed cookies to restrict access to private CloudFront distributions. Uses your CloudFront key pair (trusted key group), not IAM credentials.
npm install @aws-sdk/cloudfront-signer
CloudFront signing is fundamentally different from S3 presigning. CloudFront uses a private RSA key from a CloudFront key group, not AWS SigV4.

getSignedUrl(options) — canned policy

The simplest form signs a URL with a canned policy (expiration time only).
import { getSignedUrl } from "@aws-sdk/cloudfront-signer";

const signedUrl = getSignedUrl({
  url: "https://d111111abcdef8.cloudfront.net/private-content/image.jpeg",
  keyPairId: "K2JCJMDEHXQW5F",        // CloudFront key pair ID
  privateKey: "-----BEGIN RSA PRIVATE KEY-----\n...",
  dateLessThan: "2024-12-31",          // any Date constructor-compatible value
});
options.url
string
The full CloudFront URL to sign. Required for canned policy. Can be omitted when using a custom policy (the URL is extracted from the policy).
options.keyPairId
string
required
The public key ID of your CloudFront trusted key group key pair.
options.privateKey
string | Buffer
required
The RSA private key contents (PEM format). Load from a secure source such as AWS Secrets Manager.
options.dateLessThan
string | Date
required
Expiration date/time. Accepts any value compatible with the Date constructor.
options.dateGreaterThan
string | Date
Start date/time for access (custom policy only). Content is inaccessible before this time.
options.ipAddress
string
Restrict access to a specific IP address or CIDR range (custom policy only). Example: "198.51.100.0/24".
options.policy
string
A pre-built custom policy JSON string. When provided, dateLessThan, dateGreaterThan, and ipAddress are ignored — include them in the policy instead.

getSignedUrl(options) — custom policy

Use a custom policy to restrict access by IP address or time window:
import { getSignedUrl } from "@aws-sdk/cloudfront-signer";

const url = "https://d111111abcdef8.cloudfront.net/private-content/video.mp4";

const policy = JSON.stringify({
  Statement: [
    {
      Resource: url,
      Condition: {
        DateLessThan: {
          "AWS:EpochTime": Math.floor(new Date("2024-12-31").getTime() / 1000),
        },
        DateGreaterThan: {
          "AWS:EpochTime": Math.floor(Date.now() / 1000),
        },
        IpAddress: {
          "AWS:SourceIp": "198.51.100.0/24",
        },
      },
    },
  ],
});

const signedUrl = getSignedUrl({
  keyPairId: "K2JCJMDEHXQW5F",
  privateKey: process.env.CLOUDFRONT_PRIVATE_KEY,
  policy,
  // url is extracted from the policy Resource field; override only if needed
});

getSignedCookies(options)

Returns cookies that grant access to all URLs matching a pattern. Useful when you want to restrict an entire section of a distribution.
import { getSignedCookies } from "@aws-sdk/cloudfront-signer";

const cookies = getSignedCookies({
  url: "https://d111111abcdef8.cloudfront.net/private-content/*",
  keyPairId: "K2JCJMDEHXQW5F",
  privateKey: process.env.CLOUDFRONT_PRIVATE_KEY,
  dateLessThan: "2024-12-31",
});

// cookies is an object, e.g.:
// {
//   "CloudFront-Policy": "...",
//   "CloudFront-Signature": "...",
//   "CloudFront-Key-Pair-Id": "K2JCJMDEHXQW5F"
// }
Set each cookie on the response with Domain and Path matching your distribution:
// Express example
Object.entries(cookies).forEach(([name, value]) => {
  res.cookie(name, value, {
    domain: ".example.com",
    path: "/private-content",
    httpOnly: true,
    secure: true,
  });
});
getSignedCookies accepts the same options as getSignedUrl, including the custom policy parameter.

Polly presigner — @aws-sdk/polly-request-presigner

Generates a presigned URL for a Polly SynthesizeSpeech request so browsers can play audio directly without sending AWS credentials.
npm install @aws-sdk/polly-request-presigner @aws-sdk/client-polly

getSynthesizeSpeechUrl(options)

import { PollyClient } from "@aws-sdk/client-polly";
import { getSynthesizeSpeechUrl } from "@aws-sdk/polly-request-presigner";

const client = new PollyClient({ region: "us-east-1" });

const url = await getSynthesizeSpeechUrl({
  client,
  params: {
    Text: "Hello! This is a presigned Polly request.",
    OutputFormat: "mp3",
    VoiceId: "Joanna",
  },
});

console.log(url); // Play directly in a browser <audio> element
options.client
PollyClient | Polly
required
An initialized PollyClient (bare-bones) or Polly (aggregated) instance.
options.params
SynthesizeSpeechInput
required
Parameters for the SynthesizeSpeech operation.
options.params.Text
string
required
The text to synthesize. Up to 3000 characters (billed characters).
options.params.OutputFormat
string
required
Audio format: "mp3", "ogg_vorbis", "pcm", or "json".
options.params.VoiceId
string
required
The Polly voice ID (e.g., "Joanna", "Matthew", "Kimberly").
options.expiresIn
number
default:"900"
Seconds until the presigned URL expires.
Returns: Promise<string> — a presigned URL. Use as the src attribute of an <audio> element or a direct HTTP GET request. Example with a browser audio element:
<audio controls src="PRESIGNED_URL_HERE"></audio>

SigV4a — multi-region signing

SigV4a is required for services with multi-region endpoints, most notably S3 Multi-Region Access Points (MRAP). A SigV4a signature is valid across all AWS regions, unlike standard SigV4 which is region-specific.
You must install and import a SigV4a implementation before using services that require it. If neither implementation is loaded, you will see the error: Neither CRT nor JS SigV4a implementation is available.

Choosing an implementation

@aws-sdk/signature-v4a

Pure JavaScript implementation. Works in both Node.js and browsers. Larger bundle size — evaluate whether your use case requires SigV4a in the browser before adding this dependency.

@aws-sdk/signature-v4-crt

AWS Common Runtime (CRT) native binding. Node.js only. Better performance. Required for S3 MRAP and S3 Object Integrity with CRC checksums.

JS implementation (@aws-sdk/signature-v4a)

npm install @aws-sdk/signature-v4a
import "@aws-sdk/signature-v4a"; // Side-effect import registers the implementation

import { S3Client } from "@aws-sdk/client-s3";

const client = new S3Client({
  region: "us-east-1",
  // No additional config needed — the import enables SigV4a automatically
});

// Use with an S3 MRAP ARN
const command = new GetObjectCommand({
  Bucket: "arn:aws:s3::123456789012:accesspoint/mfzwi23gnjvgw.mrap",
  Key: "my-object",
});

await client.send(command);

CRT implementation (@aws-sdk/signature-v4-crt)

npm install @aws-sdk/signature-v4-crt
import "@aws-sdk/signature-v4-crt"; // Side-effect import registers the CRT implementation

import { S3Client } from "@aws-sdk/client-s3";

const client = new S3Client({ region: "us-east-1" });

// The CRT implementation is now active for multi-region requests
Only the import statement is needed. The implementation self-registers with @aws-sdk/signature-v4-multi-region. When both @aws-sdk/signature-v4-crt and @aws-sdk/signature-v4a are installed, the CRT version takes precedence.

authSchemePreference for explicit SigV4a

If a service supports both sigv4 and sigv4a, you can express a preference at the client level:
import "@aws-sdk/signature-v4a";
import { S3Client } from "@aws-sdk/client-s3";

const client = new S3Client({
  region: "us-east-1",
  authSchemePreference: ["sigv4a", "sigv4"],
});

sigv4aSigningRegionSet

Override the signing region set for SigV4a requests (default is ["*"]):
const client = new S3Client({
  region: "us-east-1",
  sigv4aSigningRegionSet: ["us-west-1", "us-west-2"],
});
Values other than ["*"] have limited service support. This configuration is rarely needed.

Services requiring SigV4a

Service / FeaturePackage
S3 Multi-Region Access Points (MRAP)@aws-sdk/signature-v4-crt or @aws-sdk/signature-v4a
S3 Object Integrity (CRC checksums)@aws-sdk/signature-v4-crt
CloudFront KeyValueStore@aws-sdk/signature-v4-crt
S3 CRC64-NVME checksums (optional perf)@aws-sdk/crc64-nvme-crt

Build docs developers (and LLMs) love