Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions backend/app/core/security.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,12 @@
from datetime import UTC, datetime, timedelta
from typing import Any

import bcrypt
import jwt
from jwt.exceptions import PyJWTError
from passlib.context import CryptContext

from .config import settings

# Password hashing context
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")


def _get_secret_key() -> str:
"""Return the primary signing key, asserting it is configured."""
Expand All @@ -32,12 +29,16 @@ def _refresh_secret() -> str:

def verify_password(plain_password: str, hashed_password: str) -> bool:
"""Verify a password against its hash."""
return pwd_context.verify(plain_password, hashed_password)
return bcrypt.checkpw(
plain_password.encode("utf-8"),
hashed_password.encode("utf-8"),
)


def get_password_hash(password: str) -> str:
"""Generate password hash."""
return pwd_context.hash(password)
salt = bcrypt.gensalt(rounds=12)
return bcrypt.hashpw(password.encode("utf-8"), salt).decode("utf-8")


def create_access_token(
Expand Down
4 changes: 1 addition & 3 deletions backend/requirements-ci.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,7 @@ matplotlib>=3.8.0,<4.0.0

# Authentication & Security
PyJWT[crypto]>=2.8.0,<3.0.0
passlib[bcrypt]>=1.7.4
# bcrypt pinned to <4 — see backend/requirements.txt for context.
bcrypt<4.0
bcrypt>=4.0,<5.0
httpx>=0.26.0

# Utilities
Expand Down
7 changes: 1 addition & 6 deletions backend/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,7 @@ apscheduler>=3.10.0,<4.0.0

# Authentication & Security
PyJWT[crypto]>=2.12.0,<3.0.0
passlib[bcrypt]>=1.7.4,<2.0.0
# bcrypt pinned to <4 because passlib 1.7.4 reads bcrypt.__about__ which was
# removed in bcrypt 4.0 (AttributeError: module 'bcrypt' has no attribute '__about__').
# passlib has no 1.7.5 release, so the dependency stays pinned until either passlib
# ships a fix or this codebase migrates off passlib.
bcrypt<4.0
bcrypt>=4.0,<5.0
httpx>=0.26.0,<1.0.0

# Utilities
Expand Down
2 changes: 1 addition & 1 deletion backend/tests/performance/test_response_times.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
DEALS_THRESHOLD_S = 0.500 # 500 ms
# Login threshold is higher because bcrypt password hashing is intentionally
# slow (~200-400ms per verify) as a brute-force defense mechanism.
# First call also incurs passlib backend initialization overhead.
# First call also incurs bcrypt backend initialization overhead.
LOGIN_THRESHOLD_S = 0.750 # 750 ms (bcrypt-dominated)
PROPERTIES_LIST_THRESHOLD_S = 0.500 # 500 ms
ANALYTICS_THRESHOLD_S = 0.500 # 500 ms
Expand Down
Loading