ar.io Logoar.io Documentation

Verification & Trust Headers

ar.io gateways attach HTTP response headers to every data response. They say whether the data has been verified against the Arweave base layer, whether it has reached finality, and whether the source is trusted. Clients can use them to decide how far to trust a response without relying only on the operator's reputation.

Trust & Verification Headers

Every data response from an ar.io gateway includes the following headers:

HeaderValuesDescription
X-AR-IO-Verifiedtrue / falsetrue only when data is served from local cache and has been verified against the Arweave base layer. Data streamed from network sources is marked false even if the gateway's database indicates prior verification, because the hash cannot be confirmed in-flight during streaming.
X-AR-IO-Stabletrue / falsetrue when the data exists beyond Arweave's maximum fork depth, indicating finality. Once stable, the data cannot be reorganized out of the chain.
X-AR-IO-Trustedtrue / falsetrue when the data was retrieved from a source the operator has configured as trusted (via TRUSTED_GATEWAY_URL or TRUSTED_GATEWAYS_URLS).
Content-Digestsha-256=:base64:SHA-256 hash of the response body in RFC 9530 format. Set on cache hits and HEAD requests. An uncached response of known size up to 2 MiB is buffered and hashed so it carries one too. Larger uncached responses stream without it.
X-AR-IO-Digestbase64url stringThe raw SHA-256 hash of the content in base64url encoding. Set alongside Content-Digest.
ETag"hash"Content hash for HTTP conditional requests (If-None-Match), so a client can get a 304 Not Modified. Treat it as opaque, and read the digest from X-AR-IO-Digest. See the note below for responses served through an ArNS name.
X-AR-IO-Data-Idbase64url stringThe Arweave transaction ID or data item ID of the content being served.
X-AR-IO-HopsnumberThe number of inter-gateway hops the request traversed before reaching this gateway.
X-CacheHIT / MISSWhether the data was served from the gateway's local cache or fetched from the network.

Release Requirement: From gateway Release 85, which is not released yet, a response served through an ArNS name carries the ETag "<digest>.<X-ArNS-Resolved-Id>". A 304 then means the same bytes and the same resolution, so a cache does not keep an old resolution after the name is re-pointed. /raw, /<id> and the index routes keep the plain digest.

Why X-AR-IO-Verified Can Be False for Verified Data

A common source of confusion: data may be verified in the gateway's database but still return X-AR-IO-Verified: false. This happens when the data is streamed from a network source rather than served from local cache. During streaming, the gateway cannot compute a hash of the data in-flight to confirm it matches the verified hash. Only when the data is served from local cache can the gateway guarantee that the bytes being sent match what was previously verified.

# Cache hit - verified data served from local storage
X-AR-IO-Verified: true
X-Cache: HIT
Content-Digest: sha-256=:4ROTs2lTPAKbr8Y41WrjHu+2q+7S+m+yTuO7fAUzZI4=:

# Network fetch of a large file - same data, but the hash can't be confirmed in-flight
X-AR-IO-Verified: false
X-Cache: MISS
# Content-Digest is NOT set (the body is streamed, not hashed)

ANS-104 Bundle Headers

For data items served from ANS-104 bundles, gateways include additional headers in two categories.

Position Headers

These headers describe the data item's location within its parent bundle, allowing clients to independently verify inclusion:

HeaderDescription
X-AR-IO-Root-Transaction-IdThe root Arweave transaction containing the bundle
X-AR-IO-Data-Item-OffsetByte offset of this data item within the bundle
X-AR-IO-Data-Item-SizeSize of the data item in bytes
X-AR-IO-Data-Item-Data-OffsetByte offset of the data payload within the data item
X-AR-IO-Root-Item-OffsetOffset of the root item in the bundle
X-AR-IO-Root-Item-SizeSize of the root item

Metadata Headers

ANS-104 fields are exposed at the HTTP layer so clients can read data item tags and owner information directly from response headers without parsing the binary format:

HeaderDescription
X-Arweave-OwnerThe raw owner public key of the data item
X-Arweave-Owner-AddressThe data item signer's wallet address (derived from the owner key)
X-Arweave-Tag-*One header per tag, with the tag name as the suffix (e.g., X-Arweave-Tag-Content-Type)
X-Arweave-Tags-TruncatedSet when the tag set exceeds a configurable byte budget, indicating partial tag exposure

Client-Side Verification

Clients can verify gateway responses at multiple levels, from lightweight header checks to full cryptographic verification:

Body Integrity

Compare the Content-Digest header (when present) against a locally computed SHA-256 hash of the response body. For Arweave content, the X-AR-IO-Data-Id is itself a content hash - clients can walk the Arweave or ANS-104 signature chain from this ID to verify the content.

// Verify Content-Digest in a browser
const response = await fetch('https://gateway.example/raw/TX_ID');
const body = await response.arrayBuffer();
const hash = await crypto.subtle.digest('SHA-256', body);
const base64Hash = btoa(String.fromCharCode(...new Uint8Array(hash)));

const digestHeader = response.headers.get('Content-Digest');
// Header format: sha-256=:base64hash=:
// Extract the hash between the colons
const match = digestHeader?.match(/sha-256=:(.+?):/);
const verified = match?.[1] === base64Hash;
console.log('Integrity check:', verified);

Cross-Gateway Comparison

Query the same data from multiple gateways and compare their response headers. If X-AR-IO-Verified: true and Content-Digest values match across independent gateways, the data is authentic with high confidence.

Wayfinder Verification

The Wayfinder protocol provides automated client-side routing and verification across the gateway network. It supports configurable strategies including balanced (random), fastest ping, and static gateway selection, with built-in response verification.

HTTP Message Signatures (RFC 9421)

Gateways sign response headers with RFC 9421 HTTP Message Signatures. This is on by default. An Ed25519 key signs the trust-relevant headers of each response, producing a Signature and Signature-Input header pair. The signature proves which gateway operator produced a response.

Turning HTTP Signatures Off

Signing is on unless you turn it off in your gateway's .env file:

HTTPSIG_ENABLED=false

Signing Key Selection

When OBSERVER_KEYPAIR_PATH or OBSERVER_PRIVATE_KEY is set, the gateway uses the observer's Solana keypair directly as the HTTPSIG signing key. Verifiers derive the Solana address from the public key in the keyId and look it up in the on-chain Gateway Registry — no separate attestation is needed.

When neither observer env is set, the gateway auto-generates a standalone Ed25519 key at data/keys/httpsig.pem. Responses are still signed, but the signer can't be tied back to the on-chain registry.

If you use a single Solana key for both operator and observer (Pattern 1 in the migration guide), HTTPSIG falls back to the auto-generated key because the gateway only piggybacks on OBSERVER_KEYPAIR_PATH/OBSERVER_PRIVATE_KEY when they're explicitly set. To get on-chain-verifiable HTTPSIG with a single key, explicitly set OBSERVER_KEYPAIR_PATH (or OBSERVER_PRIVATE_KEY) to the same value as your operator key.

Configuration Reference

VariableDefaultDescription
HTTPSIG_ENABLEDtrueRFC 9421 response signing
HTTPSIG_KEY_FILEdata/keys/httpsig.pemPath to standalone Ed25519 private key (auto-generated if missing). Ignored when OBSERVER_KEYPAIR_PATH or OBSERVER_PRIVATE_KEY is set
HTTPSIG_BIND_REQUESTtrueInclude request method and path in signature (prevents replay)
OBSERVER_KEYPAIR_PATH-Path to a 64-byte Solana keypair JSON. When set, used as the HTTPSIG signing key — verifiable against the on-chain GAR
OBSERVER_PRIVATE_KEY-Alternative: base58-encoded 64-byte secret. Mutually exclusive with the file form

Verifying It's Working

Check the /ar-io/info endpoint to confirm:

curl -s https://your-gateway.example/ar-io/info | jq '.httpsig'

The response includes the public key, key ID, Solana address, and attestation details (if configured). Signed responses will include Signature and Signature-Input headers on all trust-relevant data responses.

What Gets Signed

The gateway signs all trust-relevant response headers but not the response body. Body integrity is achieved through the signed X-AR-IO-Data-Id (which is a content hash) and the Content-Digest header. Header-only signing preserves streaming performance for large responses.

Signed headers (when present on the response):

  • Trust headers: X-AR-IO-Data-Id, X-AR-IO-Verified, X-AR-IO-Stable, X-AR-IO-Trusted
  • Bundle headers: X-AR-IO-Root-Transaction-Id, X-Arweave-Owner-Address, X-Arweave-Tags-Truncated
  • ArNS headers: X-ArNS-Name, X-ArNS-Resolved-Id, X-ArNS-TTL-Seconds, X-ArNS-ANT-Program-Id, X-ArNS-ANT-Id, and with them X-ArNS-Basename, X-ArNS-Record, X-ArNS-Resolved-At, X-ArNS-Undername-Limit, X-ArNS-Record-Index
  • Chunk headers: X-Arweave-Chunk-Data-Root, X-Arweave-Chunk-Tx-Id, X-AR-IO-Chunk-Source-Type
  • Index Sharing headers: X-AR-IO-Index-Publication on the publication at /ar-io/indexes, and X-AR-IO-Index-File on band files
  • Content headers: Content-Type, Content-Digest, Repr-Digest
  • Root offset headers: X-AR-IO-Root-Item-Offset, X-AR-IO-Root-Item-Size, X-AR-IO-Root-Path and the older X-AR-IO-Root-Data-Item-Offset, X-AR-IO-Root-Data-Offset
  • All X-Arweave-Tag-* headers (dynamically matched)
  • Request components (when HTTPSIG_BIND_REQUEST=true): @method, @path, @status

Only responses containing at least one trust-relevant header are signed. Non-data responses (health checks, info endpoint, errors) are not signed.

A range request for a band file answers 206 with Repr-Digest, the digest of the whole file, instead of a Content-Digest of the bytes sent. The signature covers it, so a signed range is bound to the file it came from.

Release Requirement: From gateway Release 85, which is not released yet, GET /ar-io/offsets/:id answers are signed too. They carry X-AR-IO-Root-Transaction-Id and a Content-Digest that binds the body.

Verification Chain

Clients can verify signed responses through the following chain:

  1. Signature verification — The public key is embedded in the Signature-Input header's keyid parameter and is verifiable via the Web Crypto API in modern browsers.
  2. Identity verification — When the observer Solana key is used for signing, derive the Solana address from the public key and look it up in the on-chain Gateway Registry (GAR). A match confirms the signer is a registered gateway operator.
  3. Body integrity — Compare the Content-Digest header against a locally computed hash, or walk the Arweave signature chain from the signed X-AR-IO-Data-Id.

How is this guide?