API Gateways for Web3 Applications: RPC Traffic, Identity, and Abuse Controls

API7.ai

September 17, 2026

API Gateway Guide

A Web3 API gateway can authenticate application callers, allocate shared node capacity, route RPC traffic, and expose operational evidence. It cannot prove that an API caller owns a wallet, validate blockchain consensus, make a rejected transaction valid, or turn a public RPC endpoint into a trusted identity system.

The practical design problem is to protect scarce node and provider capacity without changing JSON-RPC behavior that wallets, indexers, and applications depend on.

Key Takeaways

  • Treat application credentials, network identity, wallet ownership, and transaction signatures as separate trust domains.
  • Split inexpensive reads, expensive historical queries, subscriptions, and transaction submission into explicit policies.
  • Preserve JSON-RPC response bodies and IDs; an HTTP 200 can still carry a JSON-RPC error.
  • Rate-limit authenticated consumers, but do not silently fail open when the shared counter is unavailable.
  • Never replay transaction submission merely because a node timed out; query transaction state and reconcile first.

Define What the Gateway Owns

Ethereum applications generally communicate with a node through JSON-RPC. The protocol is stateless at the request layer, but the methods have very different cost and risk profiles.

RPC workloadExampleGateway responsibilityNode or application responsibility
Current-state readeth_blockNumberAdmission, routing, bounded retries for safe readsCanonical-chain view and result correctness
Historical queryeth_getLogs over a wide rangeConsumer budget and request boundsIndex availability and query execution
Transaction submissioneth_sendRawTransactionAuthentication, admission, and one bounded delivery attemptSignature and transaction validation, mempool policy
Subscriptioneth_subscribe over WebSocketConnection and message budgetsSubscription state and event semantics
Administrative RPCClient-specific admin methodsDeny public exposure by defaultNode administration and authorization

Most JSON-RPC-over-HTTP calls use one URL and POST; the operation name lives in the body. A path-only gateway rule therefore does not automatically distinguish a cheap read from an expensive trace call. Use separate public endpoints or an RPC-aware policy component when method-level controls matter, and test batch requests so they cannot multiply work behind one HTTP request.

Keep Four Identities Separate

sequenceDiagram
    participant A as Web3 application
    participant G as API gateway
    participant P as RPC policy and node pool
    participant N as Blockchain node
    participant C as Blockchain network
    A->>G: JSON-RPC plus application credential
    G->>G: Authenticate consumer and apply quota
    G->>P: Allowed request plus consumer context
    P->>P: Check method and network policy
    P->>N: One bounded RPC attempt
    N->>C: Read state or submit signed transaction
    C-->>N: Network result
    N-->>P: JSON-RPC result or error
    P-->>G: Preserve ID and RPC semantics
    G-->>A: Response plus gateway correlation data

An API key or access token identifies the configured gateway consumer. An IP address identifies a network source only under the deployment's trusted-proxy rules. A wallet address is a public identifier. A valid transaction signature proves control of the signing key for that transaction; it does not prove that the HTTP caller is the legal owner, an authorized employee, or the same actor that obtained the gateway credential.

Keep authorization decisions attached to the right identity. For example, a per-customer plan can use an authenticated consumer ID, while a custody workflow must use its own wallet-approval and signing controls. Never infer wallet ownership from X-Forwarded-For, an API key name, or a caller-supplied address field.

Protect Shared RPC Capacity with Explicit Failure Behavior

The following Apache APISIX 3.19.0 configuration is a schema-oriented excerpt, not a complete deployment. It assumes that a Consumer and key-auth credential already exist, and that the internal RPC proxy applies method and chain policy. Redis high availability, upstream TLS, health checks, CA trust-store provisioning, and secret provisioning are intentionally omitted.

{ "uri": "/ethereum", "methods": ["POST"], "plugins": { "key-auth": { "header": "apikey", "hide_credentials": true }, "limit-count": { "count": 120, "time_window": 60, "key_type": "var", "key": "consumer_name", "rejected_code": 429, "policy": "redis", "redis_host": "redis.internal", "redis_port": 6379, "redis_password": "$ENV://RPC_RATE_LIMIT_REDIS_PASSWORD", "redis_ssl": true, "redis_ssl_verify": true, "redis_server_name": "redis.internal", "allow_degradation": false } }, "upstream": { "type": "roundrobin", "nodes": { "rpc-policy.internal:8080": 1 } } }

The key-auth plugin sets hide_credentials to false by default: the false path leaves the credential in the forwarded request, while true removes it before proxying. This example selects true; the upstream receives APISIX consumer context, not the reusable key. That context is still only the authenticated API consumer, not wallet identity.

The limit-count plugin sets allow_degradation to false by default. With false, a counter-backend failure returns HTTP 500; with true, APISIX continues without rate limiting. The example keeps the fail-closed default because an unnoticed fail-open path could exhaust shared RPC capacity. Choose deliberately for each workload and document the operational consequence.

For the Redis connection, redis_ssl defaults to false: the false path sends the counter traffic without TLS, while true encrypts it. When TLS is enabled, redis_ssl_verify also defaults to false: the false path does not authenticate the Redis server certificate, while true verifies the certificate. When verification is enabled, redis_server_name is the TLS SNI name and must match the certificate; it defaults to redis_host, so set it explicitly when the host is an alias not covered by the certificate. This boundary authenticates the Redis endpoint named by DNS, SNI, and the configured CA trust store. It does not authenticate an API consumer, wallet owner, or transaction signer.

show_limit_quota_header defaults to true, which emits quota headers; setting it to false suppresses those headers but does not disable enforcement. Neither path makes a consumer-provided identity more trustworthy.

Preserve JSON-RPC Errors Instead of Flattening Them

EIP-1474 defines Ethereum RPC requests and responses and includes standard and Ethereum-specific error codes. A gateway must observe two error layers:

  • HTTP and transport failures, such as 401, 429, timeout, or upstream connection failure;
  • JSON-RPC errors in the response body, such as -32602 for invalid parameters, -32003 for a rejected transaction, or -32005 for a defined limit being exceeded.

Do not rewrite every JSON-RPC error into a generic HTTP success metric. Dashboards should parse both layers, and clients should preserve the request id when correlating a response. If the gateway generates an overload response before the RPC service runs, document whether it returns an HTTP error, a JSON-RPC error object, or both. Consistency matters more than pretending the layers are identical.

Batch requests need a separate budget. Counting one HTTP envelope as one request can understate node work when the array contains many operations. Bound the number of elements, total body size, allowed methods, and cost of each operation in the RPC-aware layer.

Route Reads and Writes by Consequence

Create explicit node pools for at least:

  • current-state reads that may use replicas;
  • archive or trace queries that require expensive historical state;
  • transaction submission, where duplicate delivery and mempool behavior matter;
  • WebSocket subscriptions, which consume long-lived connections;
  • internal administration, which must not share the public listener.

Safe read retries still need a budget and consistency policy. Two healthy nodes can report different chain heads during propagation or reorganization. Record the selected network, node, block tag, latency, and response class so an application can explain why repeated reads differed.

For eth_sendRawTransaction, a timeout is ambiguous: the node may have accepted the signed transaction before the response was lost. Do not submit it automatically to several providers as a generic retry policy. First derive or retain the transaction hash, query known nodes, and reconcile according to the application's nonce and replacement policy. The gateway does not own those blockchain semantics.

Observe Cost and Abuse Without Logging Secrets

Measure requests and JSON-RPC operations separately. Useful dimensions include authenticated consumer, network, method class, batch size, request bytes, response bytes, node pool, latency, HTTP status, JSON-RPC error code, and cache or retry outcome.

Avoid logging raw signed transactions, authentication credentials, complete wallet histories, or unrestricted request bodies by default. Transaction payloads and address activity can be sensitive even when blockchain data is public. Define retention, access, redaction, and incident-use rules before enabling payload logging.

Detect abuse by behavior rather than one signal: wide historical ranges, repeated failed simulations, high batch fan-out, rapidly rotating credentials, connection churn, and method mixes that consume disproportionate node resources. An IP address may help rate control, but proxies, shared networks, and attacker rotation make it an unreliable account identity.

Web3 Gateway Verification Checklist

  • Are application identity, IP source, wallet address, and signing authority kept separate?
  • Can policy distinguish reads, historical queries, submissions, and subscriptions?
  • Are batch element count, body size, and method cost bounded?
  • Is counter-backend failure explicitly fail-closed or fail-open for each route?
  • Are HTTP failures and JSON-RPC errors both visible?
  • Does transaction timeout handling query state before any resubmission?
  • Are administrative RPC methods isolated from public traffic?
  • Do logs avoid credentials and unnecessary transaction or address data?

FAQ

Does the gateway validate a blockchain transaction?

It can validate coarse request shape and admission policy. The blockchain node validates the signed transaction against protocol and local mempool rules; consensus determines inclusion and finality.

Should a quota use wallet address as its key?

Not by default. A caller can submit an address it does not control. Use an authenticated consumer or another verified account identity unless a separate signature challenge binds the caller to the wallet for the intended action.

Can read requests be cached?

Some immutable or explicitly block-pinned reads may be cacheable. Head-relative queries and pending state change over time. Define the cache key, block reference, freshness, reorganization behavior, and privacy boundary before caching.

Next Steps

Combine this design with distributed rate-limit consistency, IP trust and access-list operations, and fine-grained authorization.

Share article link