Skip to content
Quest 07Intermediate14 min

Hand Out a Pass

Sinnoh trainers want to submit their own sprites. Routing every upload through your server wastes bandwidth and Lambda time. A presigned URL lets the browser talk to S3 directly — for one operation, on one key, for a few minutes.

What you'll learn

  • A presigned URL carries a signature made with your credentials; whoever holds it can perform exactly the signed request until it expires.
  • Sign the narrowest request: one method, one key, the content type, and a short expiresIn.
  • SigV4 URLs last at most 7 days, and never longer than the credentials that signed them.

Section 01

How presigning works

Your server builds a normal S3 request — say, PutObject for uploads/trainer-42/sprite.png — and signs it with its own credentials, but puts the signature in the URL's query string instead of a header. No call to AWS happens while signing.

The browser then sends a plain HTTP PUT to that URL. S3 checks the signature, the expiry and the signer's permissions. The browser never sees your credentials, and the URL is useless for any other key or method.

Server: sign an uploadJavaScript
import { PutObjectCommand } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";

const url = await getSignedUrl(
  client,
  new PutObjectCommand({ Bucket, Key: `uploads/${trainerId}/sprite.png`, ContentType: "image/png" }),
  { expiresIn: 300 } // seconds
);
Browser: upload the fileJavaScript
await fetch(url, { method: "PUT", headers: { "Content-Type": "image/png" }, body: file });

Section 02

Expiry

  • expiresIn defaults to 900 seconds (15 minutes). Set it explicitly and keep it short: long enough to finish the upload, no longer.
  • Signature Version 4 caps it at 604,800 seconds (7 days).
  • If the signer used temporary credentials (a Lambda role, for example), the URL stops working when those credentials expire — even if expiresIn is longer.

Section 03

Keep uploads safe

  • Write untrusted uploads under their own prefix (uploads/) and process them before promoting them to sprites/.
  • A presigned PUT can't limit the file size. When you need that, use a presigned POST (@aws-sdk/s3-presigned-post) with a content-length-range condition.
  • Browsers need a CORS rule on the bucket allowing PUT from your site's origin.
  • Anyone who gets the URL can use it. Don't log it, and don't reuse one URL for many users.

Practice

Your turn

Trainers upload their own sprite PNGs straight from the browser. Your server signs a URL for exactly one upload. This code signs the wrong operation and lets the link live for a day — fix both.

Sign a PutObjectCommand with ContentType: "image/png" and expiresIn: 300.
Tab inserts two spaces. Press Escape, then Tab, to leave the editor. Control or Command plus Enter runs the code.
Simulated — no AWS calls

Check

Check your understanding

Quick Quiz · one question, as many tries as you need.

A Lambda function signs a download URL with expiresIn: 604800. Users report the link stops working after a few hours. Why?

Choose one answer.