Credentials and unique headers
The protocol identifier is g24-hmac-sha256-v2. Obtain the audience, SSP ID, key ID, and secret through an agreed secure channel. The secret must be canonical standard Base64 with padding, decoding to exactly 32 bytes and re-encoding to the same text. HMAC uses those decoded bytes, not the Base64 text as its key.
| Header | Format |
|---|---|
X-G24-Key-Id |
1–64 ASCII letters, digits, or ._- |
X-G24-Timestamp |
Decimal Unix milliseconds, at most 16 digits, no leading zero except the value 0 |
X-G24-Nonce |
A random 16-byte value encoded as 32 lowercase hexadecimal characters |
X-G24-Signature |
Full HMAC-SHA256 encoded as 64 lowercase hexadecimal characters |
Each header must occur exactly once. Duplicate headers, comma-joined values, arrays, and surrounding whitespace are not accepted or trimmed. Audience is the agreed configured value, containing 1–64 safe ASCII characters; it is not inferred from Host or forwarding headers. SSP ID allows the same characters as key ID, up to 128 bytes.
Eight-field canonical message
Join the following UTF-8 fields in this exact order with a single LF (\n) between fields and no trailing LF. Do not use CRLF or add blank lines.
g24-hmac-sha256-v2
audience
ssp_id
POST
request_path
key_id
timestamp_ms
nonce
request_path is the actual origin-form path, for example /openrtb/ssp-a. It contains no hostname, scheme, query, or fragment and must not be re-encoded. The service path is at most 512 bytes, with identities conforming to the rules in SSP integration.
signature = lowercase_hex(HMAC_SHA256(base64_decode(secret), canonical_utf8))
There are eight fields including the protocol identifier. The body, scheme, Host, Content-Length, and response are not signed. The example signer accepts no body and performs no network requests.
Time window and nonce
The server accepts timestamps in [effective_now - 30000, effective_now + 5000] milliseconds, inclusive at both ends: up to 30 seconds old or 5 seconds ahead. This uses the server’s effective clock. Synchronize your client clock; do not cache pre-signed requests for later delivery.
Generate a fresh random nonce for each sending attempt. Deduplication covers SSP ID and nonce, excluding key ID. Rotating keys does not permit reuse of a still-recorded nonce for that SSP. A nonce can be registered after authentication even if subsequent body validation fails. Expired records awaiting cleanup may still be conservatively rejected.
Replay prevention guarantees registration uniqueness only within one process. It does not guarantee deduplication across nodes or process restarts. Clock anomalies or authentication resource exhaustion fail closed and may return 503; do not bypass authentication.
Key rotation
The current key and at most one previous key can be accepted during an agreed overlap. The previous key has an absolute expiry timestamp in milliseconds and is rejected when effective server time reaches or exceeds that timestamp. Reloading does not extend it. Confirm the new key is available, switch the sender, and stop using the old key before expiry. A public example cannot verify production credential activation.
Do not put secrets, complete authentication headers, or user-bearing bodies in logs, tickets, screenshots, Git, or web pages. The example reads real inputs from the environment and rejects command-line arguments for secrets. Environment variables are not a secret-management system and still require a controlled execution environment.
Security boundary and test vector
Metadata HMAC does not establish body origin, integrity, or confidentiality. On a cleartext link, an interceptor could keep valid signed metadata, replace the unsigned body, and submit first. Process-local deduplication only rejects the later duplicate. Agree TLS or trusted-network requirements separately according to risk.
Download the signing script and public fixed vector. The vector key is 32 public bytes of 0x11, not a usable credential. See examples for execution and responses for failures.
Protocol and implementation checked: 2026-09-21.