mediumFoundationSymptom-first#s3#presigned-url#expiry#upload

S3 presigned URL expired or generated wrong

Browser upload/download fails with AccessDenied immediately

Likely source:configuration

Focused incident mode — strips away everything but this runbook.

Symptoms

  • Browser upload/download fails with AccessDenied immediately
  • Presigned links work for seconds then die
  • Temporal S3 failures match 'expired in the middle of a big upload'

Evidence to grab

Collect these artifacts before you change anything — they prove (or rule out) each cause.

  • Reproduce the signing

    aws s3 presign s3://<BUCKET>/<KEY> --expires-in <SECONDS>
  • Bucket region

    aws s3api get-bucket-location --bucket <BUCKET>

Diagnostic flow

Run the steps in order, marking each claim confirmed or refuted. The evidence you gather feeds the ranked causes below.

Guided decision tree is ready.

Steps with commands, expected output, and pass/fail branches.

Ranked root causes

Evidence checklist

  • Large file uploads fail midway
  • expires-in is seconds-to-minutes by design

Confirm before fixing

aws s3 presign s3://<BUCKET>/<KEY> --expires-in 60
READ

Prove the short window on a test object

Fix

aws s3 presign s3://<BUCKET>/<KEY> --expires-in 3600
CHANGE

Generate a longer-lived URL for slow clients (then shorten once the client is fixed)

Resolution runbook

Apply from top to bottom after the cause is confirmed. Review every command before running it — risk tags are shown on each.

1
aws s3 presign s3://<BUCKET>/<KEY> --expires-in 900
CHANGE

Regenerate with a sane window

2
aws s3api get-bucket-location --bucket <BUCKET>
READ

Confirm region for SigV4

3
curl -v -I '<PRESIGNED-URL>'
READ

Exercise the exact URL from the failing client

Expected: A 200 (or a fresh AccessDenied naming the mismatch)

Prevention

  • Size expires-in for the slowest legit client plus a buffer.
  • Sign with the bucket's region explicitly, not the default.
  • Log presign requests client-side so TTL abuse is visible.

Commands marked READ CHANGE DESTRUCTIVE — never run DESTRUCTIVE commands against production data you cannot restore. Copy → verify → execute.