synapse / backend /app /api /auth.py
adwitiyashukla's picture
updated code
48954a5
Raw History Blame Contribute Delete
3.21 kB
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy import func, select
from app.api.deps import DB, CurrentUser, rate_limit_auth, rate_limit_demo_session
from app.config import get_settings
from app.core.security import (
create_access_token,
create_refresh_token,
decode_token,
hash_password,
verify_password,
)
from app.demo import create_guest_user
from app.models import User
from app.schemas import (
LoginRequest,
RefreshRequest,
RegisterRequest,
TokenPair,
UserOut,
)
router = APIRouter(prefix="/auth", tags=["auth"], dependencies=[Depends(rate_limit_auth)])
def _issue_tokens(user_id: int) -> TokenPair:
return TokenPair(
access_token=create_access_token(user_id),
refresh_token=create_refresh_token(user_id),
)
@router.post("/register", response_model=TokenPair, status_code=status.HTTP_201_CREATED)
async def register(body: RegisterRequest, db: DB) -> TokenPair:
email = body.email.lower()
existing = await db.execute(
select(User).where(func.lower(User.email) == email)
)
if existing.scalar_one_or_none() is not None:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
detail="An account with this email already exists",
)
user = User(
email=email,
username=body.username.strip(),
password_hash=hash_password(body.password),
)
db.add(user)
await db.commit()
await db.refresh(user)
return _issue_tokens(user.id)
@router.post("/login", response_model=TokenPair)
async def login(body: LoginRequest, db: DB) -> TokenPair:
result = await db.execute(
select(User).where(func.lower(User.email) == body.email.lower())
)
user = result.scalar_one_or_none()
if user is None or not verify_password(body.password, user.password_hash):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect email or password",
)
return _issue_tokens(user.id)
@router.post("/refresh", response_model=TokenPair)
async def refresh(body: RefreshRequest, db: DB) -> TokenPair:
user_id = decode_token(body.refresh_token, expected_type="refresh")
if user_id is None:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid or expired refresh token",
)
user = await db.get(User, user_id)
if user is None or not user.is_active:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, detail="User not found"
)
return _issue_tokens(user.id)
@router.post(
"/demo",
response_model=TokenPair,
status_code=status.HTTP_201_CREATED,
dependencies=[Depends(rate_limit_demo_session)],
)
async def demo_session(db: DB) -> TokenPair:
if not get_settings().demo_mode:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Demo mode is disabled"
)
guest = await create_guest_user(db)
return _issue_tokens(guest.id)
@router.get("/me", response_model=UserOut)
async def me(user: CurrentUser) -> UserOut:
return UserOut.model_validate(user)