a7-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. API7 EE 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 the database. |
Step-by-Step: Enable hmac-auth on a Route
1. Create a consumer
a7 consumer create -g default -f - <<'EOF'
{
"username": "alice"
}
EOF
2. Add hmac-auth credential
curl -k "https://$(a7 context current -o json | jq -r .server):7443/apisix/admin/consumers/alice/credentials" \
-X PUT \
-H "X-API-KEY: $(a7 context current -o json | jq -r .token)" \
-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
a7 route create -g default -f - <<'EOF'
{
"id": "hmac-protected",
"uri": "/api/*",
"plugins": {
"hmac-auth": {}
},
"upstream": {
"type": "roundrobin",
"nodes": [{"host": "backend", "port": 8080, "weight": 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. API7 EE
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"
gateway_groups:
- name: default
consumers:
- username: alice
routes:
- id: hmac-protected
uri: /api/*
plugins:
hmac-auth: {}
upstream:
type: roundrobin
nodes:
- host: backend
port: 8080
weight: 1
Note: Consumer credentials (key_id/secret_key) must be created separately via the Admin API;
a7 config syncmanages the consumer resource but credentials are sub-resources.
This page is generated from a7-plugin-hmac-auth/SKILL.md in the api7/a7 repository. Browse all skills on the AI Agent Skills page.