59 lines
1.7 KiB
Python
59 lines
1.7 KiB
Python
"""Authentication routes."""
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, status
|
|
from sqlalchemy import select
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from tradingagents.api.database import get_db
|
|
from tradingagents.api.models import User
|
|
from tradingagents.api.schemas.auth import LoginRequest, TokenResponse
|
|
from tradingagents.api.services.auth_service import verify_password, create_access_token
|
|
|
|
|
|
router = APIRouter(prefix="/auth", tags=["Authentication"])
|
|
|
|
|
|
@router.post("/login", response_model=TokenResponse)
|
|
async def login(
|
|
credentials: LoginRequest,
|
|
db: AsyncSession = Depends(get_db)
|
|
) -> TokenResponse:
|
|
"""
|
|
Authenticate user and return JWT token.
|
|
|
|
Args:
|
|
credentials: Username and password
|
|
db: Database session
|
|
|
|
Returns:
|
|
TokenResponse: JWT access token
|
|
|
|
Raises:
|
|
HTTPException: If credentials are invalid
|
|
"""
|
|
# Get user by username
|
|
result = await db.execute(
|
|
select(User).where(User.username == credentials.username)
|
|
)
|
|
user = result.scalar_one_or_none()
|
|
|
|
# Verify user exists and password is correct
|
|
if user is None or not verify_password(credentials.password, user.hashed_password):
|
|
raise HTTPException(
|
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
detail="Incorrect username or password",
|
|
headers={"WWW-Authenticate": "Bearer"},
|
|
)
|
|
|
|
# Check if user is active
|
|
if not user.is_active:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_403_FORBIDDEN,
|
|
detail="Inactive user"
|
|
)
|
|
|
|
# Create JWT token
|
|
access_token = create_access_token(data={"sub": user.username})
|
|
|
|
return TokenResponse(access_token=access_token, token_type="bearer")
|