Expand description
HTTP gateway for webhook ingestion with bearer-token auth and health endpoint.
zeph-gateway exposes two HTTP endpoints over a single TCP listener:
| Endpoint | Method | Auth required | Purpose |
|---|---|---|---|
/health | GET | No | Liveness check; returns uptime in seconds |
/webhook | POST | Yes (if token set) | Ingest external events into the agent |
§Security model
- Bearer token comparison is performed in constant time via BLAKE3 +
subtle::ConstantTimeEqto prevent timing-oracle attacks (seeGatewayServer::with_auth). - A bearer token is mandatory:
GatewayServer::serverefuses to start (GatewayError::MissingAuthToken) when no non-empty token is configured, since/webhookforwards its body directly into the agent’s turn loop (#6487). - Payload fields are sanitised with
zeph_common::sanitizebefore forwarding.
§Rate limiting
Requests to /webhook are rate-limited per remote IP using a fixed-window counter with a
60-second window. The default ceiling is 120 requests per window and is configurable via
GatewayServer::with_rate_limit. Setting the limit to 0 disables rate limiting.
§Quick start
use tokio::sync::{mpsc, watch};
use zeph_gateway::{GatewayServer, WebhookMessage};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let (webhook_tx, mut webhook_rx) = mpsc::channel::<WebhookMessage>(64);
let (_shutdown_tx, shutdown_rx) = watch::channel(false);
tokio::spawn(async move { // EXEMPT: doc-example only
while let Some(msg) = webhook_rx.recv().await {
println!("received: {msg:?}");
}
});
GatewayServer::new("127.0.0.1", 8080, webhook_tx, shutdown_rx)
.with_auth(Some("my-secret-token".into()))
.with_rate_limit(60)
.serve()
.await?;
Ok(())
}Structs§
- Gateway
Server - HTTP gateway server with bearer-auth, rate limiting, and body-size enforcement.
- Webhook
Message - A validated, control-character-stripped webhook payload forwarded to the agent-input
forwarder (
forward_webhooksin thezephbinary).
Enums§
- Gateway
Error - Errors that can be returned by the HTTP gateway.