search

Found

info Overview

Build the AWS SigV4 Canonical Request with signed-headers, payload hash, and canonical-request SHA-256 on one screen to debug signature mismatch errors.

📘 How to Use

  1. Enter the HTTP method, URI path, query, headers, and payload
  2. Watch SignedHeaders and the payload SHA-256 update
  3. Compare the Canonical Request text and its SHA-256 against your signer

AWS SigV4 Canonical Request Builder

One key=value per line or joined with &. Empty is fine.

Header names are lowercased, values whitespace-collapsed, then sorted.

Empty for GET/DELETE, paste body for POST/PUT. SHA-256 is computed.

SignedHeaders

host;x-amz-date

Payload SHA-256

e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

Canonical Request

Canonical Request SHA-256

Copied
info

The URI path is percent-encoded once (Amazon S3 style). Other AWS services encode each path segment twice, so paths containing special characters will differ.

Article

AWS SigV4 Canonical Request Builder|See the Intermediate String and Both SHA-256 Hashes

Enter an HTTP method, URI, query, headers, and payload, and this tool assembles the AWS Signature Version 4 Canonical Request, the SignedHeaders list, the payload SHA-256, and the SHA-256 of the canonical request itself. It shows the intermediate string that most SigV4 write-ups skip, so when your SDK throws a signature mismatch you can line up every value on one screen. No backend — paste and read.

💡 About this tool

Every SigV4 signature runs through a Canonical Request before the final Signature ever exists. That canonical request is a strictly formatted string: the method, the normalized URI, the normalized query, the canonical headers block, the SignedHeaders list, and the payload hash, all joined with newlines. The AWS SDKs and boto3 build and hash this internally, but the moment you hand-roll a signer, a single off-by-one character in that string returns SignatureDoesNotMatch — and the error body only ever shows you the final hash, never where the strings diverged.

This builder constructs the canonical request exactly the way SigV4 demands. The URI and query get RFC 3986 percent-encoding (everything except the unreserved set A-Z a-z 0-9 - . _ ~), query pairs sort by key, and header names are lowercased with internal whitespace collapsed before being sorted by name. It emits the canonical request body, SignedHeaders, the payload SHA-256, and the canonical-request SHA-256 together — so you can diff your own signer's output against all four values and pinpoint which normalization step drifted.

It's built for the people writing request signers without the SDK: Lambda@Edge, IoT signing, low-level CloudFront flows — anywhere you need to eyeball each intermediate SigV4 value. Drop in a copy of your real request headers and treat the output as the reference your code should reproduce.

🧐 Frequently Asked Questions

What's the difference between the Canonical Request and the StringToSign? The canonical request is the normalized request string — that's what this tool outputs. The StringToSign is the next stage: it wraps the canonical request's hash with the algorithm name, the date, and the credential scope, and it's what gets HMAC'd with the signing key. This tool stops at the canonical request and its SHA-256.

How are headers normalized? Names are lowercased, values are trimmed and have runs of internal whitespace collapsed to a single space, then the headers sort by name. Duplicate header names are joined with a comma. SignedHeaders is the sorted names joined with semicolons.

What hash does an empty payload produce? The SHA-256 of the empty string: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855. GET and DELETE requests with no body use this value, and the tool shows it by default.

How is the query string sorted? Pairs sort ascending by the percent-encoded key, and ties break on the value. A bare key with no value (key) is treated as key= with an empty value. That ordering is a SigV4 requirement — get it wrong and the signature won't match.

Does anything I enter leave my machine? No. Every input — method, headers, payload included — is processed in your browser, and the SHA-256 is computed locally with the Web Crypto API. You can paste a real request you're trying to sign and nothing is sent to a server.

📚 Why SigV4 normalizes before it signs

The reason SigV4 bothers with a canonical request at all is that one logical request can have many byte representations. The query b=2&a=1 and a=1&b=2 mean the same thing but hash differently, and header casing or stray whitespace can shift in transit. A signature is just a hash of a string, so a one-character difference in representation produces a completely different hash and the verifier rejects it. By forcing both sides through the same fixed normalization — sort the query, lowercase and collapse the headers, percent-encode the URI — SigV4 guarantees the sender and AWS land on the identical string before either one hashes it. The clever part isn't the signing; it's that pinning the request to one canonical form before signing is what makes a stateless verifier possible at all, and it's exactly where hand-written signers tend to break.