Skip to content
Back to skills

Aws V4 Signing Custom Headers Gcs

ASecurity

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.

  • 265 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 3, 2026
testingrustgobashawsapi

Works with

  • claude code
  • api

Security analysis

A100/100

Scanned September 3, 2026

npx -y skills add divinevideo/divine-mobile --skill aws-v4-signing-custom-headers-gcs --agent claude-code

Installs 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 with every re-scan.

Security grade badge for Aws V4 Signing Custom Headers Gcs
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/divinevideo-aws-v4-signing-custom-headers-gcs-divine-mobile/badge)](https://www.skillsdirectory.com/skills/divinevideo-aws-v4-signing-custom-headers-gcs-divine-mobile)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
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

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.