Introduction to Torii
Torii is an authentication framework for Rust applications that gives you complete control over your users' data. Unlike hosted solutions that store user information in their cloud, Torii lets you own and manage your authentication stack while providing modern auth features.
With Torii, you get powerful authentication capabilities combined with full data sovereignty and the ability to store user data wherever you choose.
Warning: This project is in early development and is not production-ready. The API is subject to change without notice. As this project has not undergone security audits, it should not be used in production environments.
Key Features
- Data Sovereignty: Your user data stays in your own database
- Multiple Authentication Methods:
- Password-based authentication
- Social OAuth/OpenID Connect
- Passkey/WebAuthn support
- Magic Link authentication
- Flexible Storage: Store user data in SQLite, PostgreSQL, or MySQL
- Session Management: Choose between database sessions or JWT tokens
- Type Safety: Strongly typed APIs with compile-time guarantees
Storage Support
Authentication Method | SQLite | PostgreSQL | MySQL |
---|---|---|---|
Password | ✅ | ✅ | ✅ |
OAuth2/OIDC | ✅ | ✅ | ✅ |
Passkey | ✅ | ✅ | ✅ |
Magic Link | ✅ | ✅ | ✅ |
Getting Started with Torii
This guide will get you up and running with Torii authentication in your Rust application.
Prerequisites
- A Rust project with Cargo
- Basic understanding of async Rust
- Database (SQLite, PostgreSQL, or MySQL)
Installation
Add Torii to your Cargo.toml
:
[dependencies]
torii = { version = "0.4.0", features = ["password", "sqlite"] }
tokio = { version = "1", features = ["full"] }
Available Features
Authentication Methods:
password
- Email/password authenticationoauth
- OAuth/social loginpasskey
- WebAuthn/passkey authenticationmagic-link
- Email magic link authentication
Storage Backends:
sqlite
- SQLite storagepostgres
- PostgreSQL storageseaorm
- SeaORM support (SQLite, PostgreSQL, MySQL)
Basic Setup
Here's a complete example with SQLite and password authentication:
use std::sync::Arc; use torii::Torii; use torii_storage_seaorm::SeaORMStorage; #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> { // Initialize the database connection let storage = SeaORMStorage::connect("sqlite::memory:").await?; // Run migrations to set up the database schema storage.migrate().await?; // Create repository provider and Torii instance let repositories = Arc::new(storage.into_repository_provider()); let torii = Arc::new(Torii::new(repositories)); // Now torii is ready to use for authentication Ok(()) }
User Registration and Login
Register a User
use torii::{Torii, ToriiError};
use torii_core::RepositoryProvider;
async fn register_user(
torii: &Torii<impl RepositoryProvider>,
email: &str,
password: &str
) -> Result<(), ToriiError> {
// Register a new user
let user = torii.register_user_with_password(email, password).await?;
println!("User registered: {}", user.id);
Ok(())
}
Login a User
use torii::{Torii, ToriiError};
use torii_core::RepositoryProvider;
async fn login_user(
torii: &Torii<impl RepositoryProvider>,
email: &str,
password: &str
) -> Result<(), ToriiError> {
// Authenticate user - optional user_agent and ip_address for tracking
let (user, session) = torii.login_user_with_password(
email,
password,
Some("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36".to_string()),
Some("127.0.0.1".to_string())
).await?;
// The session token can be stored in a cookie or returned to the client
println!("User authenticated: {}", user.id);
println!("Session token: {}", session.token);
Ok(())
}
Verify a Session
use torii::{Torii, SessionToken, ToriiError};
use torii_core::RepositoryProvider;
async fn verify_session(
torii: &Torii<impl RepositoryProvider>,
session_token: &str
) -> Result<(), ToriiError> {
// Parse the session token
let token = SessionToken::new(session_token);
// Verify and get session data (works for both JWT and opaque tokens)
let session = torii.get_session(&token).await?;
// Get the user associated with this session
let user = torii.get_user(&session.user_id).await?
.ok_or_else(|| ToriiError::AuthError("User not found".to_string()))?;
println!("Session verified for user: {}", user.id);
Ok(())
}
Session Types
Database Sessions (Default)
Sessions are stored in your database and can be revoked immediately:
use std::sync::Arc;
use torii::{Torii, SessionConfig};
use chrono::Duration;
let torii = Torii::new(repositories)
.with_session_config(
SessionConfig::default()
.expires_in(Duration::days(30))
);
JWT Sessions
Self-contained tokens that don't require database lookups:
use torii::{Torii, JwtConfig, SessionConfig};
use chrono::Duration;
// Create JWT configuration with HS256 algorithm
let jwt_config = JwtConfig::new("your-secret-key-at-least-32-chars-long!".to_string())
.with_issuer("your-app-name")
.with_metadata(true);
let torii = Torii::new(repositories)
.with_jwt_sessions(jwt_config);
// Or with custom expiration
let torii = Torii::new(repositories)
.with_session_config(
SessionConfig::default()
.with_jwt(jwt_config)
.expires_in(Duration::hours(2))
);
Web Framework Integration
Axum Integration
For quick web integration, use the torii-axum
crate:
[dependencies]
torii-axum = { version = "0.4.0", features = ["password", "sqlite"] }
use std::sync::Arc;
use axum::{response::Json, routing::get, Router};
use torii::Torii;
use torii_axum::{AuthUser, CookieConfig};
use torii_storage_seaorm::SeaORMStorage;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// Set up database and Torii
let storage = SeaORMStorage::connect("sqlite::memory:").await?;
storage.migrate().await?;
let repositories = Arc::new(storage.into_repository_provider());
let torii = Arc::new(Torii::new(repositories));
// Create authentication routes with cookie configuration
let auth_routes = torii_axum::routes(torii.clone())
.with_cookie_config(CookieConfig::development())
.build();
// Build your application with auth routes
let app = Router::new()
.nest("/auth", auth_routes)
.route("/protected", get(protected_handler))
.with_state(torii);
// Start server
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await?;
axum::serve(listener, app).await?;
Ok(())
}
// Protected route handler
async fn protected_handler(user: AuthUser) -> Json<serde_json::Value> {
Json(serde_json::json!({
"user_id": user.id,
"email": user.email
}))
}
This provides automatic endpoints:
POST /auth/register
- User registrationPOST /auth/login
- User loginGET /auth/user
- Get current userPOST /auth/logout
- User logout
Other Authentication Methods
OAuth Authentication
use torii::{Torii, ToriiError};
async fn start_oauth_flow(
torii: &Torii<impl torii_core::storage::UserStorage + torii_core::storage::OAuthStorage>,
provider: &str
) -> Result<String, ToriiError> {
// Get the authorization URL for the provider
let auth_url = torii.get_oauth_authorization_url(provider).await?;
// Store the CSRF state in your session/cookies
let csrf_state = auth_url.csrf_state;
// Return the URL to redirect the user to
Ok(auth_url.url)
}
Magic Link Authentication
// Generate magic token
let token = torii.generate_magic_token("user@example.com").await?;
// Verify magic token
let (user, session) = torii.verify_magic_token(
&token.token,
Some("Browser".to_string()),
Some("127.0.0.1".to_string())
).await?;
Examples
Check out the complete examples in the repository:
- examples/axum-sqlite-password - Web server with authentication
- examples/todos - Complete todo application
Next Steps
- Learn about Core Concepts for deeper understanding
- Explore different authentication methods
- Configure production storage backends
- Add email verification and password reset functionality
Remember: Torii gives you complete control over your user data while providing modern authentication features.
Core Concepts
Torii is an authentication framework that gives you control over your users' data while providing modern authentication features. Here are the essential concepts you need to understand.
Key Components
Torii consists of four main parts:
- Torii Instance: The main coordinator that handles all authentication
- Storage: Where user and session data is stored (SQLite, PostgreSQL, MySQL)
- Authentication Methods: Password, OAuth, Passkeys, Magic Links
- Sessions: How users stay authenticated after login
Users
Users are people who can authenticate with your application. Each user has:
- Unique ID: A stable identifier that never changes
- Email: Their email address (required)
- Name: Optional display name
- Verification Status: Whether their email is verified
- Timestamps: When they were created and last updated
Sessions
Sessions keep users authenticated after they log in. Each session has:
- Token: A secret string that identifies the session
- User ID: Which user the session belongs to
- Expiration: When the session expires
- Client Info: Optional user agent and IP address
Session Types
Torii supports two session types:
- Database Sessions (default): Stored in your database, can be revoked immediately
- JWT Sessions: Self-contained tokens, fast but cannot be revoked
Authentication Methods
Torii supports multiple ways for users to authenticate:
- Password: Traditional email/password login
- OAuth: Social login (Google, GitHub, etc.)
- Passkeys: Modern biometric authentication
- Magic Links: Email-based passwordless login
Storage
Torii can store data in multiple databases:
- SQLite: Great for development and small applications
- PostgreSQL: Production-ready relational database
- MySQL: Via SeaORM integration
All storage backends support all authentication methods.
Basic Usage
Here's the typical flow:
- Set up storage and create a Torii instance
- Register users with your chosen authentication method
- Users log in to create sessions
- Validate sessions to authenticate requests
- Users log out to end sessions
This simple foundation supports all of Torii's authentication features.