A secure, production-ready web framework built with Rust, featuring JWT authentication with device fingerprinting for enhanced security against token theft.
- JWT Authentication with configurable expiration
- Device Fingerprinting - Each login generates a unique device fingerprint
- HttpOnly Cookies - Fingerprint stored securely in HttpOnly cookies
- Session Binding - JWT tokens are bound to specific device sessions
- Automatic Cleanup - Expired fingerprints are cleaned up periodically
- RBAC Authorization - Role-Based Access Control with Casbin
- Admin Policy Management - Admin-only endpoints for policy management
- Database-Backed Policies - Persistent authorization rules in PostgreSQL
- Axum Web Framework - High-performance async web framework
- PostgreSQL Database - Robust data persistence with SQLx
- Structured Logging - Comprehensive logging with tracing
- Graceful Shutdown - Proper cleanup on application termination
- Input Validation - Request validation with the validator crate
- Error Handling - Comprehensive error handling with thiserror
- Password Security - bcrypt hashing with configurable cost factor
- Token Theft Protection - Stolen JWTs cannot be used without matching fingerprint
- Cross-Device Security - Different devices get different fingerprints
- Session Expiration - Automatic fingerprint cleanup prevents accumulation
- IP Tracking - Optional IP address logging for security monitoring
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ HTTP Request │───▶│ Middleware │───▶│ Handlers │
│ │ │ (Auth) │ │ │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Fingerprint │ │ Services │ │ Repository │
│ Service │◀──▶│ │◀──▶│ │
│ │ │ │ │ │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ In-Memory Store │ │ Database │ │ JWT Token │
│ │ │ (PostgreSQL) │ │ Service │
└─────────────────┘ └─────────────────┘ └─────────────────┘
- Rust 1.70 or higher
- PostgreSQL 12 or higher
- Linux/Windows/macOS
git clone <repository-url>
cd rust-jwt-frameworkcp .env.example .env
# Edit .env with your configuration# Install SQLx CLI if not already installed
cargo install sqlx-cli
# Run database migrations
sqlx migrate runcargo build --release
cargo run --releaseThe server will start on http://localhost:8081
| Variable | Description | Default | Required |
|---|---|---|---|
DATABASE_URL |
PostgreSQL connection string | - | Yes |
JWT_SECRET |
Secret key for JWT signing | - | Yes |
JWT_TTL_IN_MINUTES |
JWT token expiration time | 30 | No |
SERVER_ADDRESS |
Server bind address | 127.0.0.1 | No |
SERVER_PORT |
Server port | 8081 | No |
DATABASE_URL=postgresql://username:password@localhost:5432/framework_db
JWT_SECRET=your-super-secret-jwt-key-here
JWT_TTL_IN_MINUTES=60
SERVER_ADDRESS=0.0.0.0
SERVER_PORT=8081Authenticate user and receive JWT token with fingerprint cookie.
Request:
{
"email": "user@example.com",
"password": "password123"
}Response:
{
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
"iat": 1640995200,
"exp": 1640998800
}Security Notes:
- Sets HttpOnly cookie:
user_fingerprint=<fingerprint> - JWT contains fingerprint hash for validation
- Cookie expires in 30 days
Register a new user account.
Request:
{
"email": "user@example.com",
"password": "password123",
"username": "johndoe",
"first_name": "John",
"last_name": "Doe"
}Response:
Status: 201 Created for successful registration
{
"success": true,
"data": {
"id": "uuid-here",
"email": "user@example.com",
"username": "johndoe",
"first_name": "John",
"last_name": "Doe",
"role": "user",
"is_active": true,
"created_at": "2023-01-01T00:00:00Z",
"updated_at": "2023-01-01T00:00:00Z"
}
}Get authenticated user profile.
Headers:
Authorization: Bearer <jwt-token>
Cookie: user_fingerprint=<fingerprint>
Response:
{
"data": {
"id": "uuid-here",
"email": "user@example.com",
"username": "johndoe",
"first_name": "John",
"last_name": "Doe",
"role": "user",
"is_active": true,
"created_at": "2023-01-01T00:00:00Z",
"updated_at": "2023-01-01T00:00:00Z"
}
}Health check endpoint.
Response:
Healthy...
-
Login Process:
- User provides credentials
- Server validates credentials
- Server generates cryptographically secure fingerprint
- Fingerprint hash is embedded in JWT
- Raw fingerprint is stored in HttpOnly cookie
-
Authentication Process:
- Client sends JWT in Authorization header
- Client sends fingerprint cookie automatically
- Server validates JWT signature and claims
- Server hashes received fingerprint
- Server compares hash with JWT fingerprint hash
- Server validates fingerprint against in-memory store
-
Security Benefits:
- Token Theft Protection: Stolen JWTs are useless without matching cookie
- Cross-Device Security: Each device gets unique fingerprint
- Session Isolation: Different browser sessions are isolated
- Automatic Expiration: Fingerprints expire and are cleaned up
The framework implements a comprehensive refresh token system that enhances security and provides better session management through token families.
graph TD
A[Client Login] --> B[Generate Tokens]
B --> C[Store Refresh Token in DB]
C --> D[Return Access + Refresh Tokens]
E[Client Request] --> F[Validate Access Token]
F --> G{Token Valid?}
G -->|Yes| H[Process Request]
G -->|No| I[Client Calls /refresh]
I --> J[Validate Refresh Token]
J --> K{Valid?}
K -->|Yes| L[Generate New Access Token]
K -->|No| M[Return 401 Unauthorized]
L --> N{Token Rotation?}
N -->|Yes| O[Generate New Refresh Token]
N -->|No| P[Keep Same Refresh Token]
O --> Q[Update DB with New Token]
P --> Q
Q --> R[Return New Access Token]
S[Client Logout] --> T{Logout Type}
T -->|Single Session| U[Invalidate One Token]
T -->|All Sessions| V[Invalidate Family]
sequenceDiagram
participant C as Client
participant A as Auth Server
participant DB as Database
Note over C,DB: Initial Login
C->>A: POST /auth (credentials)
A->>A: Generate family_id = UUID
A->>A: Generate refresh_token
A->>DB: Store: user_id, hash(refresh_token), family_id, expires_at
A->>C: Return access_token + refresh_token
Note over C,DB: Token Refresh
C->>A: POST /refresh (refresh_token)
A->>DB: Validate refresh_token exists and not expired
A->>A: Generate new_access_token
A->>A: Option: Generate new_refresh_token with same family_id
A->>DB: Update last_used_at, optionally new token hash
A->>C: Return new_access_token (+ new_refresh_token if rotated)
Note over C,DB: Family Logout
C->>A: POST /logout?family=true
A->>DB: Invalidate all tokens with matching family_id
A->>C: Success response
- Token Families: Group related tokens for bulk operations
- Token Rotation: Optional rotation on refresh for enhanced security
- Database Storage: Secure storage with hash-only approach
- Family-Based Logout: Invalidate single sessions or entire families
- Automatic Expiration: Configurable token lifetimes
- Integration: Works seamlessly with existing fingerprinting
Exchange refresh token for new access token.
Request:
{
"refresh_token": "refresh_token_here"
}Response:
{
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
"iat": 1640995200,
"exp": 1640998800,
"refresh_token": "new_refresh_token_here" // if rotation enabled
}Invalidate refresh tokens.
Request:
{
"refresh_token": "refresh_token_here",
"logout_family": true // optional: logout all family tokens
}Response:
{
"message": "Logged out successfully"
}The login endpoint now returns both access and refresh tokens:
POST /api/auth Response:
{
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
"iat": 1640995200,
"exp": 1640998800,
"refresh_token": "refresh_token_here",
"family_id": "uuid-family-id"
}| Variable | Description | Default | Required |
|---|---|---|---|
REFRESH_TOKEN_TTL_DAYS |
Refresh token expiration in days | 30 | No |
REFRESH_TOKEN_ROTATION |
Enable token rotation on refresh | true | No |
REFRESH_TOKEN_FAMILY_LOGOUT |
Enable family-based logout | true | No |
- Enhanced Session Control: Granular logout options (single session vs all sessions)
- Token Rotation: Prevents replay attacks by rotating tokens on refresh
- Family Tracking: Better audit trail and session management
- Backward Compatibility: Existing JWT-only flows continue to work
- Database Security: Only token hashes stored, never plain tokens
The framework implements Role-Based Access Control (RBAC) using Casbin, providing enterprise-grade authorization with database persistence and programmatic policy management.
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ HTTP Request │───▶│ Middleware │───▶│ Handlers │
│ │ │ (Auth + RBAC) │ │ │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Casbin Service │ │ Policies │ │ Admin Endpoints │
│ (Business │◀──▶│ (Database) │◀──▶│ (Management) │
│ Logic) │ │ │ │ │
└─────────────────┘ └─────────────────┘ └─────────────────┘
- RBAC Model: Subject (user/role) → Object (resource) → Action (permission)
- Database Persistence: Policies stored in PostgreSQL
casbin_ruletable - Admin-Only Management: Secure policy management endpoints
- Automatic Enforcement: Middleware automatically checks permissions
- Service Pattern: Clean architecture with dependency injection
- Audit Logging: Admin actions are logged for security
The system uses a standard RBAC model defined in src/casbin/model.conf:
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
g = _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.actAdd new authorization policies.
Headers:
Authorization: Bearer <admin-jwt>
Cookie: user_fingerprint=<fingerprint>
Request:
{
"subject": "admin",
"object": "/api/admin/*",
"action": "*"
}Response:
Status: 201 Created for successful policy creation
{
"success": true,
"data": {
"success": true,
"message": "Policy added: admin can * on /api/admin/* (by admin: admin@example.com)"
}
}Check if a subject has permission for an action on an object.
Request:
{
"subject": "user:123",
"object": "/api/profile",
"action": "read"
}Response:
{
"success": true,
"message": "Permission check completed by admin: admin@example.com",
"data": {
"allowed": true,
"subject": "user:123",
"object": "/api/profile",
"action": "read"
}
}curl -X POST http://localhost:8081/api/policies \
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..." \
-H "Cookie: user_fingerprint=abc123..." \
-H "Content-Type: application/json" \
-d '{
"subject": "admin",
"object": "/api/admin/*",
"action": "*"
}'curl -X POST http://localhost:8081/api/permissions/check \
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..." \
-H "Cookie: user_fingerprint=abc123..." \
-H "Content-Type: application/json" \
-d '{
"subject": "user:123",
"object": "/api/profile",
"action": "read"
}'# These routes automatically enforce Casbin policies
curl http://localhost:8081/api/profile \
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..." \
-H "Cookie: user_fingerprint=abc123..."- Granular Access Control: Define exactly what each user/role can do
- Admin-Only Management: Only administrators can modify policies
- Database Persistence: Policies survive application restarts
- Audit Trail: All policy changes are logged
- Automatic Enforcement: No manual permission checks needed
- Scalable: Supports complex role hierarchies and permissions
Policies are stored in the casbin_rule table:
CREATE TABLE casbin_rule (
id SERIAL PRIMARY KEY,
ptype VARCHAR NOT NULL, -- Policy type (p, g, etc.)
v0 VARCHAR NOT NULL, -- Subject (user, role, etc.)
v1 VARCHAR NOT NULL, -- Object (resource, endpoint)
v2 VARCHAR NOT NULL, -- Action (read, write, delete)
v3 VARCHAR NOT NULL, -- Additional parameters
v4 VARCHAR NOT NULL,
v5 VARCHAR NOT NULL,
CONSTRAINT unique_key_sqlx_adapter UNIQUE(ptype, v0, v1, v2, v3, v4, v5)
);The authorization system uses your existing configuration system:
| Variable | Description | Default | Required |
|---|---|---|---|
DATABASE_URL |
PostgreSQL connection (used for policies) | - | Yes |
The authorization system integrates seamlessly with existing security features:
- JWT Authentication: Provides user context for authorization
- Device Fingerprinting: Ensures session integrity
- Rate Limiting: Protects against abuse
- Audit Logging: Tracks all authorization decisions
# Admin can do everything on admin endpoints
curl -X POST /api/policies -d '{"subject":"admin","object":"/api/admin/*","action":"*"}'
# Users can read their own profile
curl -X POST /api/policies -d '{"subject":"user","object":"/api/profile","action":"read"}'
# Moderators can edit posts
curl -X POST /api/policies -d '{"subject":"moderator","object":"/api/posts","action":"edit"}'
# Assign user to admin role
curl -X POST /api/policies -d '{"subject":"user:123","object":"admin","action":""}'- bcrypt hashing with cost factor 12 (production-ready)
- No plaintext storage of passwords
- Secure comparison using constant-time algorithms
- Input validation on all endpoints
- SQL injection protection via prepared statements
- XSS protection via proper content-type handling
- CSRF protection via HttpOnly cookies
# Run all tests
cargo test
# Run with verbose output
cargo test -- --nocapture
# Run specific test
cargo test test_nameUse the provided test.http file with VS Code REST Client or similar tools:
# Install REST Client extension in VS Code
# Open test.http and run requests in order- ✅ Normal authentication flow
- ✅ Invalid credentials handling
- ✅ Missing fingerprint
- ✅ Invalid fingerprint validation
- ✅ Token expiration
- ✅ Cross-device access prevention
- ✅ Fingerprint expiration
- ✅ Input validation
- ✅ Error handling
The application uses structured logging with the following levels:
- ERROR: Critical errors that need immediate attention
- WARN: Warning conditions that should be reviewed
- INFO: General information about application operation
- DEBUG: Detailed debugging information
- TRACE: Very detailed tracing information
- GET /api/health - Basic health check endpoint
- Returns "Healthy..." when service is operational
- Request count and latency
- Authentication success/failure rates
- Database connection pool status
- Memory usage statistics
FROM rust:1.70-slim as builder
WORKDIR /app
COPY . .
RUN cargo build --release
FROM debian:bullseye-slim
RUN apt-get update && apt-get install -y libssl-dev ca-certificates
COPY --from=builder /app/target/release/framework /usr/local/bin/
EXPOSE 8081
CMD ["framework"][Unit]
Description=Rust JWT Framework
After=network.target postgresql.service
[Service]
Type=simple
User=framework
ExecStart=/usr/local/bin/framework
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target- Set strong
JWT_SECRET(32+ characters) - Use production PostgreSQL instance
- Configure proper logging levels
- Set up monitoring and alerting
- Configure firewall rules
- Set up SSL/TLS certificates
- Configure backup strategies
- Set up log rotation
src/
├── main.rs # Application entry point
├── config/ # Configuration management
├── entity/ # Database entities
├── dto/ # Data transfer objects
├── service/ # Business logic
├── repository/ # Data access layer
├── handler/ # HTTP request handlers
├── middleware/ # HTTP middleware
├── error/ # Error types and handling
├── response/ # HTTP response utilities
├── routes/ # Route definitions
└── state/ # Application state management
- Error Handling: Use
Result<T, ApiError>for all fallible operations - Logging: Use appropriate log levels (error, warn, info, debug, trace)
- Security: Never log sensitive information (passwords, tokens, secrets)
- Testing: Write tests for all public functions and critical paths
- Documentation: Document all public APIs and complex logic
- Define data models in
entity/ - Create DTOs in
dto/ - Implement business logic in
service/ - Add data access in
repository/ - Create HTTP handlers in
handler/ - Define routes in
routes/ - Add tests for new functionality
- Follow Rust naming conventions
- Use
rustfmtfor code formatting - Run
cargo clippyfor linting - Write comprehensive tests
- Update documentation for new features
This project is licensed under the MIT License - see the LICENSE file for details.
- Axum - Web framework
- SQLx - Database toolkit
- Casbin - Authorization library
- Casbin-RS - Rust implementation
- Axum-Casbin - Axum integration
- Sqlx-Adapter - Database adapter
- jsonwebtoken - JWT implementation
- bcrypt - Password hashing
- tracing - Logging framework
For questions, issues, or contributions:
- Create an issue on GitHub
- Check the documentation in
docs/directory - Review the test scenarios in
tests\http\test.http
Note: This framework implements advanced security features including JWT authentication with device fingerprinting and enterprise-grade RBAC authorization with Casbin. Always review and test security implementations before deploying to production.