"""Security utilities for authentication and password management. This module provides: - Password hashing and verification using bcrypt - JWT token creation and validation - Security-related helper functions """ import bcrypt from datetime import datetime, timedelta, timezone from typing import Any, Optional from jose import jwt from app.core.config import get_settings settings = get_settings() def verify_password(plain_password: str, hashed_password: str) -> bool: """Verify a plain password against a hashed password. Args: plain_password: The plain text password to verify hashed_password: The bcrypt hashed password from database Returns: True if password matches, False otherwise """ return bcrypt.checkpw( plain_password.encode('utf-8'), hashed_password.encode('utf-8') ) def get_password_hash(password: str) -> str: """Generate a bcrypt hash from a plain password. Args: password: The plain text password to hash Returns: Bcrypt hashed password string """ return bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8') def create_access_token( data: dict[str, Any], expires_delta: Optional[timedelta] = None, ) -> str: """Create a JWT access token. This function creates a JWT token with the provided data payload. The token includes an expiration time and is signed with the application's secret key. Args: data: Dictionary of claims to encode in the token (e.g., {"sub": user_id}) expires_delta: Optional custom expiration time. Defaults to settings.ACCESS_TOKEN_EXPIRE_MINUTES Returns: Encoded JWT string Example: >>> token = create_access_token({"sub": str(user.id)}) >>> # Use token in Authorization: Bearer header """ to_encode = data.copy() # Calculate expiration time if expires_delta: expire = datetime.now(timezone.utc) + expires_delta else: expire = datetime.now(timezone.utc) + timedelta( minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES ) # Add expiration and issued at claims to_encode.update({ "exp": expire, "iat": datetime.now(timezone.utc), "type": "access", }) # Encode the JWT encoded_jwt = jwt.encode( to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM, ) return encoded_jwt def decode_access_token(token: str) -> dict[str, Any]: """Decode and validate a JWT access token. Args: token: The JWT string to decode Returns: Dictionary containing the token payload Raises: jwt.JWTError: If token is invalid or expired """ return jwt.decode( token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM], )