webbotauth.dev KMS
Ed25519 Key Management Service for Cloudflare Workers.
Generate Ed25519 signing keys and sign data remotely. Private keys never leave the KMS. Supports two key distribution standards:
- OAuth/OIDC: JWKS for JWT signature verification
- Web Bot Auth: HTTP Message Signatures for authenticated bot traffic
Get Started
Create a customer account to get your API key and subdomain:
# Or via API:
curl -X POST https://webbotauth.dev/admin/customers \
-H "Content-Type: application/json" \
-d '{"name": "My Bot Agent"}'
Use Case 1: OAuth/OIDC JWT Signing
Sign JWTs for OAuth 2.0 client authentication (private_key_jwt):
// Your agent's subdomain exposes:
// https://<uuid>.webbotauth.dev/.well-known/jwks.json
// https://<uuid>.webbotauth.dev/client-metadata.json
// Sign a JWT using KMSSubtleCrypto
const jwt = await issueJwt(kms, key, {
iss: "https://<uuid>.webbotauth.dev/client-metadata.json",
sub: "https://<uuid>.webbotauth.dev/client-metadata.json",
aud: "https://auth-server.example.com",
});
Use Case 2: Web Bot Auth (HTTP Message Signatures)
Authenticate automated HTTP traffic per draft-meunier-web-bot-auth-architecture:
// Your agent's directory is at:
// https://<uuid>.webbotauth.dev/.well-known/http-message-signatures-directory
// When making requests, include Signature-Agent header:
Signature-Agent: sig1="https://<uuid>.webbotauth.dev"
// Sign requests per RFC 9421 with tag="web-bot-auth"
Signature-Input: sig1=("@authority");created=...;keyid="...";tag="web-bot-auth"
Signature: sig1=:base64-signature:=
The directory endpoint is signed per draft-meunier-http-message-signatures-directory Section 5.2.
API Endpoints
- POST /admin/customers - Create new customer (main domain only)
- POST /keys - Generate new Ed25519 key
- GET /keys - List all keys
- GET /keys/:kid - Get key by ID
- DELETE /keys/:kid - Revoke key
- POST /sign - Sign data
KMSSubtleCrypto Client
import { KMSSubtleCrypto } from "@webbotauth/kms-core";
const kms = new KMSSubtleCrypto({
apiKey: env.KMS_API_KEY,
fetcher: env.KMS.fetch.bind(env.KMS), // Service binding
});
// Generate key - private key stays in KMS
const keyPair = await kms.generateKey("Ed25519", true, ["sign"]);
// Sign data - WebCrypto-like API
const signature = await kms.sign(
"Ed25519",
keyPair.privateKey,
new TextEncoder().encode("data to sign")
);
Service Binding Setup
// wrangler.jsonc
{
"services": [{ "binding": "KMS", "service": "kms-worker" }]
}
// Then: wrangler secret put KMS_API_KEY