FREE TOOL

SigV4 / Presigned URL Debugger

Paste an S3 presigned URL or a SignatureDoesNotMatch error and see its parts - Region, service, credential scope, signed headers, X-Amz-Date, expiry and time left - and why AWS rejects the signature.

  • Your data never leaves your browser: everything is calculated by JavaScript on this page, not on a server.
  • Nothing you enter is uploaded, processed on a server or stored. Check it in your browser's developer tools (Network tab).
  • Once the page has loaded, the tool works without an internet connection.

Presigned URL or error

A presigned URL, a request with its Authorization header, or the error AWS answered - S3's XML, another service's JSON or the CLI's message. Paste the URL and the error together to compare them. It is read here and never leaves your browser.

See the parts ↓
S3 presigned URLs and request signing are AWS Developer Associate topicsTry free DVA-C02 practice questions with answers and explanations.DVA-C02 questions →

The parts of an S3 presigned URL

A presigned URL is a request signed with Signature Version 4 (SigV4) in advance: the signature and everything it needs travel in the query string, so whoever has the URL can make that one request without AWS credentials of their own - with the permissions of whoever signed it.

ParameterWhat it holds
X-Amz-AlgorithmAWS4-HMAC-SHA256 for SigV4
X-Amz-CredentialThe access key ID and the credential scope: AKID/20260115/eu-west-1/s3/aws4_request - date, Region, service
X-Amz-DateWhen it was signed, in UTC (20260115T090000Z)
X-Amz-ExpiresSeconds it stays valid after X-Amz-Date, up to 604800 (7 days)
X-Amz-SignedHeadersThe headers the request must send as signed - at least host
X-Amz-Security-TokenThe session token, when temporary credentials signed it
X-Amz-SignatureThe signature itself: an HMAC-SHA256 only the secret key can produce or check

The signature covers a canonical request: the HTTP method, the path, the sorted query string without the signature, the signed headers with their values, and the payload hash - UNSIGNED-PAYLOAD for a presigned URL. Change any of it, and the URL stops working.

Why AWS answers SignatureDoesNotMatch

AWS rebuilds the canonical request from what it received, signs it with the secret key of the access key ID in the request and compares. S3's error response shows its StringToSign and CanonicalRequest; other services put them in the message. The debugger lays them out, so you can compare them with what your client signed - the AWS SDKs log theirs at debug level.

SymptomMost common cause
A browser or fetch upload to a presigned PUT URL fails, the same file works with curlThe URL signs content-type, and the browser sends another value or adds a charset
Uploads through presigned URLs started failing in 2025 after an SDK updateThe SDK's default checksum is signed into the URL (x-amz-checksum-crc32): presign with requestChecksumCalculation: "WHEN_REQUIRED"
A PUT to a URL that works in the browser failsIt was presigned for GetObject; an upload needs PutObject
Files with spaces, + or non-ASCII characters in the key failThe URL was encoded again, or a + was read as a space, after signing
Every request fails, even from the CLIThe secret access key does not belong to the access key ID
"the region 'us-east-1' is wrong; expecting 'eu-west-1'"The client signed for another Region than the bucket's

How long a presigned URL lasts

X-Amz-Date plus X-Amz-Expires, at most 7 days - and never longer than the credentials that signed it. Signed with temporary credentials (an access key ID starting with ASIA, with an X-Amz-Security-Token), the URL dies with them: a Lambda function's or an EC2 instance's role credentials last hours, an assumed role's session 1 hour by default, and a URL made in the S3 console at most 12 hours. For a URL that lasts the full 7 days, sign with an IAM user's long-term access key.

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

// The bucket's Region, and no checksum of an empty body signed into upload URLs.
const s3 = new S3Client({ region: "eu-west-1", requestChecksumCalculation: "WHEN_REQUIRED" });

const url = await getSignedUrl(s3, new PutObjectCommand({
  Bucket: "example-bucket",
  Key: "uploads/report.pdf",
  ContentType: "application/pdf", // the upload must send exactly this Content-Type
}), { expiresIn: 900 });

Frequently asked questions

Is it safe to paste a presigned URL here?

The URL is read in your browser: nothing you paste is uploaded, processed on a server or stored. The page only counts that the debugger was used and which cause it named first, never the URL or the error. A presigned URL still grants access until it expires, so paste only into pages you trust - and prefer an expired one.

Can it check whether the signature is right?

No - that needs the secret access key, which neither the URL nor the error contains, and which should never be pasted into a web page. It reads everything around the signature, which is where the cause almost always is.

Why does my presigned URL work in the browser but not from my app, or the other way round?

The two send different requests: another method (a GET from the address bar, a PUT from the app), other headers (Content-Type, a charset, x-amz-* headers), or a URL encoded again by the app's HTTP library. Paste the URL with the error response the failing side got, and compare the canonical request AWS shows with what was signed.

What is SigV4a?

A variant of SigV4 with an asymmetric (ECDSA) signature valid in a set of Regions, used by S3 Multi-Region Access Points. Its algorithm is AWS4-ECDSA-P256-SHA256, its credential scope has no Region, and X-Amz-Region-Set lists the Regions instead.

References

AWS Signature Version 4 for API requests
Troubleshoot Signature Version 4 signed requests
Authenticating requests: using query parameters (S3)
Sharing objects with presigned URLs
Data integrity protections for Amazon S3 (AWS SDKs)