Spaces:
Sleeping
Sleeping
| # auth/security.py | |
| # JWT creation/verification and bcrypt password hashing. | |
| # Self-contained β no dependencies on existing app code. | |
| import os | |
| from datetime import datetime, timedelta, timezone | |
| from typing import Optional | |
| import bcrypt | |
| from jose import JWTError, jwt | |
| from dotenv import load_dotenv | |
| load_dotenv() | |
| SECRET_KEY = os.getenv("JWT_SECRET_KEY", "") | |
| ALGORITHM = os.getenv("JWT_ALGORITHM", "HS256") | |
| EXPIRE_MINUTES = int(os.getenv("JWT_EXPIRE_MINUTES", "10080")) # 7 days | |
| if not SECRET_KEY: | |
| raise RuntimeError( | |
| "JWT_SECRET_KEY is not set in .env β " | |
| "run: python -c \"import secrets; print(secrets.token_hex(32))\"" | |
| ) | |
| def hash_password(plaintext: str) -> str: | |
| return bcrypt.hashpw(plaintext.encode('utf-8'), bcrypt.gensalt()).decode('utf-8') | |
| def verify_password(plaintext: str, hashed: str) -> bool: | |
| try: | |
| return bcrypt.checkpw(plaintext.encode('utf-8'), hashed.encode('utf-8')) | |
| except Exception: | |
| return False | |
| def create_access_token(data: dict) -> str: | |
| payload = data.copy() | |
| payload["exp"] = datetime.now(timezone.utc) + timedelta(minutes=EXPIRE_MINUTES) | |
| return jwt.encode(payload, SECRET_KEY, algorithm=ALGORITHM) | |
| def decode_token(token: str) -> Optional[dict]: | |
| """ | |
| Returns the decoded payload dict if token is valid. | |
| Returns None if token is expired or invalid. | |
| """ | |
| try: | |
| return jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) | |
| except JWTError: | |
| return None | |