File size: 1,358 Bytes
212c959 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | from __future__ import annotations
from datetime import datetime, timedelta, timezone
from typing import Any
from jose import jwt
from passlib.context import CryptContext
from backend.utils.env import Settings
# `bcrypt` backend can be unreliable depending on the environment wheel build.
# pbkdf2_sha256 avoids native bcrypt bindings and works consistently.
pwd_context = CryptContext(
schemes=["pbkdf2_sha256"],
deprecated="auto",
pbkdf2_sha256__rounds=290_000,
)
def hash_password(password: str) -> str:
return pwd_context.hash(password)
def verify_password(password: str, password_hash: str) -> bool:
return pwd_context.verify(password, password_hash)
def create_access_token(settings: Settings, *, subject: str, extra: dict[str, Any] | None = None) -> str:
now = datetime.now(timezone.utc)
exp = now + timedelta(minutes=settings.jwt_exp_minutes)
payload: dict[str, Any] = {
"sub": subject,
"iat": int(now.timestamp()),
"exp": int(exp.timestamp()),
}
if extra:
payload.update(extra)
return jwt.encode(payload, settings.jwt_secret, algorithm=settings.jwt_algorithm)
def decode_token(settings: Settings, token: str) -> dict[str, Any]:
return jwt.decode(token, settings.jwt_secret, algorithms=[settings.jwt_algorithm])
|