skills/moonming/a6/a6-plugin-hmac-auth

a6-plugin-hmac-auth

SKILL.md

a6-plugin-hmac-auth

Overview

The hmac-auth plugin authenticates requests using HMAC (Hash-based Message Authentication Code) signatures. Clients compute an HMAC signature over the request method, path, date, and optional headers/body, then include it in the Authorization header. APISIX recomputes the signature server-side and verifies it matches. This provides request integrity verification without transmitting secrets over the wire.

When to Use

  • Request integrity verification (tamper-proof API calls)
  • Server-to-server authentication where both sides share a secret
  • APIs requiring body integrity validation
  • Environments where tokens or passwords should never appear in requests

Plugin Configuration Reference (Route/Service)

Field Type Required Default Description
allowed_algorithms array No ["hmac-sha1","hmac-sha256","hmac-sha512"] HMAC algorithms allowed
clock_skew integer No 300 Max allowed time difference in seconds between client and server
signed_headers array No — Additional headers required in the HMAC signature
validate_request_body boolean No false Validate request body integrity via SHA-256 digest
hide_credentials boolean No false Remove Authorization header before forwarding upstream
anonymous_consumer string No — Consumer username for unauthenticated requests
realm string No "hmac" Realm in WWW-Authenticate response header

Consumer Credential Reference

Field Type Required Description
key_id string Yes Unique identifier for the consumer
secret_key string Yes Secret key for HMAC computation. Auto-encrypted in etcd.

Step-by-Step: Enable hmac-auth on a Route

1. Create a consumer

a6 consumer create -f - <<'EOF'
{
  "username": "alice"
}
EOF

2. Add hmac-auth credential

curl "$(a6 context current -o json | jq -r .server)/apisix/admin/consumers/alice/credentials" \
  -X PUT \
  -H "X-API-KEY: $(a6 context current -o json | jq -r .api_key)" \
  -d '{
    "id": "cred-alice-hmac",
    "plugins": {
      "hmac-auth": {
        "key_id": "alice-key",
        "secret_key": "alice-secret-key-value"
      }
    }
  }'

3. Create a route with hmac-auth enabled

a6 route create -f - <<'EOF'
{
  "id": "hmac-protected",
  "uri": "/api/*",
  "plugins": {
    "hmac-auth": {}
  },
  "upstream": {
    "type": "roundrobin",
    "nodes": {
      "backend:8080": 1
    }
  }
}
EOF

4. Generate signature and test

The HMAC signature follows the HTTP Signatures draft.

Python example:

import hmac, hashlib, base64
from datetime import datetime, timezone

key_id = "alice-key"
secret_key = b"alice-secret-key-value"
method = "GET"
path = "/api/users"
algorithm = "hmac-sha256"

gmt_time = datetime.now(timezone.utc).strftime('%a, %d %b %Y %H:%M:%S GMT')

signing_string = f"{key_id}\n{method} {path}\ndate: {gmt_time}\n"

signature = base64.b64encode(
    hmac.new(secret_key, signing_string.encode(), hashlib.sha256).digest()
).decode()

# Use these headers in request:
# Date: {gmt_time}
# Authorization: Signature keyId="{key_id}",algorithm="{algorithm}",
#   headers="@request-target date",signature="{signature}"

curl example:

curl -i http://127.0.0.1:9080/api/users \
  -H "Date: $(date -u +'%a, %d %b %Y %H:%M:%S GMT')" \
  -H 'Authorization: Signature keyId="alice-key",algorithm="hmac-sha256",headers="@request-target date",signature="<computed_signature>"'

Authorization Header Format

Signature keyId="{key_id}",algorithm="{algorithm}",headers="{signed_headers}",signature="{signature}"
Component Description
keyId Consumer's key_id value
algorithm One of: hmac-sha1, hmac-sha256, hmac-sha512
headers Space-separated list: @request-target date [additional...]
signature Base64-encoded HMAC signature

Signing String Construction

The signing string is newline-separated:

{key_id}\n
{METHOD} {path}\n
date: {Date header value}\n
{additional-header}: {value}\n
  • First line: the key_id
  • Second line: HTTP method + space + request path
  • Subsequent lines: lowercase header names with values
  • Each line terminated with \n

Common Patterns

Restrict to specific algorithms

{
  "plugins": {
    "hmac-auth": {
      "allowed_algorithms": ["hmac-sha256", "hmac-sha512"]
    }
  }
}

Increase clock skew tolerance

{
  "plugins": {
    "hmac-auth": {
      "clock_skew": 600
    }
  }
}

Allows up to 10 minutes time difference.

Validate request body

{
  "plugins": {
    "hmac-auth": {
      "validate_request_body": true
    }
  }
}

Client must include Digest: SHA-256={base64_sha256_of_body} header. APISIX recomputes the body digest and rejects the request if it does not match.

Require custom headers in signature

{
  "plugins": {
    "hmac-auth": {
      "signed_headers": ["x-custom-header-a", "x-custom-header-b"]
    }
  }
}

Headers Added to Upstream

Header Value
X-Consumer-Username Consumer's username
X-Credential-Identifier Credential ID
X-Consumer-Custom-Id Consumer's labels.custom_id (if set)

Troubleshooting

Symptom Cause Fix
401 signature mismatch Signing string differs from server expectation Verify newline format, header lowercase, key_id first line
401 clock skew Date header too far from server time Sync clocks or increase clock_skew
401 algorithm not allowed Client used algorithm not in allowed_algorithms Add algorithm to allow list or change client
401 body digest mismatch Body changed after digest computed Recompute Digest header from actual body
Signature hard to debug Complex signing string Log the exact signing string client-side and compare

Config Sync Example

version: "1"
consumers:
  - username: alice
routes:
  - id: hmac-protected
    uri: /api/*
    plugins:
      hmac-auth: {}
    upstream_id: my-upstream
upstreams:
  - id: my-upstream
    type: roundrobin
    nodes:
      "backend:8080": 1

Note: Consumer credentials (key_id/secret_key) must be created separately via the Admin API; a6 config sync manages the consumer resource but credentials are sub-resources.

Weekly Installs
1
Repository
moonming/a6
First Seen
7 days ago
Installed on
amp1
cline1
opencode1
cursor1
kimi-cli1
codex1