MotorSignal-App/backend/motorsignal_api/app/auth.py

90 lines
1.9 KiB
Python

import hashlib
import os
import secrets
import uuid
from datetime import datetime, timedelta, timezone
import jwt
from pwdlib import PasswordHash
password_hash = PasswordHash.recommended()
JWT_SECRET = os.environ["JWT_SECRET"]
ACCESS_TOKEN_MINUTES = int(os.environ.get("ACCESS_TOKEN_MINUTES", "15"))
REFRESH_TOKEN_DAYS = int(os.environ.get("REFRESH_TOKEN_DAYS", "30"))
JWT_ALGORITHM = "HS256"
def normalize_email(email: str) -> str:
return email.strip().lower()
def hash_password(password: str) -> str:
return password_hash.hash(password)
def verify_password(password: str, hashed: str) -> bool:
return password_hash.verify(password, hashed)
def create_access_token(
user_id: uuid.UUID,
session_id: uuid.UUID,
) -> str:
now = datetime.now(timezone.utc)
payload = {
"sub": str(user_id),
"sid": str(session_id),
"iat": now,
"exp": now + timedelta(minutes=ACCESS_TOKEN_MINUTES),
"type": "access",
}
return jwt.encode(
payload,
JWT_SECRET,
algorithm=JWT_ALGORITHM,
)
def create_refresh_token() -> tuple[str, str]:
raw = secrets.token_urlsafe(64)
digest = hashlib.sha256(
raw.encode("utf-8")
).hexdigest()
return raw, digest
def hash_refresh_token(token: str) -> str:
return hashlib.sha256(
token.encode("utf-8")
).hexdigest()
def create_one_time_token() -> tuple[str, str]:
raw = secrets.token_urlsafe(48)
return raw, hashlib.sha256(raw.encode("utf-8")).hexdigest()
def hash_one_time_token(token: str) -> str:
return hashlib.sha256(token.encode("utf-8")).hexdigest()
def refresh_expiry() -> datetime:
return datetime.now(timezone.utc) + timedelta(
days=REFRESH_TOKEN_DAYS
)
def decode_access_token(token: str) -> dict:
return jwt.decode(
token,
JWT_SECRET,
algorithms=[JWT_ALGORITHM],
)