How to sign an AWS API request with SigV4 using curl

You don't need an SDK to sign a request

Since version 7.75.0, curl has an --aws-sigv4 option that computes the AWS Signature Version 4 for you. It's the fastest way to check whether an IAM-protected endpoint works before you write any code.

Check your version first:

`bash

curl --version # needs 7.75.0 or later

`

The basic command

`bash

curl --aws-sigv4 "aws:amz:us-east-1:execute-api" \

--user "$AWS_ACCESS_KEY_ID:$AWS_SECRET_ACCESS_KEY" \

https://abc123.execute-api.us-east-1.amazonaws.com/prod/orders

`

The argument has the form provider1:provider2:region:service:

--user supplies the access key and secret key. curl uses them to sign the request. It doesn't send them as Basic auth.

Examples

Read an S3 object:

`bash

curl --aws-sigv4 "aws:amz:eu-west-1:s3" \

--user "$AWS_ACCESS_KEY_ID:$AWS_SECRET_ACCESS_KEY" \

https://my-bucket.s3.eu-west-1.amazonaws.com/data.json

`

POST JSON to an IAM-authorized API Gateway route:

`bash

curl --aws-sigv4 "aws:amz:us-east-1:execute-api" \

--user "$AWS_ACCESS_KEY_ID:$AWS_SECRET_ACCESS_KEY" \

-H "Content-Type: application/json" \

-d '{"sku":"A-100","qty":2}' \

https://abc123.execute-api.us-east-1.amazonaws.com/prod/orders

`

Use temporary credentials (SSO, an assumed role, or STS): add the session token as a header.

`bash

curl --aws-sigv4 "aws:amz:us-east-1:execute-api" \

--user "$AWS_ACCESS_KEY_ID:$AWS_SECRET_ACCESS_KEY" \

-H "x-amz-security-token: $AWS_SESSION_TOKEN" \

https://abc123.execute-api.us-east-1.amazonaws.com/prod/orders

`

If you use AWS CLI profiles, you can export short-lived credentials into your shell first. The AWS CLI v2 command aws configure export-credentials --format env prints them as environment variables.

Read the response properly

Add -v to see what curl actually sent: the Authorization header, x-amz-date and the signed header list. AWS error bodies tell you what went wrong:

The last distinction saves a lot of time. A 403 whose message names your ARN means authentication worked.

Common pitfalls

1. Hostname used as the service name. The service is execute-api, not abc123.execute-api.

2. Region left at a default. The region must match the endpoint. Custom domains don't show it, so look it up.

3. --user mixed with other auth. --aws-sigv4 overrides the other auth types, so drop --basic, --digest or an Authorization header you added by hand.

4. Secrets in shell history. Use environment variables rather than pasting keys inline.

5. Clock skew. SigV4 includes a timestamp. If your machine's clock is badly off, valid credentials still get rejected.

6. Old curl. Some distributions or containers ship versions older than 7.75.0, and the option simply won't exist.

When curl isn't enough

I built Presign Pad for this: Sign an AWS request. See exactly why it fails. It runs in your browser and the free part works today.

Try it