Download backend/api/auth.py from NOT-OMEGA/AutoForge: direct link, hf CLI and curl.
- Browser
- Download file 3.81 kB
-
https://huggingface.co/spaces/NOT-OMEGA/AutoForge/resolve/main/backend/api/auth.py
- Command line
-
hf download hf://spaces/NOT-OMEGA/AutoForge/backend/api/auth.py
-
curl -L -o auth.py https://huggingface.co/spaces/NOT-OMEGA/AutoForge/resolve/main/backend/api/auth.py
3.81 kB
| """Authentication API: signup, login, and current-user retrieval.""" | |
| from datetime import datetime, timedelta, timezone | |
| from fastapi import APIRouter, Depends, HTTPException, status | |
| from jose import jwt | |
| from passlib.context import CryptContext | |
| from pydantic import BaseModel, EmailStr, Field | |
| from sqlalchemy.ext.asyncio import AsyncSession | |
| from backend.api.deps import get_current_user, get_db | |
| from backend.config.settings import get_settings | |
| from backend.db.models import User | |
| from backend.db.repository import create_user, get_user_by_email, get_user_by_username | |
| router = APIRouter(prefix="/api/auth", tags=["auth"]) | |
| pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") | |
| # ββ Schemas ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| class SignupRequest(BaseModel): | |
| username: str = Field(..., min_length=3, max_length=80) | |
| email: EmailStr | |
| password: str = Field(..., min_length=6) | |
| class LoginRequest(BaseModel): | |
| username: str | |
| password: str | |
| class TokenResponse(BaseModel): | |
| access_token: str | |
| token_type: str = "bearer" | |
| class UserResponse(BaseModel): | |
| id: str | |
| username: str | |
| email: str | |
| created_at: datetime | |
| model_config = {"from_attributes": True} | |
| # ββ Helpers ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def _hash_password(password: str) -> str: | |
| return pwd_context.hash(password) | |
| def _verify_password(plain: str, hashed: str) -> bool: | |
| return pwd_context.verify(plain, hashed) | |
| def _create_token(user_id: str) -> str: | |
| settings = get_settings() | |
| expire = datetime.now(timezone.utc) + timedelta(minutes=settings.jwt_expire_minutes) | |
| payload = {"sub": user_id, "exp": expire} | |
| return jwt.encode(payload, settings.secret_key, algorithm=settings.jwt_algorithm) | |
| # ββ Routes βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| async def signup(body: SignupRequest, session: AsyncSession = Depends(get_db)): | |
| """Register a new user account.""" | |
| # Check for duplicate username | |
| if await get_user_by_username(session, body.username): | |
| raise HTTPException( | |
| status_code=status.HTTP_409_CONFLICT, | |
| detail="Username already taken", | |
| ) | |
| # Check for duplicate email | |
| if await get_user_by_email(session, body.email): | |
| raise HTTPException( | |
| status_code=status.HTTP_409_CONFLICT, | |
| detail="Email already registered", | |
| ) | |
| user = await create_user( | |
| session, | |
| username=body.username, | |
| email=body.email, | |
| hashed_password=_hash_password(body.password), | |
| ) | |
| return TokenResponse(access_token=_create_token(user.id)) | |
| async def login(body: LoginRequest, session: AsyncSession = Depends(get_db)): | |
| """Authenticate and receive a JWT.""" | |
| user = await get_user_by_username(session, body.username) | |
| if not user or not _verify_password(body.password, user.hashed_password): | |
| raise HTTPException( | |
| status_code=status.HTTP_401_UNAUTHORIZED, | |
| detail="Invalid username or password", | |
| ) | |
| return TokenResponse(access_token=_create_token(user.id)) | |
| async def me(current_user: User = Depends(get_current_user)): | |
| """Return the currently authenticated user.""" | |
| return current_user | |