# AuthKit
[](https://opensource.org/licenses/MIT)
[](https://www.rust-lang.org)
A better-authβinspired authentication library for Rust. Plug-and-play, framework-agnostic, and opinionated yet extensible.
## Overview
AuthKit is a Rust authentication library designed to feel like [better-auth](https://github.com/better-auth/better-auth), but for the Rust ecosystem. It provides secure, database-backed authentication with a single, unified API that works across any contextβHTTP servers, CLI tools, background workers, or proxies.
### Key Features
- **π Secure by Default** - Argon2id password hashing, timing-safe comparisons, secure token generation
- **π― Single Entry Point** - One `Auth` object for all authentication operations
- **π§ Framework-Agnostic** - Works with Axum, Actix, Rocket, or standaloneβno framework lock-in
- **πΎ Database-Backed** - SQLite and PostgreSQL support via SQLx (hidden from API)
- **π Simple API** - Register, login, verify, logoutβsame API everywhere
- **β‘ Async-First** - Built on Tokio for high-performance async operations
- **π¨ Extensible** - Swappable password and session strategies
## Quick Start
### Installation
Add AuthKit to your `Cargo.toml`:
```toml
[dependencies]
authkit = "0.1"
tokio = { version = "1.28", features = ["full"] }
```
### Basic Usage
```rust
use authkit::prelude::*;
#[tokio::main]
async fn main() -> Result<()> {
// Create an Auth instance
let auth = Auth::builder()
.database(Database::sqlite("auth.db").await?)
.build()?;
// Run migrations
auth.migrate().await?;
// Register a new user
let user = auth.register(Register {
email: "user@example.com".into(),
password: "secure-password".into(),
}).await?;
println!("User registered: {}", user.email);
// Login
let session = auth.login(Login {
email: "user@example.com".into(),
password: "secure-password".into(),
}).await?;
println!("Session token: {}", session.token);
// Verify a session
let user = auth.verify(Verify {
token: session.token.clone(),
}).await?;
println!("Verified user: {}", user.email);
// Logout
auth.logout(Logout {
token: session.token,
}).await?;
println!("Logged out successfully");
Ok(())
}
```
## Design Philosophy
AuthKit is built around five core principles:
### 1. Single Entry Point
Users interact with only one object: `Auth`. No repositories, no generics, no leaked internals.
```rust
let auth = Auth::builder()
.database(Database::sqlite("auth.db").await?)
.build()?;
```
### 2. Framework-Agnostic by Design
AuthKit doesn't depend on Axum, Actix, Rocket, Hyper, or Tower. It works equally well in:
- REST APIs
- CLI tools
- gRPC services
- Proxies (Pingora)
- Background workers
Framework adapters live outside the core library.
### 3. Opinionated Defaults, Explicit Overrides
Ships with secure defaults:
- Argon2id password hashing
- Database-backed sessions
- Secure token generation
- Sensible expiry defaults
Override behavior explicitly when needed, but never accidentally weaken security.
### 4. No Leaky Abstractions
AuthKit hides implementation details:
- SQLx internals
- Database schemas
- Crypto implementations
- Token formats
Users never interact with traits, repositories, lifetimes, or generic parameters in the public API.
### 5. Same API Everywhere
```rust
auth.register(Register { ... }).await?;
auth.login(Login { ... }).await?;
auth.verify(Verify { ... }).await?;
auth.logout(Logout { ... }).await?;
```
These calls behave identically whether invoked from an HTTP handler, CLI command, test, or background task.
## Architecture
```
Auth
βββ AuthInner (Arc)
βββ Database (trait object)
βββ PasswordStrategy
βββ SessionStrategy
βββ TokenStrategy
```
**Key characteristics:**
- `Auth` is cheap to clone (uses `Arc` internally)
- Internals are completely hidden
- Components are swappable via builder pattern
- No global state required
### Strategy Pattern
AuthKit uses a consistent strategy pattern for all authentication components:
```
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Application Layer β
β (Auth, Operations: register, login, verify, etc.) β
βββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββ
β
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Strategy Layer β
β β’ PasswordStrategy (Argon2, Bcrypt, etc.) β
β β’ SessionStrategy (Database-backed) β
β β’ TokenStrategy (Database-backed) β
β β
β Strategies receive &dyn DatabaseTrait as parameter β
βββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββ
β
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β DatabaseTrait (Abstraction) β
β β
β β’ User Operations (create, find) β
β β’ Session Operations (create, find, delete) β
β β’ Token Operations (create, verify, mark used) β
βββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββ
β
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Backend Implementations β
β β’ SqliteDatabase (SQLite with ? params) β
β β’ PostgresDatabase (Postgres with $N params) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
```
**Design Benefits:**
- Strategies remain stateless and don't store database references
- Database logic is centralized in backend implementations
- Easy to add new database backends (MySQL, etc.)
- Easy to mock for testing
- No SQLx types leak into public API
## Feature Flags
AuthKit uses Cargo features for optional functionality:
```toml
[features]
default = ["sqlite", "argon2"]
# Database backends
sqlite = ["sqlx/sqlite", "sqlx/runtime-tokio"]
postgres = ["sqlx/postgres", "sqlx/runtime-tokio"]
# Password hashing strategies
argon2 = ["dep:argon2", "dep:password-hash"]
bcrypt = ["dep:bcrypt"]
# Token strategies
jwt = ["dep:jsonwebtoken"]
```
### Examples
**PostgreSQL with Argon2:**
```toml
authkit = { version = "0.1", default-features = false, features = ["postgres", "argon2"] }
```
**SQLite with bcrypt:**
```toml
authkit = { version = "0.1", default-features = false, features = ["sqlite", "bcrypt"] }
```
## Database Support
### SQLite
```rust
let auth = Auth::builder()
.database(Database::sqlite("auth.db").await?)
.build()?;
```
### PostgreSQL
```rust
let auth = Auth::builder()
.database(Database::postgres("postgresql://user:pass@localhost/authdb").await?)
.build()?;
```
### Migrations
AuthKit manages its own schema and migrations:
```rust
auth.migrate().await?;
```
**Database Schema:**
- `users` - User accounts with email and password
- `sessions` - Active user sessions
- `tokens` - Unified table for email verification, password reset, etc.
All tables include proper indexes and foreign key constraints for optimal performance and data integrity.
## API Reference
### Auth Operations
#### Register
Create a new user account:
```rust
let user = auth.register(Register {
email: "user@example.com".into(),
password: "secure-password".into(),
}).await?;
```
**Validation:**
- Email must be valid format
- Password must meet minimum security requirements
- Email must be unique
#### Login
Authenticate and create a session:
```rust
let session = auth.login(Login {
email: "user@example.com".into(),
password: "secure-password".into(),
}).await?;
```
**Returns:**
- `Session` with token, user_id, and expiration
#### Verify
Verify a session token and retrieve user:
```rust
let user = auth.verify(Verify {
token: session_token,
}).await?;
```
**Errors:**
- Invalid token
- Expired session
- Session not found
#### Logout
Invalidate a session:
```rust
auth.logout(Logout {
token: session_token,
}).await?;
```
#### Send Email Verification
Generate a verification token for a user:
```rust
let verification = auth.send_email_verification(SendEmailVerification {
user_id: user.id.clone(),
}).await?;
// Send the token via email (application's responsibility)
send_email(&verification.email, &verification.token).await?;
```
**Returns:**
- `VerificationToken` with token, email, and expiration time
- Token expires in 24 hours
**Errors:**
- User not found
- Email already verified
#### Verify Email
Verify a user's email using a token:
```rust
let verified_user = auth.verify_email(VerifyEmail {
token: verification_token,
}).await?;
```
**Returns:**
- Updated `User` with `email_verified` set to `true`
**Errors:**
- Invalid or expired token
- Token already used
- Email already verified
#### Resend Email Verification
Resend verification token to a user:
```rust
let verification = auth.resend_email_verification(ResendEmailVerification {
email: "user@example.com".into(),
}).await?;
```
**Returns:**
- New `VerificationToken` (old tokens remain valid until used or expired)
**Errors:**
- User not found
- Email already verified
### Types
#### User
```rust
pub struct User {
pub id: String,
pub email: String,
pub created_at: i64,
pub email_verified: bool,
pub email_verified_at: Option<i64>,
}
```
#### Session
```rust
pub struct Session {
pub token: String,
pub user_id: String,
pub expires_at: i64,
}
```
#### VerificationToken
```rust
pub struct VerificationToken {
pub token: String,
pub email: String,
pub expires_at: i64,
}
```
## Security
### Default Security Features
| Password hashing | Argon2id |
| Timing-safe compares | β
Enabled |
| Session expiration | β
Enabled (24 hours) |
| Token entropy | High (cryptographically secure) |
| Password reuse | π« Prevented |
| Weak passwords | π« Rejected |
### Password Requirements
- Minimum length: 8 characters
- Must contain at least one uppercase letter
- Must contain at least one lowercase letter
- Must contain at least one number
- Must contain at least one special character
### Email Validation
- RFC 5322 compliant email validation
- Checks for valid format and structure
## Advanced Configuration
### Custom Password Strategy
```rust
use authkit::prelude::*;
use authkit::strategies::password::PasswordStrategyType;
let auth = Auth::builder()
.database(Database::sqlite("auth.db").await?)
.password_strategy(PasswordStrategyType::Argon2)
.build()?;
```
### Custom Session Strategy
```rust
use authkit::prelude::*;
use authkit::strategies::session::SessionStrategyType;
let auth = Auth::builder()
.database(Database::sqlite("auth.db").await?)
.session_strategy(SessionStrategyType::Database)
.build()?;
```
## Error Handling
AuthKit provides a comprehensive error type:
```rust
use authkit::prelude::*;
match auth.login(login_request).await {
Ok(session) => println!("Login successful"),
Err(AuthError::InvalidCredentials) => println!("Wrong email or password"),
Err(AuthError::UserNotFound) => println!("User doesn't exist"),
Err(e) => println!("Error: {}", e),
}
```
## Examples
Check the `examples/` directory for more usage examples:
- `email_verification.rs` - Complete email verification workflow
- `basic.rs` - Simple registration and login flow (planned)
- `web_server.rs` - Integration with Axum (planned)
- `cli_tool.rs` - CLI authentication example (planned)
Run an example:
```bash
cargo run --example email_verification --features sqlite
```
## Testing
Run the test suite:
```bash
cargo test
```
Run tests with all features:
```bash
cargo test --all-features
```
## Roadmap
### Current Status: Foundation Phase β
**Implemented:**
- β
Core Auth API
- β
Builder pattern
- β
SQLite backend
- β
PostgreSQL backend
- β
Argon2 password hashing
- β
Database sessions
- β
Email validation
- β
Password validation
- β
Token system (database-backed)
- β
Email verification flow (send, verify, resend)
**Planned:**
- π JWT sessions
- π Refresh tokens
- π Password reset flow
- π Magic link authentication
- π Axum adapter
- π Actix adapter
- π Rate limiting
- π Audit logging
- π OAuth integration
- π Two-factor authentication
## Contributing
Contributions are welcome! Please read our [contribution guidelines](AGENTS.md) first.
### For Contributors (Including AI Agents)
When contributing to AuthKit, you **MUST**:
- β
Preserve the single-entry-point design
- β
Avoid exposing generics or traits publicly
- β
Keep framework dependencies out of core
- β
Prefer composition over configuration
- β
Default to secure behavior
You **MUST NOT**:
- β Add framework-specific logic to core
- β Leak SQLx types into the public API
- β Introduce global state
- β Require users to wire repositories manually
**If a change makes the API feel less like better-auth, it's probably wrong.**
## License
This project is dual-licensed under your choice of:
- MIT License ([LICENSE-MIT](LICENSE-MIT))
- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE))
at your option.
### Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
## Acknowledgments
Inspired by [better-auth](https://github.com/better-auth/better-auth) - an excellent authentication library for JavaScript/TypeScript.
## Support
- π [Documentation](https://docs.rs/authkit)
- π [Issue Tracker](https://github.com/Akshay2642005/authkit/issues)
- π¬ [Discussions](https://github.com/Akshay2642005/authkit/discussions)
---
**Built with β€οΈ by [Akshay B](mailto:akshay2642005@gmail.com)**