From eb79bec92e042125450cba3db5422a16bed1b532 Mon Sep 17 00:00:00 2001 From: Agzamus Date: Mon, 12 Oct 2026 16:25:39 +0300 Subject: [PATCH] =?UTF-8?q?feat:=206.1=20=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20=D0=BC=D0=BE=D0=B4=D1=83=D0=BB=D1=8C=20`app/core?= =?UTF-8?q?/jwt.py`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/core/jwt.py | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 app/core/jwt.py diff --git a/app/core/jwt.py b/app/core/jwt.py new file mode 100644 index 0000000..801d856 --- /dev/null +++ b/app/core/jwt.py @@ -0,0 +1,38 @@ +from datetime import datetime, timedelta, timezone +from typing import Any +from uuid import uuid4 + +from jose import JWTError, jwt + +from app.config import settings + + +# формирует JWT с claim'ами: +# sub (email или id пользователя), +# iat, +# exp, +# jti (случайный идентификатор), +# typ: "access", +# подписывает HS256 секретом из настроек; +def create_access_token(sub: str, ttl_min: int | None = None) -> str: + now = datetime.now(timezone.utc) + ttl = ttl_min if ttl_min is not None else settings.access_token_ttl_min + payload: dict[str, Any] = { + "sub": sub, + "iat": now, + "exp": now + timedelta(minutes=ttl), + "jti": uuid4().hex, + "typ": "access", + } + return jwt.encode(payload, settings.jwt_secret, algorithm=settings.jwt_algorithm) + + +# decode_token(token) – декодирует и проверяет подпись/срок, +# при ошибке бросает `ValueError` с понятным сообщением. +def decode_token(token: str) -> dict[str, Any]: + try: + return jwt.decode( + token, settings.jwt_secret, algorithms=[settings.jwt_algorithm] + ) + except JWTError as exc: + raise ValueError(f"Invalid token: {exc}") from exc