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
Replace <gateway-group-id> with the ID returned by
a7 gateway-group list -o json.
1. Create a consumer
a7 consumer create -g <gateway-group-id> -f - <<'EOF'
{
"username": "alice"
}
EOF
2. Add hmac-auth credential
a7 credential create cred-alice-hmac -g <gateway-group-id> \
--consumer alice \
--plugins-json '{"hmac-auth":{"key_id":"alice-key","secret_key":"alice-secret-key-value"}}'
3. Create a service and route with hmac-auth enabled
a7 service create -g <gateway-group-id> -f - <<'EOF'
{
"id": "hmac-protected-service",
"name": "HMAC protected service",
"upstream": {
"type": "roundrobin",
"nodes": [{"host": "backend", "port": 8080, "weight": 1}]
}
}
EOF
a7 route create -g <gateway-group-id> -f - <<'EOF'
{
"id": "hmac-protected",
"paths": ["/api/*"],
"service_id": "hmac-protected-service",
"plugins": {
"hmac-auth": {}
}
}
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
Save the following as hmac-auth.yaml:
version: "1"
services:
- id: hmac-protected-service
name: HMAC protected service
upstream:
type: roundrobin
nodes:
- host: backend
port: 8080
weight: 1
routes:
- id: hmac-protected
name: HMAC protected route
paths:
- /api/*
service_id: hmac-protected-service
plugins:
hmac-auth: {}
Validate and apply this partial configuration to the target gateway group:
a7 config validate -f hmac-auth.yaml
a7 config sync -g <gateway-group-id> -f hmac-auth.yaml --delete=false
Note: Create the consumer and credential separately with
a7 consumer createanda7 credential create. Config Sync manages only the service and route in this example. Disabling deletion preserves other resources that are not included in this partial configuration.
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.