How Auth Works
Every Eko API request is authenticated with a static key plus a per-request HMAC signature. Nothing secret ever travels on the wire in plain form.
The two keys
| Key | Where it comes from | How it's used |
|---|---|---|
| Access Key | Shared once, kept server-side only | Never sent in a request; used to compute the secret-key |
| Developer Key | UAT key from your dashboard; production key after KYC | Sent as the developer_key header |
Request headers
| Header | Required | Description |
|---|---|---|
developer_key | yes | Your static developer key. |
secret-key | yes | Per-request HMAC signature (see below). |
secret-key-timestamp | yes | Current time in milliseconds since the UNIX epoch. |
content-type | yes | application/json |
Computing the secret-key
The signature binds the request to a timestamp, so it must be generated fresh for every call:
- Base64-encode the
access_key— keep this as a string. - Take the current timestamp in milliseconds, as a string.
- Compute
HMAC-SHA256with the timestamp as the message and that base64 string as the key. - Base64-encode the result — that's the
secret-key.
Send the same timestamp in secret-key-timestamp. A stale or mismatched
timestamp returns 403 Forbidden.
secret-key = base64( HMAC-SHA256( message = timestamp, key = base64(access_key) ) )
Common mistake: the HMAC key is the base64 string
base64(access_key), used as-is. Do not base64-decode it back to raw bytes before signing — that produces a different signature and a403.
Code examples
Sign on your backend — the access_key must never reach a browser. The same
recipe in five languages:
// Backend only. Never expose access_key in a browser.import crypto from "node:crypto";const accessKey = process.env.EKO_ACCESS_KEY;const timestamp = Date.now().toString();const encodedKey = Buffer.from(accessKey).toString("base64");const secretKey = crypto.createHmac("sha256", encodedKey).update(timestamp).digest("base64");// headers: { developer_key, "secret-key": secretKey, "secret-key-timestamp": timestamp }
Why sign client-side
Because the access_key never leaves your server, a leaked request can't be
replayed or forged — the timestamp-bound signature is only valid for a short
window. When using the in-page Test Request modal, signing happens locally
in your browser with the UAT credentials you supply: your access_key is used
only to compute the signature and is stripped before the request is sent — it is
never transmitted.