3 releases
| new 0.1.2 | Dec 23, 2025 |
|---|---|
| 0.1.1 | Dec 23, 2025 |
| 0.1.0 | Dec 22, 2025 |
#3 in #database-storage
Used in 2 crates
635KB
17K
SLoC
TSA - Tokens, Sessions, and Authentication
A comprehensive, modular authentication library for Rust applications. TSA provides everything you need to implement secure user authentication, session management, and organization-based access control.
Features
- User Authentication - Email/password signup and signin with secure password hashing (Argon2)
- Session Management - Secure session tokens with configurable expiration
- JWT Tokens - Access and refresh token generation and validation
- Two-Factor Authentication - TOTP-based 2FA with backup codes
- Passkey/WebAuthn - Passwordless authentication support
- OAuth 2.0 - Social login with Google, GitHub, Discord, and 10+ providers
- Organizations - Multi-tenant support with roles (owner, admin, member)
- API Keys - Scoped API key generation and validation
- Rate Limiting - Configurable rate limiting for auth actions
- Enterprise RBAC - Role-based access control with YAML configuration
Architecture
TSA is organized as a Cargo workspace with modular crates:
crates/
├── tsa # Main crate - combines all functionality
├── tsa-core # Core types: User, Session, Organization, errors
├── tsa-token # JWT and opaque token generation/validation
├── tsa-session # Session management and configuration
├── tsa-adapter # Database adapter trait + in-memory implementation
├── tsa-oauth # OAuth 2.0 provider registry and state management
├── tsa-enterprise # Enterprise features: RBAC, approval workflows
├── tsa-axum # Standalone Axum HTTP server
├── tsa-cli # Command-line interface
│
├── tsa-adapter-seaorm # PostgreSQL/SQLite adapter (SeaORM)
├── tsa-adapter-mongodb # MongoDB adapter
├── tsa-adapter-redis # Redis adapter
├── tsa-adapter-dynamodb # AWS DynamoDB adapter
├── tsa-adapter-firestore # Google Firestore adapter
└── tsa-adapter-bigtable # Google Bigtable adapter
Installation
Add TSA to your Cargo.toml:
[dependencies]
tsa = "0.1"
Feature Flags
[dependencies]
tsa = { version = "0.1", features = ["oauth", "totp", "passkey", "enterprise"] }
| Feature | Description |
|---|---|
oauth |
OAuth 2.0 social login (enabled by default) |
totp |
TOTP-based two-factor authentication (enabled by default) |
passkey |
WebAuthn/Passkey authentication |
enterprise |
RBAC and approval workflows |
axum |
Axum web framework integration |
adapter-seaorm |
PostgreSQL/SQLite support |
adapter-mongodb |
MongoDB support |
adapter-redis |
Redis support |
adapter-dynamodb |
AWS DynamoDB support |
adapter-firestore |
Google Firestore support |
adapter-bigtable |
Google Bigtable support |
Quick Start
use tsa::{Auth, AuthConfig, adapter::InMemoryAdapter, NoopCallbacks};
#[tokio::main]
async fn main() -> tsa::Result<()> {
// Create auth instance with in-memory storage
let config = AuthConfig::builder()
.jwt_secret("your-secret-key")
.build();
let adapter = InMemoryAdapter::new();
let auth = Auth::new(config, adapter, NoopCallbacks);
// Sign up a new user
let (user, session, token) = auth
.signup("user@example.com", "secure-password", Some("John Doe".to_string()))
.await?;
println!("User created: {}", user.email);
println!("Session token: {}", token);
// Sign in
let (user, session, token) = auth
.signin("user@example.com", "secure-password", None, None)
.await?;
// Validate session
let (user, session) = auth.validate_session(&token).await?;
// Sign out
auth.revoke_session(session.id).await?;
Ok(())
}
CLI Usage
TSA includes a command-line interface for managing authentication:
# Start the TSA server
tsa server --port 6001
# Authentication
tsa auth signup --email user@example.com --password secret123
tsa auth signin --email user@example.com --password secret123
tsa auth signout
tsa auth status
# User management
tsa user me
tsa user update --name "John Doe"
tsa user password --current oldpass --new newpass
# Organizations
tsa org list
tsa org create --name "My Company" --slug my-company
tsa org members <org-id>
tsa org add-member <org-id> <user-id> --role admin
# Sessions
tsa session list
tsa session revoke <session-id>
tsa session revoke-all
# API Keys
tsa apikey list
tsa apikey create --name "CI Key" --scopes read,write
tsa apikey delete <key-id>
# Configuration
tsa config init
tsa config set server_url http://localhost:6001
tsa config show
# Health check
tsa health
API Endpoints
The tsa-axum server exposes these REST endpoints:
Authentication
POST /auth/signup- Register a new userPOST /auth/signin- Sign in with email/passwordPOST /auth/signout- Sign out current sessionPOST /auth/refresh- Refresh sessionPOST /auth/2fa/setup- Enable 2FAPOST /auth/2fa/verify- Verify 2FA codeDELETE /auth/2fa- Disable 2FAPUT /auth/password- Change password
Users
GET /users/me- Get current userPUT /users/me- Update current userGET /users/me/sessions- List user sessionsDELETE /users/me/sessions/:id- Revoke a sessionDELETE /users/me/sessions- Revoke all sessionsGET /users/me/api-keys- List API keysPOST /users/me/api-keys- Create API keyDELETE /users/me/api-keys/:id- Delete API key
Organizations
GET /organizations- List user's organizationsPOST /organizations- Create organizationGET /organizations/:slug- Get organizationPUT /organizations/:id- Update organizationDELETE /organizations/:id- Delete organizationGET /organizations/:id/members- List membersPOST /organizations/:id/members- Add memberPUT /organizations/:id/members/:userId- Update member roleDELETE /organizations/:id/members/:userId- Remove member
Health
GET /health- Health check
OAuth Configuration
use tsa::oauth::{OAuthRegistry, ProviderConfig};
let mut registry = OAuthRegistry::new("state-secret");
registry.register_google(ProviderConfig {
client_id: "your-client-id".to_string(),
client_secret: "your-client-secret".to_string(),
redirect_uri: "http://localhost:3000/auth/callback/google".to_string(),
scopes: None, // Uses defaults
});
registry.register_github(ProviderConfig {
client_id: "your-client-id".to_string(),
client_secret: "your-client-secret".to_string(),
redirect_uri: "http://localhost:3000/auth/callback/github".to_string(),
scopes: None,
});
// Get authorization URL
let (auth_url, csrf_state) = registry.authorization_url("google")?;
Supported providers:
- GitHub
- Discord
- Microsoft
- Apple
- Slack
- GitLab
- Twitch
- Spotify
Enterprise RBAC
Configure role-based access control with YAML:
roles:
viewer:
permissions:
- read:documents
- read:reports
editor:
inherits: [viewer]
permissions:
- write:documents
- delete:documents
admin:
inherits: [editor]
permissions:
- manage:users
- manage:settings
superuser:
permissions:
- "*"
resources:
documents:
actions: [read, write, delete]
reports:
actions: [read, generate]
users:
actions: [read, manage]
use tsa::enterprise::{RbacConfig, PermissionResolver};
let config = RbacConfig::from_yaml(yaml_content)?;
let resolver = PermissionResolver::new(config);
// Check permissions
let allowed = resolver.has_permission("editor", "write:documents");
assert!(allowed);
// Get all permissions for a role
let permissions = resolver.get_all_permissions("admin");
Database Adapters
PostgreSQL (SeaORM)
[dependencies]
tsa = { version = "0.1", features = ["adapter-seaorm"] }
use tsa::adapter::seaorm::SeaOrmAdapter;
use sea_orm::Database;
let db = Database::connect("postgres://user:pass@localhost/tsa").await?;
let adapter = SeaOrmAdapter::new(db);
let auth = Auth::new(config, adapter, NoopCallbacks);
MongoDB
[dependencies]
tsa = { version = "0.1", features = ["adapter-mongodb"] }
use tsa::adapter::mongodb::MongoDbAdapter;
let adapter = MongoDbAdapter::new("mongodb://localhost:27017", "tsa").await?;
let auth = Auth::new(config, adapter, NoopCallbacks);
Redis
[dependencies]
tsa = { version = "0.1", features = ["adapter-redis"] }
use tsa::adapter::redis::RedisAdapter;
let adapter = RedisAdapter::new("redis://localhost:6379").await?;
let auth = Auth::new(config, adapter, NoopCallbacks);
Testing
# Run all tests
cargo test
# Run tests for a specific crate
cargo test --package tsa
# Run with all features
cargo test --all-features
License
MIT OR Apache-2.0
Dependencies
~4–52MB
~718K SLoC