One engine.
Eight ways in.

Authkestra orchestrates passkeys, OAuth2, TOTP, device flow and more behind a single Rust engine — chain the strategies you need, and a flow that doesn't hold together simply won't compile.

One engine, dispatched at compile time

Every request lands on the same Engine. It hands off to whichever strategy you configured — a passkey, an authenticator code, an OAuth2 provider, a device flow — verifies the credential, mints a session or token, and returns the result. Below, the diagram cycles through all four so you can see one engine carry every route, and the panel beside it shows the code that registers whichever strategy is active. Three of them are the same builder; the device flow is its own object, because there is no browser session to hang it off.

  • Passkey
  • Authenticator code
  • OAuth2
  • Device flow

Request → Engine → strategy → verified → minted → returned

let engine = Authkestra::builder()    .provider(OAuth2Flow::new(github_provider))    .session_store(session_store)    .build();

Why Authkestra

Compile-time safety

The typestate builder pattern turns a misconfigured engine into a compiler error, not a 2am runtime surprise.

Stateless OAuth

State and nonce live in encrypted cookies, never your database — so the engine scales horizontally without a shared session store.

Flexible chaining

Token, session, basic, and custom strategies chain together in the engine, so a complex flow is composed, not bolted on.

Framework & database agnostic

The engine is pure Rust logic. Axum and Actix are isolated adapters, and storage is a trait you implement — no schema is ever assumed.

Eight ways to prove who someone is

Each one is a strategy you hand to the same engine. Mix them, chain them, or ship just one — the shape of your code doesn't change.

Authkestra vs. the world

In the Rust ecosystem you generally choose between a standalone identity provider and a library you embed. Authkestra sits in between: a modular identity engine, embedded in your binary, with the reach of a standalone OP server. Here is how it compares to the two most popular alternatives — both of which are good at what they do.

Feature comparison between Authkestra, better-auth.rs, and standalone servers Rauthy and Kanidm
FeatureAuthkestrabetter-auth.rsRauthy / Kanidm
CategoryEmbedded identity engineComprehensive auth libraryStandalone IdP server
OIDC OP serverNative, fully featuredRelying party onlyFull support
Resource serverNative (guard, strategies)API validationAPI validation
Configuration safetyStrict — typestate builderStandard builderN/A — external config
State managementStateless, encrypted cookiesStateful, in your DBStateful, dedicated DB
Data architectureAgnostic, trait-based — any DBBuilt-in adapters and ORMs100% yours
Passkeys / WebAuthnNative supportNative supportFull support
Multi-factor authNative supportNative supportFull support
Device signaturesBuilt inNot offeredNot offered
Bot protectionBuilt inPlugins availableBuilt in

vs. better-auth.rs

A strong, batteries-included library for user management, with built-in database adapters and passkeys or 2FA out of the box. It doesn't build an OpenID Provider, though — Authkestra's typestate-checked builder and native OP support are where it pulls ahead.

vs. Rauthy & Kanidm

Both are excellent, fast standalone identity servers — the right call when you want a dedicated IdP microservice. Authkestra gives you the same OP capability without the extra service to deploy, the network hop, or the database to back up.

Working GitHub login, four lines in

Add the facade crate with the features you need, then build the engine. The typestate builder only lets you call .build() once every prerequisite it needs is actually in place.

Read the full quickstart guide
Cargo.toml
authkestra = { version = "0.9", features = ["axum", "session", "github"] }
src/main.rs
let github_provider = GithubProvider::new(client_id, client_secret, redirect_uri);let session_store: Arc<dyn SessionStore> = Arc::new(MemoryStore::default()); let auth_engine = Authkestra::builder()    .provider(OAuth2Flow::new(github_provider))    .session_store(session_store)    .build();