A high-performance REST API built with Rust using the Axum web framework and MongoDB for user authentication. This project demonstrates best practices for building secure authentication systems with proper password hashing, JWT tokens, and MongoDB integration.
- High Performance: Built with Axum for excellent performance and async support
- MongoDB Integration: NoSQL database with the official MongoDB Rust driver
- Secure Authentication: JWT-based authentication with bcrypt password hashing
- Input Validation: Request validation using serde and validator
- Error Handling: Comprehensive error handling with custom error types
- Structured Logging: Application tracing with the tracing crate
- CORS Support: Cross-origin resource sharing configuration
- Rate Limiting: Basic rate limiting middleware
- Health Checks: Application health monitoring endpoints
- Web Framework: Axum - Ergonomic web framework for Rust
- Database: MongoDB with mongodb driver
- Async Runtime: Tokio - Asynchronous runtime
- Authentication: jsonwebtoken - JWT implementation
- Password Hashing: bcrypt - Secure password hashing
- Serialization: Serde - JSON serialization/deserialization
- Validation: validator - Input validation
- Logging: tracing - Structured logging
- Environment: dotenvy - Environment variables
- Rust 1.70+ installed (Install Rust)
- MongoDB 4.4+ running locally or remotely
- Git
git clone https://github.com/yourusername/rust-axum-mongodb-auth.git
cd rust-axum-mongodb-auth
Create a .env
file in the project root:
# MongoDB Configuration
MONGODB_URI=mongodb://localhost:27017
DATABASE_NAME=rust_auth_db
# JWT Configuration
JWT_SECRET=your-super-secret-jwt-key-change-this-in-production
JWT_EXPIRES_IN=24h
# Server Configuration
SERVER_HOST=127.0.0.1
SERVER_PORT=3000
# Logging
RUST_LOG=debug
# Security
BCRYPT_COST=12
cargo build
# Development mode with hot reload (requires cargo-watch)
cargo install cargo-watch
cargo watch -x run
# Or standard run
cargo run
The API will be available at http://localhost:3000
src/
├── main.rs # Application entry point
├── lib.rs # Library root
├── config/
│ └── mod.rs # Configuration management
├── database/
│ ├── mod.rs # Database modules
│ └── connection.rs # MongoDB connection setup
├── handlers/
│ ├── mod.rs # Handler modules
│ ├── auth.rs # Authentication handlers
│ ├── user.rs # User management handlers
│ └── health.rs # Health check handlers
├── middleware/
│ ├── mod.rs # Middleware modules
│ ├── auth.rs # JWT authentication middleware
│ ├── cors.rs # CORS middleware
│ └── rate_limit.rs # Rate limiting middleware
├── models/
│ ├── mod.rs # Model modules
│ ├── user.rs # User model and validation
│ └── auth.rs # Authentication request/response models
├── services/
│ ├── mod.rs # Service modules
│ ├── auth_service.rs # Authentication business logic
│ └── user_service.rs # User business logic
├── utils/
│ ├── mod.rs # Utility modules
│ ├── jwt.rs # JWT token utilities
│ ├── password.rs # Password hashing utilities
│ └── validation.rs # Custom validators
└── errors/
└── mod.rs # Custom error types
tests/
├── integration/ # Integration tests
│ ├── auth_tests.rs # Authentication tests
│ └── user_tests.rs # User management tests
└── common/
└── mod.rs # Test utilities
Add these dependencies to your Cargo.toml
:
[dependencies]
# Web framework
axum = { version = "0.7", features = ["macros"] }
tokio = { version = "1.0", features = ["full"] }
tower = "0.4"
tower-http = { version = "0.5", features = ["cors", "trace", "limit"] }
# Database
mongodb = "2.8"
bson = { version = "2.9", features = ["chrono-0_4"] }
futures = "0.3"
# Serialization
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
# Authentication & Security
jsonwebtoken = "9.2"
bcrypt = "0.15"
# Validation
validator = { version = "0.18", features = ["derive"] }
regex = "1.10"
# Time handling
chrono = { version = "0.4", features = ["serde"] }
# Logging & Tracing
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
# Environment & Configuration
dotenvy = "0.15"
# Error handling
anyhow = "1.0"
thiserror = "1.0"
# Utilities
uuid = { version = "1.0", features = ["v4", "serde"] }
[dev-dependencies]
reqwest = { version = "0.11", features = ["json"] }
tokio-test = "0.4"
tower-test = "0.4"
// MongoDB User document structure
{
"_id": ObjectId("..."),
"id": "uuid-v4-string",
"username": "john_doe",
"email": "[email protected]",
"password_hash": "$2b$12$...", // bcrypt hash
"is_active": true,
"is_verified": false,
"created_at": ISODate("2024-01-01T00:00:00Z"),
"updated_at": ISODate("2024-01-01T00:00:00Z"),
"last_login": ISODate("2024-01-01T00:00:00Z")
}
// Create indexes for better performance
db.users.createIndex({ "email": 1 }, { unique: true })
db.users.createIndex({ "username": 1 }, { unique: true })
db.users.createIndex({ "id": 1 }, { unique: true })
- POST
/api/auth/register
- Description: Register a new user account
- Request Body:
{
"username": "johndoe",
"email": "[email protected]",
"password": "SecurePass123!"
}
- Response (201):
{
"success": true,
"message": "User registered successfully",
"data": {
"user": {
"id": "uuid-here",
"username": "johndoe",
"email": "[email protected]",
"is_active": true,
"created_at": "2024-01-01T00:00:00Z"
},
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
}
- POST
/api/auth/login
- Description: Authenticate user and return JWT token
- Request Body:
{
"email": "[email protected]",
"password": "SecurePass123!"
}
- Response (200):
{
"success": true,
"message": "Login successful",
"data": {
"user": {
"id": "uuid-here",
"username": "johndoe",
"email": "[email protected]"
},
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expires_at": "2024-01-02T00:00:00Z"
}
}
- GET
/api/auth/me
- Description: Get current authenticated user details
- Headers:
Authorization: Bearer <token>
- Response (200):
{
"success": true,
"data": {
"id": "uuid-here",
"username": "johndoe",
"email": "[email protected]",
"is_active": true,
"created_at": "2024-01-01T00:00:00Z",
"last_login": "2024-01-01T12:00:00Z"
}
}
- POST
/api/auth/logout
- Description: Logout user (client should discard token)
- Headers:
Authorization: Bearer <token>
- Response (200):
{
"success": true,
"message": "Logged out successfully"
}
- GET
/health
- Description: Application health status
- Response (200):
{
"status": "healthy",
"timestamp": "2024-01-01T00:00:00Z",
"database": "connected"
}
curl -X POST http://localhost:3000/api/auth/register \
-H "Content-Type: application/json" \
-d '{
"username": "johndoe",
"email": "[email protected]",
"password": "SecurePass123!"
}'
curl -X POST http://localhost:3000/api/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected]",
"password": "SecurePass123!"
}'
curl -X GET http://localhost:3000/api/auth/me \
-H "Authorization: Bearer YOUR_JWT_TOKEN_HERE"
- Minimum 8 characters
- At least 1 uppercase letter
- At least 1 lowercase letter
- At least 1 number
- At least 1 special character (!@#$%^&*(),.?":{}|<>)
- Password Hashing: Bcrypt with configurable cost factor
- JWT Tokens: Secure token-based authentication
- Input Validation: Comprehensive request validation
- Rate Limiting: Protection against brute force attacks
- CORS Configuration: Configurable cross-origin requests
- Error Handling: No sensitive information leakage
- MongoDB Injection Prevention: Using BSON and parameterized queries
Run the test suite:
# Run all tests
cargo test
# Run tests with output
cargo test -- --nocapture
# Run integration tests only
cargo test --test integration
# Test specific module
cargo test auth
# Run tests with coverage (requires cargo-tarpaulin)
cargo install cargo-tarpaulin
cargo tarpaulin --out Html
# Format code
cargo fmt
# Check formatting without applying
cargo fmt -- --check
# Run clippy
cargo clippy
# Run clippy with all targets and features
cargo clippy --all-targets --all-features -- -D warnings
# Connect to MongoDB
mongosh mongodb://localhost:27017
# Use your database
use rust_auth_db
# View users collection
db.users.find().pretty()
# Create indexes
db.users.createIndex({ "email": 1 }, { unique: true })
db.users.createIndex({ "username": 1 }, { unique: true })
Variable | Description | Default | Required |
---|---|---|---|
MONGODB_URI |
MongoDB connection string | mongodb://localhost:27017 |
Yes |
DATABASE_NAME |
Database name | rust_auth_db |
Yes |
JWT_SECRET |
JWT signing secret | - | Yes |
JWT_EXPIRES_IN |
Token expiration time | 24h |
No |
SERVER_HOST |
Server bind address | 127.0.0.1 |
No |
SERVER_PORT |
Server port | 3000 |
No |
BCRYPT_COST |
Bcrypt hashing cost | 12 |
No |
RUST_LOG |
Logging level | info |
No |
Create a Dockerfile
:
FROM rust:1.75 as builder
WORKDIR /app
COPY . .
RUN cargo build --release
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
COPY --from=builder /app/target/release/rust-axum-mongodb-auth /usr/local/bin/app
EXPOSE 3000
CMD ["app"]
Build and run:
# Build image
docker build -t rust-axum-mongodb-auth .
# Run with docker-compose (recommended)
docker-compose up -d
- Use strong, randomly generated
JWT_SECRET
- Set
RUST_LOG=info
in production - Configure MongoDB with authentication
- Use connection pooling
- Set up SSL/TLS termination
- Implement proper rate limiting
- Add monitoring and alerting
- Use secrets management
- Set up backup strategies
The API returns consistent error responses:
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid input data",
"details": [
{
"field": "email",
"message": "Invalid email format"
}
]
}
}
Common error codes:
VALIDATION_ERROR
: Input validation failedUNAUTHORIZED
: Authentication requiredFORBIDDEN
: Access deniedNOT_FOUND
: Resource not foundCONFLICT
: Resource already existsINTERNAL_ERROR
: Server error
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature
) - Make your changes
- Add tests for new functionality
- Run
cargo fmt
andcargo clippy
- Commit your changes (
git commit -m 'Add amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.