Files
boc/landvex-admin/backend/app/core/security.py
T
Bernt aee0f09db8 landvex: Fixar och tester klara för alla komponenter
- Datafabrik: Dockerfile fix, agentorkestrering fungerar
- Vision: Identify-modell, FAISS, OCR alla testade
- API: Alla 7 integrationstester passerade
- Upplösare: Entitetsupplösning verifierad
2026-07-05 06:41:32 +00:00

104 lines
2.7 KiB
Python

"""Security utilities for authentication and authorization."""
from datetime import datetime, timedelta
from typing import Any
from uuid import UUID
import jwt
from passlib.context import CryptContext
from app.config import settings
# Password hashing with Argon2id
pwd_context = CryptContext(schemes=["argon2"], deprecated="auto")
def verify_password(plain_password: str, hashed_password: str) -> bool:
"""Verify a plain password against a hash."""
return pwd_context.verify(plain_password, hashed_password)
def get_password_hash(password: str) -> str:
"""Hash a password using Argon2id."""
return pwd_context.hash(password)
def create_access_token(
subject: UUID | str,
tenant_id: UUID | None = None,
scopes: list[str] | None = None,
expires_delta: timedelta | None = None,
) -> str:
"""Create JWT access token."""
if expires_delta:
expire = datetime.utcnow() + expires_delta
else:
expire = datetime.utcnow() + timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
to_encode: dict[str, Any] = {
"sub": str(subject),
"exp": expire,
"iat": datetime.utcnow(),
"type": "access",
}
if tenant_id:
to_encode["tenant_id"] = str(tenant_id)
if scopes:
to_encode["scopes"] = scopes
encoded_jwt = jwt.encode(
to_encode, settings.SECRET_KEY, algorithm=settings.JWT_ALGORITHM
)
return encoded_jwt
def create_refresh_token(subject: UUID | str) -> str:
"""Create JWT refresh token."""
expire = datetime.utcnow() + timedelta(days=settings.REFRESH_TOKEN_EXPIRE_DAYS)
to_encode: dict[str, Any] = {
"sub": str(subject),
"exp": expire,
"iat": datetime.utcnow(),
"type": "refresh",
}
encoded_jwt = jwt.encode(
to_encode, settings.SECRET_KEY, algorithm=settings.JWT_ALGORITHM
)
return encoded_jwt
def decode_token(token: str) -> dict[str, Any]:
"""Decode and validate JWT token."""
return jwt.decode(
token, settings.SECRET_KEY, algorithms=[settings.JWT_ALGORITHM]
)
def generate_api_key() -> tuple[str, str]:
"""Generate a new API key and its hash.
Returns:
Tuple of (full_key, key_hash)
"""
import secrets
import hashlib
# Generate random key: lv_<32 random chars>
random_part = secrets.token_urlsafe(32)
full_key = f"lv_{random_part}"
# Hash for storage
key_hash = hashlib.sha256(full_key.encode()).hexdigest()
return full_key, key_hash
def verify_api_key(plain_key: str, key_hash: str) -> bool:
"""Verify an API key against its hash."""
import hashlib
computed_hash = hashlib.sha256(plain_key.encode()).hexdigest()
return computed_hash == key_hash