ZatcaX
Home Documentation Authentication & Security

Authentication & Security

The SDK authenticates each request with an HMAC signature, client identity, and authorized domain.

How request signing works

  1. The SDK serializes array payloads with JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES.
  2. It signs the exact raw request body with hash_hmac('sha256', $body, $clientSecret).
  3. The hex signature is sent as X-Signature.
  4. The server resolves X-Client-Id, validates the signature, and checks X-Client-Domain against the client's allowlist.
use ZatcaX\SDK\Http\RequestSigner;

$rawJson = json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$signature = RequestSigner::sign($rawJson, $clientSecret);
Do not re-encode the payload after signing. Any byte-level change produces a different HMAC.

Headers generated by ZatcaClient

HeaderValueWhen sent
Content-Typeapplication/jsonAlways
Acceptapplication/jsonAlways
X-SignatureHMAC-SHA256 hex digestAlways, including GET requests signed with an empty body
X-Client-IdConfigured client IDWhen a client ID is configured
X-Client-DomainConfigured or detected hostWhen a domain is available
Originhttps://{domain}Alongside the client domain

Domain allowlisting

The owner dashboard can restrict a client to one or more hosts. Exact hosts, wildcard subdomains such as *.example.com, and local aliases are supported by the server. A rejected domain produces HTTP 403 and ZatcaDomainUnauthorizedException.

Operational security checklist

  • Store credentials in environment variables or a secrets manager.
  • Never send the API secret to browser code, mobile clients, logs, or exception pages.
  • Use HTTPS and keep SSL peer verification enabled in production.
  • Restrict allowed domains and rotate the API secret after suspected exposure.
  • Use a separate portal password; it is not the HMAC client secret.
  • Do not log certificate private keys, OTP values, or authorization tokens.