hmac-auth
Authenticates requests by verifying an HMAC signature over a canonical signing string built from the request. A client proves possession of a shared secret_key by signing and sending the base64 signature alongside the access_key that names the credential. Place it early in the request pipeline, before the upstream node.
Configuration
| Key | Type | Default | Description |
|---|---|---|---|
use_consumers | boolean | false | Resolve the presented access_key against the gateway's consumers: section (their hmac-auth: {access_key, secret_key} credentials) and attach the matched consumer. |
access_key | string | unset | Inline single-credential key id. |
secret_key | string | required with access_key | The secret paired with the inline access_key. |
algorithm | string | hmac-sha256 | One of hmac-sha1, hmac-sha256, hmac-sha512. |
clock_skew | integer (s) | 300 | Maximum allowed drift between the Date header and now; 0 disables the check. |
signed_headers | array of strings | unset | Headers the client must have included in its signature; a request omitting any is rejected. |
keep_headers | boolean | false | Keep the X-HMAC-* proof headers when proxying (they are stripped by default). |
hide_credentials | boolean | false | Strip the Authorization header before proxying upstream. |
anonymous_consumer | string | unset | Consumer name attached when no credential matches, instead of rejecting. |
realm | string | hmac | Realm advertised in the WWW-Authenticate challenge on rejection. |
At least one of access_key (+secret_key) / use_consumers must be provided, otherwise policy compilation fails.
- id: auth
type: hmac-auth
config:
use_consumers: true
algorithm: hmac-sha256
clock_skew: 300
signed_headers: [date]
Consumers declare their credential under hmac-auth:
consumers:
- name: alice
credentials:
hmac-auth: { access_key: alice-ak, secret_key: alice-sk }
Wire format
Signature parameters are read from either an Authorization header:
Authorization: Signature keyId="alice-ak",algorithm="hmac-sha256",headers="date @request-target",signature="<base64>"
(keyId is the featherbit access_key), or the discrete headers X-HMAC-ACCESS-KEY, X-HMAC-ALGORITHM, X-HMAC-SIGNED-HEADERS (space-separated), and X-HMAC-SIGNATURE. The Date header (RFC 1123 / GMT) carries the timestamp checked against clock_skew.
Signing string
The access key on the first line, then one line per signed header, with a trailing newline:
<access_key>\n
<h1>: <value1>\n
<h2>: <value2>\n
The pseudo-header @request-target is rendered as <METHOD> <request-uri> instead of a header lookup. signature = base64(HMAC(secret_key, signing_string)).
Behavior
The plugin extracts the signature parameters, enforces the algorithm/clock_skew/required signed_headers, then resolves the credential in order:
- Inline — if the presented
access_keymatches the configured one, the signature is verified with the inlinesecret_key. - Consumer store (when
use_consumers: true) — theaccess_keyis looked up against thehmac-authconsumer credentials and the signature verified with that consumer'ssecret_key. On success the consumer identity is attached (consumer.*keys incontext.messageplusX-Consumer-*headers). - Anonymous fallback (when
anonymous_consumeris set) — if no credential is presented or matched, the named consumer is attached instead of rejecting.
On success the context passes through the success port; the X-HMAC-* proof headers are stripped unless keep_headers is set, and the Authorization header is stripped when hide_credentials is set.
On a missing/invalid signature, unknown access key, stale Date, or a missing required signed header, the plugin routes through the error port:
context.response.status_code=401- Body:
{"error": "unauthorized", "message": "<reason>"}withcontent-type: application/json WWW-Authenticate: hmac realm="<realm>"challenge header- Error code appended to
context.errors:HMAC_INVALID
Behavior notes
- Consumer credentials use the field names
access_key/secret_key; featherbit'shmac-authconsumer index is keyed onaccess_key. - A single
algorithmis accepted per node, not a list of allowed algorithms; the client's declared algorithm must match it. @request-target's request URI is reconstructed from the parsed path plus a sortedkey=valuequery string (original query byte order is not retained), so a client signing@request-targetmust canonicalise its query the same way.- Only the RFC 1123 (
Sun, 06 Nov 1994 08:49:37 GMT)Dateformat is parsed for clock-skew checks. - Request-body digest validation (
validate_request_body) is not implemented.