# API authentication and request signing: tokens, HMAC, OAuth, mTLS

> HTTP APIs authenticate callers with a credential in the Authorization header — an API key or bearer token (Authorization: Bearer <token>). Stronger schemes sign each request with HMAC over a canonical request so credentials are never replayable, use OAuth 2.0 client-credentials for machine-to-machine tokens, and add mutual TLS where transport-level identity is required.

- Canonical URL: https://www.broadnet.me/reference/api-authentication-and-signing
- Language: en
- Last updated: 2026-07-19
- Publisher: BroadNet (https://www.broadnet.me)

The standard ways to authenticate an HTTP messaging API: bearer tokens and API keys in the Authorization header, HMAC request signing over a canonical request, key scoping and rotation, mutual TLS, and OAuth 2.0 client-credentials for machine-to-machine access.

## Bearer tokens and API keys

The simplest authentication is a bearer credential: the client presents a secret token in the Authorization header and the server validates it. RFC 9110 defines the Authorization header and its scheme prefix, and OAuth 2.0 defines the Bearer scheme — Authorization: Bearer <token> — whose defining property is that mere possession grants access, so the token must travel only over TLS and never appear in a URL, log or error message. An API key is the same idea with a longer-lived, often non-expiring secret. Because a bearer credential is replayable if captured, it is the baseline rather than the ceiling: it is easy to integrate and perfectly adequate over TLS for most traffic, but high-value operations often layer request signing on top.

*Bearer token on a request*

```http
POST /v1/messages HTTP/1.1
Host: api.example
Authorization: Bearer eyJhbGciOi...  # secret; TLS only, never logged
Content-Type: application/json
```

## HMAC request signing

Request signing raises the bar: instead of sending the secret, the client uses it to compute an HMAC over a canonical representation of the request, and sends only the signature. The server, holding the same secret, recomputes the signature and compares. Because the signature covers the method, path, key headers and a hash of the body, a captured signature cannot be replayed against a different request, and because the secret itself never leaves the client, capturing one request does not reveal the credential. The construction mirrors webhook signing in the other direction and is the same HMAC-SHA256 (RFC 2104 / RFC 6234) primitive. The delicate part is the canonical request: both sides must agree byte-for-byte on how to serialise it, or every signature mismatches.

*Canonical request and signature*

```text
canonical =
  HTTP-METHOD  + '\n' +
  URI-PATH     + '\n' +
  SORTED-QUERY + '\n' +
  SIGNED-HEADERS (name:value, sorted, '\n'-joined) + '\n' +
  HEX(SHA256(raw_body))

signature = HMAC_SHA256(secret, canonical)

Authorization: SIGV1 Credential=<key-id>,
  SignedHeaders=host;x-date;content-type, Signature=<hex>
```

## Signed headers and the request date

Two details make request signing sound. First, an explicit SignedHeaders list names exactly which headers are covered, so an intermediary that adds or reorders unrelated headers does not invalidate the signature while any header the client chose to sign is tamper-evident. Second, a request date (a signed X-Date or the standard Date header) is part of the canonical request and is checked against the server clock within a tolerance — the same replay defence as webhooks, applied to inbound API calls. Together they mean a signed request is bound to its exact content, its declared headers and a narrow time window; a captured request is useless a few minutes later.

## Key scoping and rotation

Credentials should carry the least privilege that works and be rotatable without downtime. Scoping attaches permissions to a key — which operations it may call, from which source, at what rate — so a key that only sends messages cannot read account settings, and a leaked key's blast radius is bounded. Rotation follows the overlapping-keys pattern: issue a new credential, run both in parallel while clients migrate, then revoke the old one, so nothing breaks mid-flight. Keys should be identifiable (a non-secret key id travels in the request so the server knows which secret to verify against and which scope to apply) and revocable individually, so one compromised integration is cut off without disturbing the rest.

*Authentication schemes compared*

| Scheme | What travels | Strength / use |
|---|---|---|
| API key | Long-lived secret in Authorization | Simple baseline; TLS-only; easy to leak in logs |
| Bearer token (OAuth 2.0) | Short-lived access token | Expiring, scoped; refreshed via token endpoint |
| HMAC request signing | Signature (secret stays local) | Replay-resistant, tamper-evident per request |
| mTLS | Client X.509 certificate | Transport-level identity; strong but heavier ops |

## Mutual TLS

Mutual TLS authenticates the client at the transport layer: in addition to the server presenting a certificate, the client presents its own X.509 certificate during the handshake, and the server admits only connections whose certificate chains to a trusted CA and matches an enrolled identity. This binds API identity to a cryptographic key managed at the connection level rather than a bearer secret in a header, which is attractive for high-assurance machine-to-machine links and for pinning a partner to specific certificates. The cost is operational — certificate issuance, distribution, rotation and revocation — so mTLS is typically reserved for the most sensitive integrations, often combined with a bearer token or signature for fine-grained authorization on top of the coarse transport identity.

## OAuth 2.0 client-credentials for M2M

For server-to-server integrations with no end user present, OAuth 2.0 (RFC 6749) defines the client-credentials grant. The client authenticates to a token endpoint with its client_id and client_secret (or a client certificate) and receives a short-lived access token, which it then presents as a bearer token on API calls until it expires and is refreshed. The advantage over a static API key is lifetime and scope: tokens are short-lived, so a captured token expires quickly, and they carry explicit scopes, so a token minted for sending cannot be used to administer the account. This is the standard pattern for machine-to-machine API access and the mechanism BroadNet's authentication guide documents concretely for its endpoints.

*OAuth 2.0 client-credentials token request (RFC 6749)*

```http
POST /oauth/token HTTP/1.1
Host: auth.example
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials
&client_id=<id>
&client_secret=<secret>
&scope=messages:send

-> { "access_token": "...", "token_type": "Bearer",
     "expires_in": 3600, "scope": "messages:send" }
```

## Frequently asked questions

### What is the difference between a bearer token and HMAC signing?

A bearer token is sent on every request and grants access by possession, so a captured token is replayable until it expires. HMAC signing never sends the secret — the client signs a canonical request and sends only the signature, so a captured request cannot be replayed against a different call and the credential itself is never exposed.

### Why does HMAC signing need a canonical request?

Because both sides must compute the identical string to get matching signatures. The canonical request fixes exactly how the method, path, sorted query, signed headers and body hash are serialised. Any disagreement — header order, whitespace, a re-encoded body — produces a different signature and the request is rejected even though nothing was tampered with.

### What does OAuth 2.0 client-credentials give me over an API key?

Short lifetime and explicit scope. The client exchanges its credentials at a token endpoint for a short-lived, scoped access token (RFC 6749). A captured token expires quickly, and a token minted for sending cannot administer the account. A static API key, by contrast, is long-lived and typically broad.

### How should API keys be scoped and rotated?

Grant least privilege — restrict each key to the operations, sources and rate it needs — so a leak is contained. Rotate with overlapping keys: issue a new credential, run both in parallel while clients migrate, then revoke the old one. Keys should carry a non-secret key id and be individually revocable so one compromised integration is cut off alone.

### When is mutual TLS worth the operational cost?

When you need transport-level cryptographic identity for a high-assurance machine-to-machine link, or to pin a partner to specific certificates. mTLS admits only clients whose X.509 certificate chains to a trusted CA. It is heavier to run — issuance, rotation, revocation — so it is usually reserved for the most sensitive integrations, often layered with a token or signature for authorization.

### Why must bearer credentials never appear in a URL or log?

Because a bearer credential grants access by possession alone. URLs are logged by proxies, stored in browser history and leaked via the Referer header, and application logs are widely readable, so a token in any of those is effectively disclosed. Bearer credentials must travel only in the Authorization header over TLS and be scrubbed from logs.

## Sources

- [IETF RFC 6749 — The OAuth 2.0 Authorization Framework](https://datatracker.ietf.org/doc/html/rfc6749)
- [IETF RFC 2104 — HMAC: Keyed-Hashing for Message Authentication](https://datatracker.ietf.org/doc/html/rfc2104)

## Related

- [Webhook signature verification](https://www.broadnet.me/reference/webhook-signature-verification)
- [Idempotency & rate limiting](https://www.broadnet.me/reference/idempotency-and-rate-limiting)
- [REST messaging API design](https://www.broadnet.me/reference/rest-messaging-api-design)
- [API errors & pagination](https://www.broadnet.me/reference/api-errors-and-pagination)
- [BroadNet authentication guide](https://www.broadnet.me/developers/authentication)
