yauth
Modular, plugin-based authentication library for Rust (Axum) with a generated TypeScript client, Vue 3 components, and SolidJS components.
Every feature is behind a feature flag — enable only what you need.
Features
| Feature | Description | When to use |
|---|---|---|
email-password |
Registration, login, email verification, forgot/reset/change password, HIBP breach checking, configurable password policy | Default auth for most apps |
passkey |
WebAuthn registration and passwordless login | When you want passwordless/biometric login |
mfa |
TOTP setup/verify with backup codes; intercepts login flow via event system | When you need 2FA for sensitive accounts |
oauth |
OAuth2 client — multi-provider linking (Google, GitHub, etc.) | When users should sign in with external providers |
bearer |
JWT access/refresh tokens with token family tracking (reuse detection) | When API clients need stateless auth tokens |
api-key |
Scoped API key generation with optional expiration | When third-party integrations or scripts need long-lived credentials |
magic-link |
Passwordless email login with optional signup | When you want frictionless email-based auth |
admin |
User management, ban/unban, session management, impersonation | When you need a back-office admin panel |
status |
Protected endpoint listing enabled plugins | When you want a settings/admin page to show active auth features |
oauth2-server |
Full OAuth2 authorization server (authorization code + PKCE, device flow, client credentials, dynamic registration, token introspection + revocation) | When yauth is the identity provider for other apps |
account-lockout |
Brute-force protection with exponential backoff, unlock via email or admin | When you need per-account lockout beyond IP rate limiting |
webhooks |
HMAC-signed HTTP callbacks on auth events with retry + delivery history | When external systems need real-time auth event notifications |
oidc |
OpenID Connect Provider — id_token issuance, OIDC discovery, JWKS, /userinfo | When downstream apps need OIDC-compliant SSO |
telemetry |
Native OpenTelemetry SDK instrumentation | When you need distributed tracing |
openapi |
utoipa OpenAPI spec generation for client codegen | When you need to generate or update the TypeScript client |
redis |
Redis caching decorator — wraps repository traits for sub-ms lookups | Multi-replica deployments, high-traffic apps |
diesel-pg-backend |
PostgreSQL backend via diesel-async + deadpool | Production Postgres deployments (default) |
diesel-mysql-backend |
MySQL/MariaDB backend via diesel-async + deadpool | MySQL 8.0+ / MariaDB 10.6+ deployments |
diesel-sqlite-backend |
Native SQLite backend via diesel + SyncConnectionWrapper | Embedded apps, local dev (vanilla SQLite) |
diesel-libsql-backend |
SQLite/Turso backend via diesel-libsql | Remote Turso edge databases, libSQL |
sqlx-pg-backend |
PostgreSQL via sqlx with compile-time query!() macros |
sqlx users who want compile-time SQL checking |
sqlx-mysql-backend |
MySQL via sqlx with compile-time query!() macros |
sqlx + MySQL deployments |
sqlx-sqlite-backend |
SQLite via sqlx with compile-time query!() macros |
sqlx + SQLite deployments |
seaorm-pg-backend |
PostgreSQL via SeaORM 2.0 | SeaORM users who want entity-based queries + public entity exports |
seaorm-mysql-backend |
MySQL via SeaORM 2.0 | SeaORM + MySQL deployments |
seaorm-sqlite-backend |
SQLite via SeaORM 2.0 | SeaORM + SQLite deployments |
memory-backend |
Fully in-memory backend (no database) | Unit tests, prototyping, CI |
full |
All auth plugins (no backends) | Real apps: full + one backend |
all-backends |
Every backend + redis, except diesel-libsql and toasty (CI-only) | Conformance testing only (diesel-libsql and toasty tested separately due to sqlite3 symbol conflicts) |
email-password + diesel-pg-backend are enabled by default. Real apps use full + one backend (e.g., features = ["full", "diesel-pg-backend"]). CI uses full,all-backends.
Toasty backends (experimental, pre-1.0) are in a separate crate due to a Cargo links conflict with sqlx:
= { = "0.8", = ["full"] }
= { = "https://github.com/yackey-labs/yauth", = ["postgresql"] }
| Feature | Description | When to use |
|---|---|---|
postgresql |
PostgreSQL via Toasty | Toasty users, PG deployments |
mysql |
MySQL via Toasty | Toasty + MySQL deployments |
sqlite |
SQLite via Toasty | Toasty + SQLite deployments |
Try It in 30 Seconds
No database needed. Add the dependencies, then copy, paste, run:
use *;
use InMemoryBackend;
async
# Register
# Login
Schema Generation CLI
cargo-yauth generates migration files for your ORM from a declarative schema. It produces files — it does not run migrations or connect to a database.
# Install the CLI
# Initialize yauth in your project (creates yauth.toml + migration files)
# Add a plugin later — regenerates migration files
# Remove a plugin
# Show current config and plugin status
# Regenerate migration files (CI: --check verifies freshness)
All commands accept -f <path> to specify a config file (default: yauth.toml).
What each ORM generates:
- diesel:
up.sql+down.sqlmigration files +schema.rswithdiesel::table!macros - sqlx: Numbered
.sqlmigration files forsqlx migrate run - seaorm:
up.sql+down.sql+entities/*.rswithDeriveEntityModelstructs - toasty:
#[derive(toasty::Model)]Rust files (no SQL — Toasty manages schema viapush_schema())
yauth.toml
[]
= "diesel" # "diesel" | "sqlx" | "seaorm" | "toasty"
= "postgres" # "postgres" | "mysql" | "sqlite"
= "migrations"
= "yauth_"
[]
= ["email-password", "passkey", "mfa"]
No secrets in config -- database URLs come from environment variables only.
Workspace Crates
| Crate | Purpose |
|---|---|
yauth |
Main library -- plugins, middleware, builder, auth logic, backends |
yauth-entity |
Domain types (User, Session, Password, etc.) |
yauth-migration |
Schema types, DDL generation, diff engine, migration file gen (zero ORM deps) |
cargo-yauth |
CLI binary -- cargo yauth init/add-plugin/remove-plugin/status/generate |
yauth-toasty |
Toasty ORM backends (experimental, separate crate due to sqlite3 links conflict) |
Quick Start
1. Backend (Rust/Axum)
use *;
use DieselPgBackend;
use Router;
async
SeaORM Backend (alternative)
SeaORM backends export their entity types publicly, so you can use yauth tables in your own SeaORM queries:
# Apply generated migrations with sea-orm-cli
use *;
use SeaOrmPgBackend;
async
2. Frontend (TypeScript)
import { createYAuthClient } from "@yackey-labs/yauth-client";
const auth = createYAuthClient({ baseUrl: "/api/auth" });
// Register
await auth.emailPassword.register({ email: "user@example.com", password: "s3cure!Pass" });
// Login
await auth.emailPassword.login({ email: "user@example.com", password: "s3cure!Pass" });
// Check session
const user = await auth.getSession();
console.log(user.email); // "user@example.com"
// Logout
await auth.logout();
3. Pre-built UI (optional)
Vue 3
Install the plugin in your app entry (main.ts):
import { createApp } from "vue";
import { YAuthPlugin } from "@yackey-labs/yauth-ui-vue";
import App from "./App.vue";
createApp(App)
.use(YAuthPlugin, { baseUrl: "/api/auth" })
.mount("#app");
Login page — the LoginForm component handles email/password and emits @success when login succeeds:
<script setup lang="ts">
import { LoginForm } from "@yackey-labs/yauth-ui-vue";
import { useRouter } from "vue-router";
const router = useRouter();
</script>
<template>
<LoginForm @success="router.push('/dashboard')" />
</template>
Dashboard page — use the useSession() composable to access the current user:
<script setup lang="ts">
import { useSession, useAuth } from "@yackey-labs/yauth-ui-vue";
const { user, isAuthenticated, loading } = useSession();
const { logout } = useAuth();
</script>
<template>
<div v-if="loading">Loading...</div>
<div v-else-if="isAuthenticated">
<p>Logged in as {{ user?.email }}</p>
<button @click="logout">Logout</button>
</div>
<div v-else>Not logged in</div>
</template>
Composables reference:
| Composable | Returns | Use for |
|---|---|---|
useYAuth() |
{ client, user, loading, refetch } |
Direct client access |
useAuth() |
{ user, loading, error, submitting, login, register, logout, forgotPassword, resetPassword, changePassword } |
Auth actions with error/loading state |
useSession() |
{ user, loading, isAuthenticated, isEmailVerified, logout } |
Reactive session state checks |
Component props and events:
| Component | Props | Events |
|---|---|---|
LoginForm |
showPasskey?: boolean |
@success, @mfa-required(pendingSessionId) |
RegisterForm |
— | @success(message) |
ForgotPasswordForm |
— | @success(message) |
ResetPasswordForm |
token: string |
@success(message) |
ChangePasswordForm |
— | @success(message) |
VerifyEmail |
token: string |
@success(message) |
MfaChallenge |
pendingSessionId: string |
@success |
MfaSetup |
— | @complete |
PasskeyButton |
mode: "login" | "register", email?: string |
@success |
OAuthButtons |
providers: string[] |
— |
MagicLinkForm |
— | @success(message) |
ProfileSettings |
— | — |
AuthUser type (returned by getSession() and available in composables):
interface AuthUser {
id: string;
email: string;
display_name: string | null;
email_verified: boolean;
role: string;
auth_method: "Session" | "Bearer" | "ApiKey";
}
SolidJS
import { YAuthProvider, LoginForm } from "@yackey-labs/yauth-ui-solidjs";
function App() {
return (
<YAuthProvider baseUrl="/api/auth">
<LoginForm onSuccess={() => navigate("/dashboard")} />
</YAuthProvider>
);
}
Access the session in any child component:
import { useYAuth } from "@yackey-labs/yauth-ui-solidjs";
function Dashboard() {
const { user, refetch } = useYAuth();
return <p>Logged in as {user()?.email}</p>;
}
Adding more features
Enable additional plugins with feature flags:
let yauth = new
.with_email_password
.with_passkey
.with_mfa
.with_oauth
.build
.await?;
All new endpoints are automatically available on the client — no regeneration needed if you use the pre-built @yackey-labs/yauth-client package.
Choose Your Backend
All backends accept a pool or connection you create — yauth does not manage connections. Generate migration files with cargo yauth generate, apply them with your ORM's CLI, then pass the pool to yauth.
Diesel + PostgreSQL (default)
use DieselPgBackend;
let pool = /* your diesel-async deadpool */;
let backend = from_pool;
// Or with a custom PostgreSQL schema:
let backend = from_pool_with_schema;
let yauth = new.build.await?;
Diesel + MySQL / MariaDB
use DieselMysqlBackend;
let pool = /* your diesel-async deadpool */;
let backend = from_pool;
let yauth = new.build.await?;
Diesel + SQLite / Turso (diesel-libsql)
use DieselLibsqlBackend;
let pool = /* your diesel-libsql connection pool */;
let backend = from_pool;
let yauth = new.build.await?;
Diesel + Native SQLite
Requires
libsqlite3-dev(Debian/Ubuntu) orsqlite3(macOS Homebrew) system package.
use DieselSqliteBackend;
let pool = /* your diesel SyncConnectionWrapper pool */;
let backend = from_pool;
let yauth = new.build.await?;
sqlx + PostgreSQL
use SqlxPgBackend;
let pool = connect.await?;
let backend = from_pool;
let yauth = new.build.await?;
sqlx backends use
query!()macros — setDATABASE_URLat compile time and run migrations first. Apply withsqlx migrate run, then build withDATABASE_URL=postgres://... cargo build.
sqlx + MySQL
use SqlxMysqlBackend;
let pool = connect.await?;
let backend = from_pool;
let yauth = new.build.await?;
Requires
DATABASE_URLat compile time. Apply migrations withsqlx migrate runfirst.
sqlx + SQLite
use SqlxSqliteBackend;
let pool = connect.await?;
let backend = from_pool;
let yauth = new.build.await?;
Use an absolute path for SQLite:
DATABASE_URL=sqlite:/absolute/path/to/yauth.db.
SeaORM + PostgreSQL
# Apply generated migrations with sea-orm-cli
use SeaOrmPgBackend;
let db = connect.await?;
let backend = from_connection;
let yauth = new.build.await?;
// SeaORM backends export entity types for your own queries:
// use yauth::backends::seaorm_pg::entities::users;
// let user = users::Entity::find_by_id(id).one(&db).await?;
Toasty + SQLite (experimental, separate crate)
= { = "0.8", = ["full"] }
= { = "https://github.com/yackey-labs/yauth", = ["sqlite"] }
use ToastySqliteBackend;
let db = /* your toasty::Db */;
db.push_schema.await?; // Toasty manages its own schema
let backend = from_db;
let yauth = new.build.await?;
In-Memory (no database)
use InMemoryBackend;
let backend = new;
let yauth = new.build.await?;
Redis Caching
Redis wraps repository traits as a caching decorator. The database remains the source of truth.
let redis_client = open?;
let redis_conn = redis_client.get_connection_manager.await?;
let yauth = new
.with_redis // caches sessions, rate limits, challenges, revocation
.with_email_password
.build
.await?;
Architecture
Plugin System
Plugins implement the YAuthPlugin trait:
public_routes()— unauthenticated endpoints (login, register, etc.)protected_routes()— endpoints behind auth middlewareon_event()— react to auth events (e.g., MFA intercepts login, account lockout blocks login)
Custom plugins can be added via builder.with_plugin(Box::new(MyPlugin)).
Tri-Mode Auth Middleware
Every protected route checks credentials in order:
- Session cookie —
CookieJar→validate_session() - Bearer token —
Authorization: Bearer <jwt>→ JWT validation (requiresbearerfeature) - API key —
X-Api-Key: <key>→ key hash lookup (requiresapi-keyfeature)
The authenticated user is injected as Extension<AuthUser> with fields: id, email, display_name, email_verified, role, banned, auth_method, and scopes.
Event System
All auth operations emit an AuthEvent:
UserRegistered,LoginSucceeded,LoginFailed,SessionCreated,LogoutPasswordChanged,EmailVerifiedMfaEnabled,MfaDisabledUserBanned,UserUnbannedMagicLinkSent,MagicLinkVerifiedAccountLocked,AccountUnlockedWebhookDelivered
Plugins respond with Continue, RequireMfa { pending_session_id }, or Block { status, message }.
Configuration Guide
Session Binding
Detects session hijacking by binding sessions to client IP and/or User-Agent. Configure in YAuthConfig:
bind_ip: true— track client IP at session creationbind_user_agent: true— track User-Agent at session creationBindingAction::Warn— log mismatch but allow accessBindingAction::Invalidate— destroy session on mismatch (forces re-auth)
When to use: Enable Warn by default; use Invalidate for high-security applications. Note that bind_ip may cause issues with mobile users or VPN changes.
Remember Me
Set remember_me_ttl on YAuthConfig to enable longer sessions when users opt in. The login request accepts a remember_me: true field.
When to use: When you want short default sessions (e.g., 24h) with opt-in long sessions (e.g., 30d) via a "keep me logged in" checkbox.
Password Policy
Configure PasswordPolicyConfig on EmailPasswordConfig:
require_uppercase,require_lowercase,require_digit,require_special— character class requirementsmax_length— maximum password length (default: 128)disallow_common_passwords— reject top common passwordspassword_history_count— prevent reuse of last N passwords (0 = disabled)
When to use: When regulatory compliance or security policy requires specific password complexity rules beyond minimum length + HIBP checking.
Account Lockout
Configure AccountLockoutConfig:
max_failed_attempts— threshold before lockout (default: 5)lockout_duration— base lockout time (default: 5 minutes)exponential_backoff— double duration on each lockoutmax_lockout_duration— cap for backoff (default: 24 hours)auto_unlock— auto-unlock after duration expires
When to use: When you need per-account brute-force protection that works across IPs. Rate limiting is per-IP; account lockout is per-account. Use both together for defense in depth.
Webhooks
Configure WebhookConfig:
max_retries— retry failed deliveries (default: 3)retry_delay— delay between retries (default: 30s)timeout— HTTP timeout per delivery (default: 10s)max_webhooks— limit per user (default: 10)
Payloads are signed with HMAC-SHA256 via the X-Webhook-Signature header. Admin routes at /webhooks manage webhook CRUD.
When to use: When external systems (Slack bots, CRMs, analytics) need real-time notifications of auth events without polling.
OIDC
Configure OidcConfig:
issuer— OIDC issuer URL (must matchissclaim)id_token_ttl— id_token expiry (default: 1 hour)claims_supported— advertised claims (default: sub, email, email_verified, name)
When to use: When yauth is the identity provider and downstream apps need OIDC-compliant SSO. Automatically enables bearer + oauth2-server.
API Routes
Core (always available)
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /session |
Yes | Get authenticated user info |
| POST | /logout |
Yes | Invalidate session |
| PATCH | /me |
Yes | Update display name |
Email/Password
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /register |
No | Register with email + password |
| POST | /login |
No | Authenticate (supports remember_me flag) |
| POST | /verify-email |
No | Verify email token |
| POST | /resend-verification |
No | Resend verification email |
| POST | /forgot-password |
No | Request password reset |
| POST | /reset-password |
No | Reset password with token |
| POST | /change-password |
Yes | Change password |
Passkey (WebAuthn)
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /passkey/login/begin |
No | Start WebAuthn login challenge |
| POST | /passkey/login/finish |
No | Complete WebAuthn login |
| POST | /passkeys/register/begin |
Yes | Start passkey registration |
| POST | /passkeys/register/finish |
Yes | Complete passkey registration |
| GET | /passkeys |
Yes | List passkeys |
| DELETE | /passkeys/{id} |
Yes | Delete passkey |
MFA (TOTP + Backup Codes)
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /mfa/verify |
No | Verify MFA code during login |
| POST | /mfa/totp/setup |
Yes | Generate TOTP secret + backup codes |
| POST | /mfa/totp/confirm |
Yes | Confirm TOTP setup |
| DELETE | /mfa/totp |
Yes | Disable TOTP |
| GET | /mfa/backup-codes |
Yes | Get backup code count |
| POST | /mfa/backup-codes/regenerate |
Yes | Regenerate backup codes |
OAuth (Client)
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /oauth/{provider}/authorize |
No | Start OAuth flow |
| GET/POST | /oauth/{provider}/callback |
No | OAuth callback |
| GET | /oauth/accounts |
Yes | List connected accounts |
| DELETE | /oauth/{provider} |
Yes | Unlink provider |
| POST | /oauth/{provider}/link |
Yes | Link account to provider |
Bearer Tokens (JWT)
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /token |
No | Get access + refresh tokens |
| POST | /token/refresh |
No | Refresh access token |
| POST | /token/revoke |
Yes | Revoke refresh token |
API Keys
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /api-keys |
Yes | List API keys |
| POST | /api-keys |
Yes | Create API key (optional scopes, expiry) |
| DELETE | /api-keys/{id} |
Yes | Delete API key |
Magic Link
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /magic-link/send |
No | Send magic link email |
| POST | /magic-link/verify |
No | Verify magic link token |
Status
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /status |
Yes | List enabled plugin names |
Admin
All admin routes require role = "admin".
| Method | Path | Description |
|---|---|---|
| GET | /admin/users |
List users (paginated, searchable) |
| GET | /admin/users/{id} |
Get user details |
| PUT | /admin/users/{id} |
Update user |
| DELETE | /admin/users/{id} |
Delete user |
| POST | /admin/users/{id}/ban |
Ban user |
| POST | /admin/users/{id}/unban |
Unban user |
| POST | /admin/users/{id}/impersonate |
Create session as user |
| GET | /admin/sessions |
List sessions |
| DELETE | /admin/sessions/{id} |
Terminate session |
OAuth2 Server
| Method | Path | Description |
|---|---|---|
| GET | /.well-known/oauth-authorization-server |
Authorization server metadata (RFC 8414) |
| GET | /oauth/authorize |
Authorization endpoint (JSON or redirect to consent UI) |
| POST | /oauth/authorize |
Consent submission (JSON or form-urlencoded) |
| POST | /oauth/token |
Token endpoint — authorization_code, refresh_token, client_credentials (RFC 6749) |
| POST | /oauth/introspect |
Token introspection (RFC 7662) |
| POST | /oauth/revoke |
Token revocation (RFC 7009) |
| POST | /oauth/register |
Dynamic client registration (RFC 7591) |
| POST | /oauth/device/code |
Device authorization request (RFC 8628) |
| GET/POST | /oauth/device |
Device verification |
Supported grant types: authorization_code (with PKCE S256), refresh_token, client_credentials, urn:ietf:params:oauth:grant-type:device_code.
Account Lockout
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /account/request-unlock |
No | Request unlock email |
| POST | /account/unlock |
No | Unlock account with token |
| POST | /admin/users/{id}/unlock |
Yes (admin) | Admin force-unlock |
Webhooks
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /webhooks |
Yes | Create webhook |
| GET | /webhooks |
Yes | List webhooks |
| GET | /webhooks/{id} |
Yes | Get webhook with delivery history |
| PUT | /webhooks/{id} |
Yes | Update webhook |
| DELETE | /webhooks/{id} |
Yes | Delete webhook |
| POST | /webhooks/{id}/test |
Yes | Send test delivery |
OIDC
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /.well-known/openid-configuration |
No | OIDC discovery document |
| GET | /.well-known/jwks.json |
No | JSON Web Key Set |
| GET/POST | /userinfo |
Yes | OIDC UserInfo endpoint |
TypeScript Packages
@yackey-labs/yauth-client
HTTP client auto-generated from the OpenAPI spec via utoipa + orval.
import { createYAuthClient } from "@yackey-labs/yauth-client";
const auth = createYAuthClient({ baseUrl: "https://myapp.example.com/auth" });
// Email/password
await auth.emailPassword.register({ email, password });
await auth.emailPassword.login({ email, password, remember_me: true });
// Session
const user = await auth.getSession();
await auth.logout();
// Webhooks, account lockout, OIDC, OAuth2 server, passkey, MFA, etc.
// — all available as namespaced methods on the client
@yackey-labs/yauth-shared
Shared TypeScript types (AuthUser, AuthSession, etc.) and an AAGUID authenticator map.
@yackey-labs/yauth-ui-vue
Pre-built Vue 3 components and composables:
YAuthPlugin/useYAuth()— Vue plugin (acceptsclientorbaseUrl)useAuth()— composable for auth actions (login, register, logout, etc.)useSession()— composable for reactive session state (user,isAuthenticated,loading)LoginForm,RegisterForm,ForgotPasswordForm,ResetPasswordFormChangePasswordForm,VerifyEmail,ProfileSettingsPasskeyButton,OAuthButtonsMfaSetup,MfaChallengeMagicLinkForm
Components check for feature availability — if a feature group isn't present on the client, the component gracefully renders nothing.
@yackey-labs/yauth-ui-solidjs
Pre-built SolidJS components:
YAuthProvider/useYAuth()— context provider (acceptsclientorbaseUrl)- Same component set as Vue:
LoginForm,RegisterForm,ProfileSettings, etc. ConsentScreen— OAuth2 authorization consent UI
Security
- Argon2id password hashing with timing-safe dummy hash on failed lookups
- HaveIBeenPwned k-anonymity password breach checking (fail-open)
- Password policy — configurable complexity, common password rejection, history tracking
- Rate limiting per operation (login, register, forgot-password, magic-link)
- Account lockout — per-account brute-force protection with exponential backoff
- Session binding — optional IP + User-Agent binding for hijacking detection
- Session tokens stored as SHA-256 hashes
- JWT refresh token family tracking — automatic revocation on reuse detection
- CSRF protection — HttpOnly + SameSite=Lax cookies; bearer/API key via headers
- Email enumeration prevention — consistent responses for non-existent accounts
- Audit logging — all auth events written to
yauth_audit_logtable - WebAuthn challenge TTL — 5-minute expiry with credential exclusion
- Webhook signing — HMAC-SHA256 signatures for payload integrity
- PKCE S256 — required for all OAuth2 authorization code flows
Database Backends
yauth uses a DatabaseBackend trait with pluggable implementations. All persistent data (users, passwords, sessions, API keys, etc.) is accessed through repository traits, making the auth logic fully database-agnostic. All backends accept pools or connections you create — yauth does not manage database connections.
| Backend | Feature Flag | Constructor | Use case |
|---|---|---|---|
DieselPgBackend |
diesel-pg-backend (default) |
from_pool(pool) |
Production Postgres |
DieselMysqlBackend |
diesel-mysql-backend |
from_pool(pool) |
MySQL/MariaDB production |
DieselSqliteBackend |
diesel-sqlite-backend |
from_pool(pool) |
Embedded, local dev |
DieselLibsqlBackend |
diesel-libsql-backend |
from_pool(pool) |
Turso edge databases |
SqlxPgBackend |
sqlx-pg-backend |
from_pool(pool) |
sqlx users, compile-time SQL |
SqlxMysqlBackend |
sqlx-mysql-backend |
from_pool(pool) |
sqlx + MySQL |
SqlxSqliteBackend |
sqlx-sqlite-backend |
from_pool(pool) |
sqlx + SQLite |
SeaOrmPgBackend |
seaorm-pg-backend |
from_connection(db) |
SeaORM users, entity-based |
SeaOrmMysqlBackend |
seaorm-mysql-backend |
from_connection(db) |
SeaORM + MySQL |
SeaOrmSqliteBackend |
seaorm-sqlite-backend |
from_connection(db) |
SeaORM + SQLite |
InMemoryBackend |
memory-backend |
new() |
Tests, prototyping |
yauth does not run migrations. Use cargo yauth generate to produce migration files for your ORM, then apply them with your ORM's CLI (diesel migration run, sqlx migrate run, sea-orm-cli migrate, etc.).
Configurable PostgreSQL Schema
By default, yauth tables live in the public schema. Use from_pool_with_schema() to isolate them:
let backend = from_pool_with_schema;
Redis Caching
Enable the redis feature for Redis-backed caching of sessions, rate limits, challenges, and JTI revocation:
let redis_client = open?;
let redis_conn = redis_client.get_connection_manager.await?;
let yauth = new
.with_redis // wraps repo traits with Redis caching
.with_email_password
.build
.await?;
.with_redis() adds a caching layer around repository operations for sessions, rate limits, challenges, and token revocation. The database backend remains the source of truth.
When to use Redis: multi-replica deployments (shared sessions), high-traffic apps (sub-millisecond session lookups), or when you need instant JWT revocation across all nodes.
See docs/migrating-to-diesel.md for a migration guide if upgrading from yauth v0.1.x (which supported SeaORM).
Database Schema
All tables are prefixed with yauth_. Generated migrations are feature-gated — only tables for enabled plugins are included.
Generate migrations with cargo yauth generate, then apply with your ORM's CLI:
# Generate migration files
# Apply with your ORM
Schema by Plugin
Only the tables for your enabled features are created. Core tables are always present.
Core (always)
| Table | Description |
|---|---|
yauth_users |
id (uuid), email, display_name, email_verified, role, banned, banned_reason, banned_until, created_at, updated_at |
yauth_sessions |
id (uuid), user_id → users, token_hash, ip_address, user_agent, expires_at, created_at |
yauth_audit_log |
id (uuid), user_id → users, event_type, metadata (json), ip_address, created_at |
email-password
| Table | Description |
|---|---|
yauth_passwords |
user_id → users (pk), password_hash |
yauth_email_verifications |
id, user_id → users, token_hash, expires_at, created_at |
yauth_password_resets |
id, user_id → users, token_hash, expires_at, used_at, created_at |
passkey
| Table | Description |
|---|---|
yauth_webauthn_credentials |
id, user_id → users, name, aaguid, device_name, credential (json), created_at, last_used_at |
mfa
| Table | Description |
|---|---|
yauth_totp_secrets |
id, user_id → users (unique), encrypted_secret, verified, created_at |
yauth_backup_codes |
id, user_id → users, code_hash, used, created_at |
oauth
| Table | Description |
|---|---|
yauth_oauth_accounts |
id, user_id → users, provider, provider_user_id, access_token_enc, refresh_token_enc, expires_at, updated_at, created_at |
yauth_oauth_states |
state (pk), provider, redirect_url, expires_at, created_at |
bearer
| Table | Description |
|---|---|
yauth_refresh_tokens |
id, user_id → users, token_hash, family_id (token rotation), expires_at, revoked, created_at |
api-key
| Table | Description |
|---|---|
yauth_api_keys |
id, user_id → users, key_prefix, key_hash, name, scopes (json), last_used_at, expires_at, created_at |
magic-link
| Table | Description |
|---|---|
yauth_magic_links |
id, email, token_hash, expires_at, used, created_at |
oauth2-server
| Table | Description |
|---|---|
yauth_oauth2_clients |
id, client_id, client_secret_hash, redirect_uris (json), client_name, grant_types (json), scopes (json), is_public, created_at |
yauth_authorization_codes |
id, code_hash, client_id, user_id → users, scopes (json), redirect_uri, code_challenge, code_challenge_method, nonce, expires_at, used, created_at |
yauth_consents |
id, user_id → users, client_id, scopes (json), created_at — unique (user_id, client_id) |
yauth_device_codes |
id, device_code_hash, user_code, client_id, scopes (json), user_id → users, status, interval, expires_at, last_polled_at, created_at |
account-lockout
| Table | Description |
|---|---|
yauth_account_locks |
id, user_id → users (unique), failed_count, locked_until, lock_count, locked_reason, created_at, updated_at |
yauth_unlock_tokens |
id, user_id → users, token_hash, expires_at, created_at |
webhooks
| Table | Description |
|---|---|
yauth_webhooks |
id, url, secret, events (json), active, created_at, updated_at |
yauth_webhook_deliveries |
id, webhook_id → webhooks, event_type, payload (json), status_code, response_body, success, attempt, created_at |
oidc
| Table | Description |
|---|---|
yauth_oidc_nonces |
id, nonce_hash, authorization_code_id, created_at |
Also adds a nonce column to yauth_authorization_codes.
Plugins without tables: admin, status, telemetry.
Development
# Rust
# TypeScript
# Integration testing (requires docker compose up -d for PostgreSQL + MySQL)
# Migration CLI
Versioning
Automated via knope from conventional commits. Never manually edit version numbers. All Rust crates and npm packages share a single unified version.
License
MIT