39 lines
1.3 KiB
Python
39 lines
1.3 KiB
Python
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
|