import hashlib import uuid from datetime import timedelta from typing import Any from jose import jwt from passlib.context import CryptContext from app.config import settings from app.utils import utcnow pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") ALGORITHM = "HS256" def hash_password(password: str) -> str: return pwd_context.hash(password) def verify_password(plain_password: str, hashed_password: str) -> bool: return pwd_context.verify(plain_password, hashed_password) def create_access_token(data: dict[str, Any]) -> str: to_encode = data.copy() to_encode["exp"] = utcnow() + timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES) return jwt.encode(to_encode, settings.SECRET_KEY, algorithm=ALGORITHM) def create_refresh_token(data: dict[str, Any]) -> str: to_encode = data.copy() to_encode["exp"] = utcnow() + timedelta(days=settings.REFRESH_TOKEN_EXPIRE_DAYS) # jti ensures each token is unique even when issued for the same user at the same time to_encode["jti"] = str(uuid.uuid4()) return jwt.encode(to_encode, settings.SECRET_KEY, algorithm=ALGORITHM) def decode_token(token: str) -> dict[str, Any]: """Decode and verify a JWT token. Raises jose.JWTError on failure.""" return jwt.decode(token, settings.SECRET_KEY, algorithms=[ALGORITHM]) def hash_token(token: str) -> str: """Return SHA-256 hex digest of a token for safe storage.""" return hashlib.sha256(token.encode()).hexdigest()