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.5", 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 torii::ToriiBuilder; #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> { // Create Torii using the builder pattern // This connects to SQLite and applies migrations automatically let torii = ToriiBuilder::new() .with_seaorm("sqlite::memory:") .await? .apply_migrations(true) .build() .await?; // 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.password().register(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.password().authenticate(
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);
let token = session.token.as_ref().expect("freshly created session should have token");
println!("Session token: {}", 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 torii::ToriiBuilder;
use chrono::Duration;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Opaque sessions are the default - sessions are stored in the database
let _torii = ToriiBuilder::new()
.with_sqlite("sqlite::memory:")
.await?
.with_session_expiry(Duration::days(30))
.apply_migrations(true)
.build()
.await?;
Ok(())
}
JWT Sessions
Self-contained tokens that don't require database lookups:
use torii::{ToriiBuilder, JwtConfig};
use chrono::Duration;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create JWT configuration with HS256 algorithm
// The secret must be at least 32 bytes for security
let jwt_config = JwtConfig::new_hs256(
b"your-secret-key-at-least-32-chars-long!".to_vec()
)?
.with_issuer("your-app-name")
.with_metadata(true);
let torii = ToriiBuilder::new()
.with_sqlite("sqlite::memory:")
.await?
.with_jwt_sessions(jwt_config)
.with_session_expiry(Duration::hours(2))
.apply_migrations(true)
.build()
.await?;
Ok(())
}
Web Framework Integration
Axum Integration
For quick web integration, use the torii-axum crate:
[dependencies]
torii-axum = { version = "0.5.0", features = ["password", "magic-link"] }
use std::sync::Arc;
use axum::{response::Json, routing::get, Router};
use torii::ToriiBuilder;
use torii_axum::{AuthUser, CookieConfig, LinkConfig};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// Set up Torii using the builder pattern
let torii = Arc::new(
ToriiBuilder::new()
.with_seaorm("sqlite::memory:")
.await?
.apply_migrations(true)
.build()
.await?
);
// Create authentication routes with configuration
let auth_routes = torii_axum::routes(torii.clone())
.with_cookie_config(CookieConfig::development())
.with_link_config(LinkConfig::new("http://localhost:3000"))
.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 loginPOST /auth/magic-link- Request magic link emailPOST /auth/magic-link/verify- Verify magic linkPOST /auth/password/reset/request- Request password resetGET /auth/user- Get current userPOST /auth/logout- User logout
For complete documentation on configuration options, middleware, and all available routes, see the Axum Integration guide.
Other Authentication Methods
Torii provides organized namespaces for different authentication methods:
torii.password(): Traditional email/password authenticationtorii.oauth(): Social login (Google, GitHub, etc.)torii.passkey(): Modern biometric authenticationtorii.magic_link(): Email-based passwordless login
Each namespace contains focused methods for that authentication type.
OAuth Authentication
use torii::{Torii, ToriiError};
use torii_core::RepositoryProvider;
async fn start_oauth_flow<R: RepositoryProvider>(
torii: &Torii<R>,
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
// Send magic link email (requires mailer to be configured)
let token = torii.magic_link().send_link(
"user@example.com",
"https://example.com/auth/magic-link/verify"
).await?;
// Verify magic token (called when user clicks the link)
let (user, session) = torii.magic_link().authenticate(
&token_from_url,
Some("Browser".to_string()),
Some("127.0.0.1".to_string())
).await?;
Examples
Check out the complete examples in the repository:
- examples/axum-example - Complete web server with authentication and email support
- 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.