import hashlib import os import secrets import uuid from datetime import datetime, timedelta, timezone import jwt from pwdlib import PasswordHash password_hash = PasswordHash.recommended() JWT_SECRET = os.environ["JWT_SECRET"] ACCESS_TOKEN_MINUTES = int(os.environ.get("ACCESS_TOKEN_MINUTES", "15")) REFRESH_TOKEN_DAYS = int(os.environ.get("REFRESH_TOKEN_DAYS", "30")) JWT_ALGORITHM = "HS256" def normalize_email(email: str) -> str: return email.strip().lower() def hash_password(password: str) -> str: return password_hash.hash(password) def verify_password(password: str, hashed: str) -> bool: return password_hash.verify(password, hashed) def create_access_token( user_id: uuid.UUID, session_id: uuid.UUID, ) -> str: now = datetime.now(timezone.utc) payload = { "sub": str(user_id), "sid": str(session_id), "iat": now, "exp": now + timedelta(minutes=ACCESS_TOKEN_MINUTES), "type": "access", } return jwt.encode( payload, JWT_SECRET, algorithm=JWT_ALGORITHM, ) def create_refresh_token() -> tuple[str, str]: raw = secrets.token_urlsafe(64) digest = hashlib.sha256( raw.encode("utf-8") ).hexdigest() return raw, digest def hash_refresh_token(token: str) -> str: return hashlib.sha256( token.encode("utf-8") ).hexdigest() def create_one_time_token() -> tuple[str, str]: raw = secrets.token_urlsafe(48) return raw, hashlib.sha256(raw.encode("utf-8")).hexdigest() def hash_one_time_token(token: str) -> str: return hashlib.sha256(token.encode("utf-8")).hexdigest() def refresh_expiry() -> datetime: return datetime.now(timezone.utc) + timedelta( days=REFRESH_TOKEN_DAYS ) def decode_access_token(token: str) -> dict: return jwt.decode( token, JWT_SECRET, algorithms=[JWT_ALGORITHM], )