Add custom metadata headers (x-amz-meta-*) to AWS v4 signed requests for GCS S3-compatible API. Use when: (1) Adding custom metadata to GCS uploads via S3 API, (2) Getting signature mismatch errors after adding new headers, (3) x-amz-meta-* headers being ignored or causing 403 errors. Custom headers MUST be included in canonical headers and signed headers list.
Scanned 9/3/2026
Install to Claude Code
npx -y skills add divinevideo/divine-mobile --skill aws-v4-signing-custom-headers-gcs --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Aws V4 Signing Custom Headers Gcs?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/divinevideo-aws-v4-signing-custom-headers-gcs-divine-mobile)More formats (shields.io, HTML) on the badges page.
---
name: aws-v4-signing-custom-headers-gcs
description: |
Add custom metadata headers (x-amz-meta-*) to AWS v4 signed requests for GCS S3-compatible
API. Use when: (1) Adding custom metadata to GCS uploads via S3 API, (2) Getting signature
mismatch errors after adding new headers, (3) x-amz-meta-* headers being ignored or causing
403 errors. Custom headers MUST be included in canonical headers and signed headers list.
author: Claude Code
version: 1.0.0
date: 2026-01-20
---
# AWS v4 Signing with Custom Metadata Headers for GCS
## Problem
When adding custom metadata headers (`x-amz-meta-*`) to GCS S3-compatible API requests,
the requests fail with signature mismatch errors. The headers must be properly included
in the AWS v4 signature calculation.
## Context / Trigger Conditions
- Using GCS S3-compatible XML API (not the native JSON API)
- Adding `x-amz-meta-*` headers for object metadata
- Error: "SignatureDoesNotMatch" or 403 Forbidden after adding headers
- Headers work with unsigned requests but fail with AWS v4 signing
- HMAC credentials configured for GCS interoperability
## Solution
Custom headers must be included in **both** the canonical headers and the signed headers list,
sorted **alphabetically**:
### 1. Canonical Headers (alphabetically sorted)
```rust
let canonical_headers = format!(
"host:{}\nx-amz-content-sha256:{}\nx-amz-date:{}\nx-amz-meta-owner:{}\n",
host, payload_hash, amz_date, owner // Note: alphabetical order!
);
```
### 2. Signed Headers List
```rust
let signed_headers = "host;x-amz-content-sha256;x-amz-date;x-amz-meta-owner";
```
### 3. Complete Example (Rust)
```rust
fn sign_request_with_owner(
req: &mut Request,
config: &GCSConfig,
payload_hash: Option<String>,
owner: &str
) -> Result<()> {
// Set headers first
req.set_header("x-amz-date", &amz_date);
req.set_header("x-amz-content-sha256", &payload_hash);
req.set_header("x-amz-meta-owner", owner); // Custom metadata
// Canonical headers - MUST be alphabetically sorted
let signed_headers = "host;x-amz-content-sha256;x-amz-date;x-amz-meta-owner";
let canonical_headers = format!(
"host:{}\nx-amz-content-sha256:{}\nx-amz-date:{}\nx-amz-meta-owner:{}\n",
host, payload_hash, amz_date, owner
);
// Rest of AWS v4 signing...
let canonical_request = format!(
"{}\n{}\n{}\n{}\n{}\n{}",
method, uri, query, canonical_headers, signed_headers, payload_hash
);
// Sign and add Authorization header...
}
```
## Verification
After uploading, verify metadata is present:
```bash
gsutil stat gs://bucket/object-name
# Should show:
# Metadata:
# owner: <value>
```
Or via S3 API:
```bash
aws s3api head-object --bucket bucket --key object-name --endpoint-url https://storage.googleapis.com
```
## Example
**Before (broken)** - header not in signature:
```rust
let signed_headers = "host;x-amz-content-sha256;x-amz-date"; // Missing x-amz-meta-owner
req.set_header("x-amz-meta-owner", owner); // Header added but not signed
// Result: 403 SignatureDoesNotMatch
```
**After (working)** - header properly signed:
```rust
let signed_headers = "host;x-amz-content-sha256;x-amz-date;x-amz-meta-owner"; // Included!
req.set_header("x-amz-meta-owner", owner);
// Include in canonical_headers too
// Result: 200 OK, metadata visible in GCS
```
## Notes
- Header names are case-insensitive but conventionally lowercase in canonical form
- The semicolon-separated signed headers list must match the newline-separated canonical headers
- For GCS, the metadata appears as `Metadata: key: value` in gsutil stat output
- When using the native GCS JSON API, use the `metadata` object field instead
- Multiple custom headers can be added - just ensure all are in canonical/signed lists
## References
- AWS Signature Version 4: https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-header-based-auth.html
- GCS S3 Interoperability: https://cloud.google.com/storage/docs/interoperability
- GCS Object Metadata: https://cloud.google.com/storage/docs/metadata
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!