m3mo 911f192c38 Add JWT-based user authentication to backend
- Create User model with bcrypt password hashing
- Add auth routes: register, login, refresh, me
- Implement JWT access and refresh tokens
- Add get_current_user dependency for protected routes
- Update Task model with user_id foreign key for data isolation
- Update TaskService to filter tasks by authenticated user
- Add auth configuration (secret key, token expiry)
2026-02-02 22:57:38 +01:00

68 lines
1.9 KiB
Python

from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
from ..db import get_db
from .schemas import UserCreate, UserLogin, UserResponse, TokenResponse, TokenRefresh
from .services import AuthService
from .dependencies import get_current_user
from .models import User
router = APIRouter(prefix="/auth", tags=["authentication"])
def get_auth_service(db: Session = Depends(get_db)) -> AuthService:
return AuthService(db)
@router.post("/register", response_model=UserResponse, status_code=201)
def register(
user_data: UserCreate,
service: AuthService = Depends(get_auth_service),
):
existing_user = service.get_user_by_email(user_data.email)
if existing_user:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Email already registered",
)
user = service.create_user(user_data)
return user
@router.post("/login", response_model=TokenResponse)
def login(
credentials: UserLogin,
service: AuthService = Depends(get_auth_service),
):
user = service.authenticate_user(credentials.email, credentials.password)
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid email or password",
)
return service.create_tokens(user)
@router.post("/refresh", response_model=TokenResponse)
def refresh(
token_data: TokenRefresh,
service: AuthService = Depends(get_auth_service),
):
tokens = service.refresh_tokens(token_data.refresh_token)
if tokens is None:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid or expired refresh token",
)
return tokens
@router.get("/me", response_model=UserResponse)
def get_current_user_info(
current_user: User = Depends(get_current_user),
):
return current_user