galaxis-po/backend/app/core/security.py

61 lines
1.7 KiB
Python
Raw Normal View History

"""
Security utilities for authentication.
"""
import hashlib
from datetime import datetime, timedelta, timezone
from typing import Optional
import bcrypt
import jwt
from jwt.exceptions import PyJWTError
from app.core.config import get_settings
settings = get_settings()
def sha256_hash(password: str) -> str:
"""SHA-256 hash a raw password (matches client-side hashing)."""
return hashlib.sha256(password.encode()).hexdigest()
def verify_password(sha256_password: str, hashed_password: str) -> bool:
"""Verify a SHA-256 hashed password against its bcrypt hash."""
return bcrypt.checkpw(
sha256_password.encode(), hashed_password.encode()
)
def get_password_hash(raw_password: str) -> str:
"""Hash a raw password: SHA-256 then bcrypt."""
return bcrypt.hashpw(
sha256_hash(raw_password).encode(), bcrypt.gensalt()
).decode()
def create_access_token(data: dict, expires_delta: Optional[timedelta] = None) -> str:
"""Create a JWT access token."""
to_encode = data.copy()
if expires_delta:
expire = datetime.now(timezone.utc) + expires_delta
else:
expire = datetime.now(timezone.utc) + timedelta(
minutes=settings.access_token_expire_minutes
)
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(
to_encode, settings.jwt_secret, algorithm=settings.jwt_algorithm
)
return encoded_jwt
def decode_access_token(token: str) -> Optional[dict]:
"""Decode and verify a JWT access token."""
try:
payload = jwt.decode(
token, settings.jwt_secret, algorithms=[settings.jwt_algorithm]
)
return payload
except PyJWTError:
return None