A scalable, production-ready authentication microservice built with FastAPI. Database-agnostic design with clean architecture and enterprise-grade security.
OpenAuth-Service is a standalone authentication microservice designed to be integrated into distributed systems. It handles user registration, login, token generation, token validation, and role-based access control with industry-standard practices.
Why this service?
- β Microservices ready β Deploy independently
- β Database agnostic β Works with PostgreSQL, MongoDB, MySQL
- β JWT-based β Stateless authentication
- β Clean architecture β Testable and maintainable
- β Production hardened β Rate limiting, input validation, encryption
- π User registration with email verification
- π Secure login with password hashing (bcrypt)
- π« JWT token generation with configurable expiry
- π Refresh token mechanism
- πͺ Logout with token blacklist
- π€ Role-based access control (RBAC)
- π Permission management
- π‘οΈ Scope-based authorization
- π Password hashing with bcrypt
- π« Rate limiting (Slowhttptest protection)
- βοΈ Input validation (Pydantic)
- π Audit logging
- π CORS configuration
- π§ͺ CSRF protection ready
- π Auto-generated OpenAPI documentation
- β Request/response validation
- π Structured error responses
- π Health check endpoint
- Python 3.10+
- Docker (optional)
- PostgreSQL 13+ (or any database)
git clone https://github.com/devberatzengin/OpenAuth-Service.git
cd OpenAuth-Service
# Create virtual environment
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
# Install dependencies
pip install -r requirements.txt
# Setup environment
cp .env.example .env
# Edit .env with your database credentials# Database migrations
alembic upgrade head
# Start service
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
# API docs: http://localhost:8000/docs
# ReDoc: http://localhost:8000/redocdocker build -t openauth-service .
docker run -p 8000:8000 --env-file .env openauth-servicePOST /api/v1/auth/register
Content-Type: application/json
{
"email": "user@example.com",
"password": "SecurePass123!",
"first_name": "John",
"last_name": "Doe"
}
Response: 201 Created
{
"id": "uuid",
"email": "user@example.com",
"access_token": "eyJ...",
"token_type": "bearer",
"expires_in": 3600
}POST /api/v1/auth/login
{
"email": "user@example.com",
"password": "SecurePass123!"
}POST /api/v1/auth/refresh
{
"refresh_token": "eyJ..."
}POST /api/v1/auth/logout
Authorization: Bearer <token>GET /api/v1/users/me
Authorization: Bearer <token>
PUT /api/v1/users/me
Authorization: Bearer <token>
{
"first_name": "Jane",
"last_name": "Smith"
}
PATCH /api/v1/users/me/password
{
"current_password": "old_pass",
"new_password": "new_pass123!"
}GET /api/v1/admin/users
Authorization: Bearer <admin_token>
GET /api/v1/admin/users/{user_id}
PATCH /api/v1/admin/users/{user_id}/role
{
"role": "admin"
}
DELETE /api/v1/admin/users/{user_id}app/
βββ main.py # FastAPI app
βββ config.py # Settings (Pydantic)
βββ api/
β βββ v1/
β β βββ endpoints/
β β β βββ auth.py
β β β βββ users.py
β β β βββ admin.py
β β βββ dependencies.py # Dependency injection
βββ services/ # Business logic
β βββ auth_service.py
β βββ user_service.py
β βββ token_service.py
βββ models/ # Database models (SQLAlchemy)
βββ schemas/ # Pydantic models
βββ database/ # DB connection, session
β βββ base.py
βββ security/ # Hash, JWT, crypto
βββ tests/
βββ conftest.py # Fixtures
βββ test_auth.py
βββ test_users.py
HTTP Request
β
Route Handler (API endpoint)
β
Dependency Injection (auth verification)
β
Service Layer (business logic)
β
Database Layer (ORM)
β
Response (JSON)
# Using bcrypt with salt
from passlib.context import CryptContext
pwd_context = CryptContext(
schemes=["bcrypt"],
deprecated="auto",
bcrypt__rounds=12
)
hashed = pwd_context.hash("password")
verified = pwd_context.verify("password", hashed)import jwt
from datetime import datetime, timedelta
payload = {
"sub": user_id,
"email": email,
"role": role,
"exp": datetime.utcnow() + timedelta(hours=1)
}
token = jwt.encode(payload, SECRET_KEY, algorithm="HS256")
decoded = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])from slowapi import Limiter
limiter = Limiter(key_func=get_remote_address)
@app.post("/auth/login")
@limiter.limit("5/minute")
def login(request: LoginSchema):
# Max 5 login attempts per minute
pass# Run all tests
pytest -v
# Run with coverage
pytest --cov=app tests/
# Specific test file
pytest tests/test_auth.py -vdef test_user_registration(client):
response = client.post(
"/api/v1/auth/register",
json={
"email": "test@example.com",
"password": "TestPass123!",
"first_name": "Test",
"last_name": "User"
}
)
assert response.status_code == 201
assert response.json()["email"] == "test@example.com"-- Users table
CREATE TABLE users (
id UUID PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
first_name VARCHAR(100),
last_name VARCHAR(100),
role VARCHAR(50) DEFAULT 'user',
is_active BOOLEAN DEFAULT TRUE,
is_verified BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
-- Roles table
CREATE TABLE roles (
id UUID PRIMARY KEY,
name VARCHAR(50) UNIQUE NOT NULL,
description TEXT
);
-- User roles junction
CREATE TABLE user_roles (
user_id UUID REFERENCES users(id),
role_id UUID REFERENCES roles(id),
PRIMARY KEY (user_id, role_id)
);
-- Token blacklist (logout)
CREATE TABLE token_blacklist (
id UUID PRIMARY KEY,
token TEXT NOT NULL,
blacklisted_at TIMESTAMP DEFAULT NOW(),
expires_at TIMESTAMP NOT NULL
);# Database
DATABASE_URL=postgresql://user:pass@localhost:5432/openauth
# JWT
SECRET_KEY=your-super-secret-key-change-in-production
ALGORITHM=HS256
ACCESS_TOKEN_EXPIRE_MINUTES=60
REFRESH_TOKEN_EXPIRE_DAYS=7
# Security
CORS_ORIGINS=["http://localhost:3000"]
RATE_LIMIT=10/minute
# Email (optional)
SMTP_SERVER=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your-email@gmail.com
SMTP_PASSWORD=your-app-password- Set strong
SECRET_KEY - Enable HTTPS only
- Configure CORS properly
- Setup email verification
- Enable rate limiting
- Monitor logs and errors
- Use managed database (not localhost)
- Setup CI/CD pipeline
import logging
logger = logging.getLogger(__name__)
@app.post("/auth/login")
def login(credentials: LoginSchema):
logger.info(f"Login attempt for {credentials.email}")
try:
# auth logic
except Exception as e:
logger.error(f"Login failed: {str(e)}")- OAuth 2.0 / OpenID Connect
- Two-factor authentication (2FA)
- Social login (Google, GitHub)
- Permission scopes (fine-grained)
- API key authentication
- Service-to-service JWT
- Audit logging dashboard
- WebSocket token validation
- Fork the repo
- Create feature branch (
git checkout -b feature/new-auth) - Write tests first
- Commit with clear messages
- Push and create Pull Request