from datetime import datetime, timedelta, timezone from jose import JWTError, jwt from passlib.context import CryptContext from app.config import settings pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") ALGORITHM = "HS256" 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_access_token(user_id: int) -> str: expire = datetime.now(timezone.utc) + timedelta(minutes=settings.JWT_EXPIRE_MINUTES) return jwt.encode( {"sub": str(user_id), "exp": expire}, settings.JWT_SECRET_KEY, algorithm=ALGORITHM, ) def decode_token(token: str) -> int: """Decode JWT and return user_id. Raises JWTError on failure.""" payload = jwt.decode(token, settings.JWT_SECRET_KEY, algorithms=[ALGORITHM]) user_id = payload.get("sub") if user_id is None: raise JWTError("Missing sub claim") return int(user_id)