| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798 |
- """
- Security utilities: JWT tokens, password hashing.
- """
- from datetime import datetime, timedelta, timezone
- from typing import Any
- from jose import JWTError, jwt
- from passlib.context import CryptContext
- from app.config import settings
- # Password hashing context
- pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
- def create_access_token(data: dict[str, Any]) -> str:
- """
- Create JWT access token.
- Args:
- data: Payload to encode (typically {"sub": user_id})
- Returns:
- Encoded JWT token string
- """
- to_encode = data.copy()
- expire = datetime.now(timezone.utc) + timedelta(
- minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES
- )
- to_encode.update({"exp": expire, "type": "access"})
- return jwt.encode(to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM)
- def create_refresh_token(data: dict[str, Any]) -> str:
- """
- Create JWT refresh token.
- Args:
- data: Payload to encode (typically {"sub": user_id})
- Returns:
- Encoded JWT token string
- """
- to_encode = data.copy()
- expire = datetime.now(timezone.utc) + timedelta(
- days=settings.REFRESH_TOKEN_EXPIRE_DAYS
- )
- to_encode.update({"exp": expire, "type": "refresh"})
- return jwt.encode(to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM)
- def verify_token(token: str, expected_type: str = "access") -> dict[str, Any] | None:
- """
- Verify and decode JWT token.
- Args:
- token: JWT token string
- expected_type: Expected token type ("access" or "refresh")
- Returns:
- Decoded payload if valid, None otherwise
- """
- try:
- payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM])
- token_type: str = payload.get("type")
- if token_type != expected_type:
- return None
- return payload
- except JWTError:
- return None
- def verify_password(plain_password: str, hashed_password: str) -> bool:
- """
- Verify a plain password against a hashed password.
- Args:
- plain_password: Plain text password
- hashed_password: Hashed password from database
- Returns:
- True if password matches, False otherwise
- """
- return pwd_context.verify(plain_password, hashed_password)
- def hash_password(password: str) -> str:
- """
- Hash a password using bcrypt.
- Args:
- password: Plain text password
- Returns:
- Hashed password
- """
- return pwd_context.hash(password)
|