Authentication utilities for Smart Platform - JWT, password hashing, and auth services
Project description
smart-auth-kit
Authentication utilities for Smart Platform - JWT tokens, password hashing, and extensible auth services
Installation
pip install smart-auth-kit
Features
- ✅ JWT Tokens: Access and refresh token generation with role-based claims
- ✅ Password Hashing: Argon2id for secure password storage
- ✅ Auth Service: Extensible authentication service with hooks
- ✅ FastAPI Integration: Dependencies for current user and role-based access
- ✅ Multi-tenancy: Built-in tenant ID support
- ✅ Type Safe: Full type hints with Pydantic
Quick Start
1. Implement User Provider
from uuid import UUID
from typing import Optional
from mehdashti_auth.services.auth_service import UserProvider
class MyUserProvider:
"""Custom user provider backed by your database."""
def __init__(self, db):
self.db = db
async def get_user_by_email(self, email: str) -> Optional[dict]:
# Query your database
user = await self.db.users.find_one({"email": email})
if not user:
return None
return {
"uid": user["id"],
"email": user["email"],
"hashed_password": user["password"],
"is_active": user["is_active"],
"role": user["role"],
}
async def get_user_by_uid(self, uid: UUID) -> Optional[dict]:
user = await self.db.users.find_one({"id": uid})
if not user:
return None
return {
"uid": user["id"],
"email": user["email"],
"is_active": user["is_active"],
"role": user["role"],
}
async def create_user(self, user_data: dict) -> dict:
result = await self.db.users.insert_one(user_data)
return {**user_data, "uid": result.inserted_id}
2. Setup Auth Service
from mehdashti_auth import AuthService, AuthServiceConfig, hash_password
# Configuration
config = AuthServiceConfig(
secret_key="your-secret-key-here",
access_token_expire_minutes=30,
refresh_token_expire_days=7,
)
# Initialize
user_provider = MyUserProvider(db)
auth_service = AuthService(config, user_provider)
3. FastAPI Integration
from fastapi import FastAPI, Depends
from typing import Annotated
from mehdashti_auth.dependencies.current_user import (
create_get_current_user_dependency,
create_require_roles_dependency,
)
app = FastAPI()
# Create dependencies
get_current_user = create_get_current_user_dependency(auth_service)
require_admin = create_require_roles_dependency(auth_service, ["admin"])
# Login endpoint
@app.post("/auth/login")
async def login(email: str, password: str):
try:
result = await auth_service.login(email, password)
return result
except ValueError as e:
raise HTTPException(status_code=401, detail=str(e))
# Refresh token
@app.post("/auth/refresh")
async def refresh(refresh_token: str):
try:
result = await auth_service.refresh_access_token(refresh_token)
return result
except ValueError as e:
raise HTTPException(status_code=401, detail=str(e))
# Protected endpoint
@app.get("/users/me")
async def read_users_me(current_user: Annotated[dict, Depends(get_current_user)]):
return current_user
# Admin-only endpoint
@app.delete("/users/{user_id}")
async def delete_user(
user_id: str,
current_user: Annotated[dict, Depends(require_admin)]
):
# Only admins can access this
return {"message": f"User {user_id} deleted"}
Password Hashing
from mehdashti_auth import hash_password, verify_password
# Hash password
hashed = hash_password("my_secure_password")
# Verify password
is_valid = verify_password("my_secure_password", hashed) # True
is_valid = verify_password("wrong_password", hashed) # False
JWT Tokens
Creating Tokens
from mehdashti_auth import create_access_token, create_refresh_token
# Access token
access_token = create_access_token(
subject="user-uuid",
secret_key="your-secret",
roles=["admin", "user"],
tenant_id="tenant-123",
email="user@example.com",
)
# Refresh token
refresh_token = create_refresh_token(
subject="user-uuid",
secret_key="your-secret",
)
Decoding Tokens
from mehdashti_auth import decode_token, verify_token_type
# Decode token
payload = decode_token(token, "your-secret")
# Verify type
if payload and verify_token_type(payload, "access"):
user_id = payload["sub"]
roles = payload["roles"]
Extension Points
Custom Role Extraction
class CustomAuthService(AuthService):
def get_user_roles(self, user: dict) -> list[str]:
# Custom logic: combine role + permissions
roles = [user["role"]]
if user.get("is_superuser"):
roles.append("superuser")
return roles
Custom Login Validation
class MFAAuthService(AuthService):
async def validate_login(self, user: dict) -> None:
# Add MFA check
if user.get("mfa_enabled"):
# Verify MFA code (implementation depends on your MFA system)
if not await self.verify_mfa(user):
raise ValueError("Invalid MFA code")
Multi-Tenancy
# Create token with tenant
token = create_access_token(
subject="user-uuid",
secret_key="secret",
tenant_id="tenant-123",
)
# Extract tenant from token
payload = decode_token(token, "secret")
tenant_id = payload.get("tenant_id")
Error Handling
from mehdashti_auth import AuthService
try:
result = await auth_service.login(email, password)
except ValueError as e:
# Authentication failed
# Possible reasons:
# - Invalid email or password
# - User account is inactive
# - Custom validation failed
print(f"Login failed: {e}")
Security Best Practices
-
Secret Key: Use a strong, random secret key (at least 32 characters)
import secrets secret_key = secrets.token_urlsafe(32)
-
Password Requirements: Enforce strong passwords in your application
-
Token Expiration: Use short expiration for access tokens (30 min)
-
HTTPS Only: Always use HTTPS in production
-
Token Storage: Store tokens securely (HttpOnly cookies recommended)
Configuration
Auth Service Config
from mehdashti_auth import AuthServiceConfig
config = AuthServiceConfig(
secret_key="your-secret-key",
access_token_expire_minutes=30, # Access token TTL
refresh_token_expire_days=7, # Refresh token TTL
)
Environment Variables
# .env file
SECRET_KEY=your-secret-key-here
ACCESS_TOKEN_EXPIRE_MINUTES=30
REFRESH_TOKEN_EXPIRE_DAYS=7
Complete Example
See the examples/ directory for a complete FastAPI application with:
- User registration
- Login/logout
- Token refresh
- Protected endpoints
- Role-based access control
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mehdashti_auth_kit-0.2.0.tar.gz.
File metadata
- Download URL: mehdashti_auth_kit-0.2.0.tar.gz
- Upload date:
- Size: 7.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.11 {"installer":{"name":"uv","version":"0.9.11"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7b229b98a64ad0a06385bc8fb622175a8d81bc4779a3bee73b8ff16469b122b9
|
|
| MD5 |
3ba246fcdae47128246650afd3fc7459
|
|
| BLAKE2b-256 |
3cfaddb5e5826579cd889b1b36feb03effc7c9de0afe4811e27f62521465fe91
|
File details
Details for the file mehdashti_auth_kit-0.2.0-py3-none-any.whl.
File metadata
- Download URL: mehdashti_auth_kit-0.2.0-py3-none-any.whl
- Upload date:
- Size: 10.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.11 {"installer":{"name":"uv","version":"0.9.11"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
87716edcd65d2c7206465a2bb9d086447d50acf24887ae4a4cf340c6529fa3e0
|
|
| MD5 |
207f0bec168111f4b64a4205326f0b60
|
|
| BLAKE2b-256 |
c9d336fc570e8a324de15aeeba3fd59f52a9b47b0fecdb67aaffed0dc400324d
|