46 lines
1.1 KiB
Python
46 lines
1.1 KiB
Python
"""Token value objects — framework-free.
|
|
|
|
The auth flow issues a short-lived *access* token and a long-lived *refresh*
|
|
token (offline-first: clients may stay disconnected for weeks). Refresh tokens
|
|
are persisted and revocable (see :class:`~app.domain.ports.RefreshTokenRepository`);
|
|
access tokens are stateless and verified by signature + expiry alone.
|
|
"""
|
|
|
|
import datetime as dt
|
|
import enum
|
|
import uuid
|
|
from dataclasses import dataclass
|
|
|
|
|
|
class TokenType(enum.StrEnum):
|
|
ACCESS = "access"
|
|
REFRESH = "refresh"
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class TokenClaims:
|
|
"""Decoded, verified claims from a JWT."""
|
|
|
|
subject: uuid.UUID # user id (``sub``)
|
|
token_type: TokenType
|
|
jti: uuid.UUID
|
|
expires_at: dt.datetime
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class IssuedToken:
|
|
"""A freshly minted token: the encoded string plus the metadata needed to
|
|
persist/track it (jti, expiry)."""
|
|
|
|
encoded: str
|
|
jti: uuid.UUID
|
|
expires_at: dt.datetime
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class TokenPair:
|
|
"""The access + refresh pair returned to clients on login/refresh."""
|
|
|
|
access: IssuedToken
|
|
refresh: IssuedToken
|