Crate axum_turnstile

Crate axum_turnstile 

Source
Expand description

§axum-turnstile

Cloudflare Turnstile verification middleware for Axum.

This crate provides middleware for verifying Cloudflare Turnstile tokens in Axum web applications. Turnstile is Cloudflare’s privacy-first CAPTCHA alternative that helps protect your application from bots and abuse.

§Features

  • 🔒 Easy integration with Axum applications
  • 🎯 Tower middleware layer for flexible composition
  • ⚙️ Configurable header names and verification endpoints
  • 🧪 Support for Cloudflare’s test keys
  • 📦 Minimal dependencies

§Quick Start

Add this to your Cargo.toml:

[dependencies]
axum-turnstile = "0.1"
axum = "0.8"
tokio = { version = "1", features = ["full"] }

§Basic Usage

use axum::{routing::post, Router};
use axum_turnstile::{TurnstileLayer, VerifiedTurnstile};

#[tokio::main]
async fn main() {
    // Create a protected endpoint
    let app = Router::new()
        .route("/api/protected", post(protected_handler))
        .layer(TurnstileLayer::from_secret("your-secret-key"));

    let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
        .await
        .unwrap();
    axum::serve(listener, app).await.unwrap();
}

// Handler that requires Turnstile verification
async fn protected_handler(_verified: VerifiedTurnstile) -> &'static str {
    "Success! Turnstile token verified."
}

§How It Works

  1. Client includes the Turnstile token in the CF-Turnstile-Token header
  2. Middleware extracts and verifies the token with Cloudflare’s API
  3. If valid, the request proceeds and handlers can extract VerifiedTurnstile
  4. If invalid or missing, the request is rejected with an appropriate status code

§Advanced Configuration

use axum_turnstile::{TurnstileConfig, TurnstileLayer};

let config = TurnstileConfig::new("your-secret-key")
    .with_header_name("X-Custom-Turnstile-Token")
    .with_verify_url("https://custom-endpoint.example.com/verify");

let layer = TurnstileLayer::new(config);

§Testing

Cloudflare provides test keys that always pass or fail verification:

  • Always passes: 1x0000000000000000000000000000000AA
  • Always fails: 2x0000000000000000000000000000000AA
use axum_turnstile::TurnstileLayer;

// Use the test key that always passes
let layer = TurnstileLayer::from_secret("1x0000000000000000000000000000000AA");

§Response Codes

  • 400 Bad Request: Turnstile token header is missing
  • 403 Forbidden: Token verification failed
  • 500 Internal Server Error: Error communicating with Cloudflare’s API

§Extracting the Verified Marker

The VerifiedTurnstile type implements FromRequestParts, so you can use it as an extractor in your handlers:

use axum_turnstile::VerifiedTurnstile;

async fn handler(_verified: VerifiedTurnstile) -> &'static str {
    "Only reached if Turnstile verification succeeded"
}

Structs§

TurnstileConfig
Configuration for Turnstile verification
TurnstileLayer
Layer that applies Turnstile verification middleware
TurnstileMiddleware
Middleware that verifies Turnstile tokens
VerifiedTurnstile
Marker type that can be extracted in handlers after successful verification