RFC 9421 HTTP Message Signatures with Ed25519 โ seamlessly integrating Cloudflare's Web Bot Auth with the X402 payment protocol on Solana.
End-to-end bot verification flow from agent to origin, through Cloudflare's edge network.
Solana Wallet
Bot Protection
Express / NestJS / Fastify
Payment Validated
Traffic is classified into tiers based on Cloudflare bot scores and Web Bot Auth signatures.
Cloudflare-verified bots registered via Web Bot Auth or IP validation. Full unrestricted access.
Self-hosted agents using Web Bot Auth with Ed25519 signatures. High trust, user-controlled.
Traffic classified as likely human by Cloudflare's ML and heuristic detection engines.
Suspicious traffic patterns detected. Restricted access with heavy rate limiting.
Definitively automated traffic. Unverified bots blocked from all endpoints by default.
Full-featured TypeScript package for both client and server-side bot verification.
keys.ts
Key generation, JWK conversion, thumbprint calculation (RFC 7638), and JWKS directory hosting.
generateKeyPair()
importFromPem()
importFromBase64()
calculateThumbprint()
createKeyDirectory()
createKeyDirectoryHandler()
client.ts
RFC 9421 HTTP Message Signatures for outgoing requests. Signs with Ed25519 covering @authority + signature-agent.
sign(url, method)
fromPem()
fromBase64()
testSignature()
shouldSign()
server.ts
Express/Hono middleware that parses Cloudflare headers, classifies traffic into tiers, and enforces access policies.
middleware()
requireTier()
requireMinScore()
parseBotInfo()
requireTierWithPayment()
cloudflare.ts
Edge-native Worker handler for key directory hosting, bot analytics via GraphQL API, and score-based routing.
handleRequest()
createWorkerExport()
handleKeyDirectory()
handleBotAnalytics()
@autonomy/x402-bot-auth
โโโ src/
โ โโโ index.ts โ Constants, types, tier definitions
โ โโโ keys.ts โ Ed25519 key gen, JWK, thumbprints
โ โโโ client.ts โ BotAuthSigner, BotVerifiedX402Client
โ โโโ server.ts โ CloudflareBotMiddleware, BotVerificationGuard
โ โโโ cloudflare.ts โ CloudflareWorkerBotHandler
โโโ exports:
โ โโโ "." โ ./dist/index.js
โ โโโ "./client" โ ./dist/client.js
โ โโโ "./server" โ ./dist/server.js
โ โโโ "./keys" โ ./dist/keys.js
โ โโโ "./cloudflare" โ ./dist/cloudflare.js
โโโ deps: @noble/ed25519, @autonomy/x402-core
Five complete examples demonstrating x402 payment protocol on Solana with Cloudflare Bot Verification.
The minimum viable x402 setup. Adds micropayments ($0.001/req) to an Express API with just a few lines of code.
GET /api/free โ Free
GET /api/paid โ $0.001
AI-powered betting platform with full Cloudflare bot verification. Tier-based access to betting endpoints.
Tiered pricing ($0.001โ$0.01) with bot-aware access control. Demonstrates all 5 bot tiers in action.
/weather/free โ All traffic
/weather/basic โ Humans + bots
/weather/premium โ Humans only
/weather/automation โ Bots only
Enterprise microservice pattern with BotVerificationGuard and decorators for clean, modular bot checks.
High-performance implementation supporting 70k+ req/s. Fastify hooks for bot verification at maximum speed.
From key generation to production deployment โ the complete setup for Cloudflare Web Bot Auth.
Create a new key pair for signing HTTP requests per RFC 9421.
import { Ed25519KeyManager } from '@autonomy/x402-bot-auth/keys';
const keyPair = await Ed25519KeyManager.generateKeyPair();
console.log('Thumbprint:', keyPair.thumbprint);
console.log('Public JWK:', JSON.stringify(keyPair.jwk));
// Save private key securely
fs.writeFileSync('private-key.pem', keyPair.privatePem, { mode: 0o600 });
Serve your JWKS at /.well-known/http-message-signatures-directory over HTTPS.
app.get(
'/.well-known/http-message-signatures-directory',
Ed25519KeyManager.createKeyDirectoryHandler([keyPair.jwk])
);
// Response:
// Content-Type: application/http-message-signatures-directory+json
// { "keys": [{ "kty": "OKP", "crv": "Ed25519", "x": "..." }] }
Submit your bot for verification through Cloudflare's dashboard.
Attach RFC 9421 signatures to every outgoing HTTP request.
import { BotAuthSigner } from '@autonomy/x402-bot-auth/client';
const signer = BotAuthSigner.fromPem(
fs.readFileSync('./private-key.pem', 'utf-8'),
'https://your-domain.com/.well-known/http-message-signatures-directory'
);
const headers = signer.sign('https://api.example.com/data', 'GET');
const response = await fetch('https://api.example.com/data', { headers });
Add bot-tier enforcement to your X402 payment endpoints.
import { CloudflareBotMiddleware, BOT_TIERS } from '@autonomy/x402-bot-auth';
const bot = new CloudflareBotMiddleware({
allowVerifiedBots: true,
allowSignedAgents: true,
});
app.use(bot.middleware());
app.get('/api/premium',
x402.requirePayment(0.01),
bot.requireMinScore(30),
handler
);
Complete reference for Cloudflare bot management headers and protection tier capabilities.
| Header | Description | Tier Required |
|---|---|---|
cf-bot-score | 1-99 bot likelihood | Enterprise |
cf-verified-bot | "true" if Cloudflare-verified | Pro+ |
cf-bot-managed | Detection result | Pro+ |
cf-bot-tags | Classification tags | Enterprise |
cf-ja3-hash | TLS fingerprint hash | Enterprise |
cf-ja4 | JA4 TLS fingerprint | Enterprise |
cf-connecting-ip | Client IP | All plans |
cf-ipcountry | Country code | All plans |
| Feature | Free | Pro | Enterprise |
|---|---|---|---|
| Basic Blocking | โ | โ | โ |
| Bot Analytics | โ | Basic | Full |
| Granular Scores | โ | Groupings | 1-99 |
| Verified Bots | Basic | โ | โ |
| Custom Rules | โ | โ | โ |
| JA3/JA4 | โ | โ | โ |
| Bot Tags | โ | โ | โ |
Ensure header value is enclosed in double quotes and is an HTTPS URL.
Use expirySeconds: 60 or less. Sync system clock via NTP.
Verify keyid matches the JWK thumbprint calculated per RFC 7638.
Only sign ASCII headers. Use @query not @query-params.
Key is registered but signature base is wrong. Check the signing algorithm.
Header format error. Check the Signature-Input syntax carefully.
Three headers are required on every authenticated request.
Points to the JWKS key directory URL. Cloudflare fetches this to retrieve your public key.
"https://your-domain.com/.well-known/http-message-signatures-directory"
Defines covered components and signature parameters per RFC 9421.
sig1=("@authority" "signature-agent");created=1735689600;keyid="<thumbprint>";alg="ed25519";expires=1735693200;nonce="<random>";tag="web-bot-auth"
The Ed25519 signature over the signature base string, base64-encoded.
sig1=:<base64-ed25519-signature>: