first commit - MVE Incrementables Parser microservice with FastAPI, JWT, Celery, Redis

This commit is contained in:
Ernesto Herrera
2026-03-02 21:31:50 -07:00
commit 068d859f42
27 changed files with 2337 additions and 0 deletions

61
app/api/auth.py Normal file
View File

@@ -0,0 +1,61 @@
"""Authentication endpoints."""
from fastapi import APIRouter, HTTPException, status, Request
from datetime import timedelta
import logging
from app.core.config import get_settings
from app.core.security import authenticate_user, create_access_token, check_rate_limit
from app.schemas import LoginRequest, LoginResponse
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/auth", tags=["Authentication"])
@router.post("/login", response_model=LoginResponse)
async def login(request: Request, credentials: LoginRequest):
"""
Authenticate user and return JWT token.
- **username**: Username
- **password**: Password
Returns JWT access token with expiration time.
"""
settings = get_settings()
# Get client IP for rate limiting
client_ip = request.client.host if request.client else "unknown"
# Check rate limit
if check_rate_limit(client_ip):
logger.warning(f"Rate limit exceeded for IP: {client_ip}")
raise HTTPException(
status_code=status.HTTP_429_TOO_MANY_REQUESTS,
detail="Too many login attempts. Please try again later."
)
# Authenticate (never log the password)
logger.info(f"Login attempt for user: {credentials.username} from IP: {client_ip}")
if not authenticate_user(credentials.username, credentials.password):
logger.warning(f"Failed login attempt for user: {credentials.username}")
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid credentials",
headers={"WWW-Authenticate": "Bearer"},
)
# Create access token
access_token_expires = timedelta(minutes=settings.jwt_expires_minutes)
access_token = create_access_token(
data={"sub": credentials.username},
expires_delta=access_token_expires
)
logger.info(f"Successful login for user: {credentials.username}")
return LoginResponse(
access_token=access_token,
token_type="bearer",
expires_in=settings.jwt_expires_minutes * 60 # Convert to seconds
)