The community-maintained Rust SDK for the Clerk Backend API, plus request-authentication middleware for Actix Web, Axum, Rocket, and Poem.
Version 0.5 targets Clerk Backend API version 2026-05-12. The generated API and model modules come from Clerk's official dated OpenAPI specification and use https://api.clerk.com/v1 by default.
use clerk_rs::{apis::users_api, Clerk};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let clerk = Clerk::from_secret_key("your_secret_key");
let user = users_api::get_user(&clerk.config, "user_id").await?;
println!("{}", user.id);
Ok(())
}Every generated function accepts &ClerkConfiguration as its first argument:
use clerk_rs::{apis::organizations_api, ClerkConfiguration};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = ClerkConfiguration::new("your_secret_key");
let organization =
organizations_api::get_organization(&config, "organization_id", None, None).await?;
println!("{}", organization.id);
Ok(())
}See the generated docs directory for all API groups, request types, and response models.
Enable the integration for your web framework:
[dependencies]
clerk-rs = { version = "0.5", features = ["axum"] }Enable the actix feature, then wrap the application with ClerkMiddleware:
use actix_web::{web, App, HttpServer, Responder};
use clerk_rs::{
validators::{actix::ClerkMiddleware, jwks::MemoryCacheJwksProvider},
Clerk,
};
async fn index() -> impl Responder {
"Hello world!"
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
let clerk = Clerk::from_secret_key("your_secret_key");
App::new()
.wrap(ClerkMiddleware::new(
MemoryCacheJwksProvider::new(clerk),
None,
true,
))
.route("/index", web::get().to(index))
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}See the complete Actix Web example.
Enable the axum feature, then add ClerkLayer to the router. The authenticated JWT is available through Axum's Extension extractor on protected routes:
use axum::{routing::get, Extension, Router};
use clerk_rs::{
validators::{
authorizer::ClerkJwt,
axum::ClerkLayer,
jwks::MemoryCacheJwksProvider,
},
Clerk,
};
async fn profile(Extension(jwt): Extension<ClerkJwt>) -> String {
format!("Hello, {}!", jwt.sub)
}
#[tokio::main]
async fn main() -> std::io::Result<()> {
let clerk = Clerk::from_secret_key("your_secret_key");
let app = Router::new()
.route("/profile", get(profile))
.layer(ClerkLayer::new(
MemoryCacheJwksProvider::new(clerk),
Some(vec!["/profile".to_owned()]),
true,
));
let listener = tokio::net::TcpListener::bind("0.0.0.0:8080").await?;
axum::serve(listener, app).await
}The route list passed to ClerkLayer::new selects protected routes. Passing None protects every route. See the complete Axum example.
Enable the rocket feature, register ClerkGuardConfig, and add ClerkGuard to protected route handlers:
use clerk_rs::{
validators::{
jwks::MemoryCacheJwksProvider,
rocket::{ClerkGuard, ClerkGuardConfig},
},
Clerk,
};
use rocket::{get, launch, routes};
#[get("/")]
fn index(_jwt: ClerkGuard<MemoryCacheJwksProvider>) -> &'static str {
"Hello world!"
}
#[launch]
fn rocket() -> _ {
let clerk = Clerk::from_secret_key("your_secret_key");
let guard_config = ClerkGuardConfig::new(
MemoryCacheJwksProvider::new(clerk),
None,
true,
);
rocket::build()
.mount("/", routes![index])
.manage(guard_config)
}See the complete Rocket example.
Enable the poem feature, then apply ClerkPoemMiddleware to the route:
use clerk_rs::{
validators::{jwks::MemoryCacheJwksProvider, poem::ClerkPoemMiddleware},
Clerk,
};
use poem::{get, handler, listener::TcpListener, EndpointExt, Route, Server};
#[handler]
fn hello() -> &'static str {
"Hello world!"
}
#[tokio::main]
async fn main() -> Result<(), std::io::Error> {
let clerk = Clerk::from_secret_key("your_secret_key");
let middleware = ClerkPoemMiddleware::new(
MemoryCacheJwksProvider::new(clerk),
true,
None,
);
let app = Route::new().at("/", get(hello)).with(middleware);
Server::new(TcpListener::bind("0.0.0.0:3000"))
.run(app)
.await
}The authenticated JWT is available as Data<&ClerkJwt> or through req.data::<ClerkJwt>(). The final constructor argument optionally lists routes excluded from authentication.
Live validator integration tests for all four frameworks are documented in tests/README.md. They are ignored during normal test runs and require credentials for a development Clerk instance.
ClerkConfiguration::default() and ClerkConfiguration::new() send:
Clerk-API-Version: 2026-05-12
An older supported Clerk version can be selected explicitly:
use clerk_rs::ClerkConfiguration;
let config = ClerkConfiguration::new("your_secret_key")
.with_api_version("2025-11-10");The Rust types still describe 2026-05-12; selecting an older wire version does not change compile-time types.
The repository vendors Clerk's exact specification at openapi/clerk-bapi-2026-05-12.yml and pins OpenAPI Generator in openapitools.json.
Install @openapitools/openapi-generator-cli, then run:
./scripts/generate-openapi.shThe script verifies the specification checksum, applies the narrowly scoped int64 normalization documented in scripts/prepare-openapi.mjs, regenerates src/apis, src/models, and docs, preserves the hand-written Clerk configuration, and formats the result.
rustls-tls(default)native-tlsactixaxumrocketpoem
- Tembo
- Rezon
- Gitar
- Have I Been Squatted
- Open a PR and add your company here :)
MIT