Coverage for src / lexigram / contracts / auth / token.py: 100%
20 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-19 05:41 +0800
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-19 05:41 +0800
1"""Token management protocols.
3Protocols for JWT token creation, validation, and refresh.
4"""
6from __future__ import annotations
8from dataclasses import dataclass
9from typing import TYPE_CHECKING, Any, Protocol, runtime_checkable
11if TYPE_CHECKING:
12 from datetime import datetime
14 from lexigram.contracts.auth.exceptions import TokenError
15 from lexigram.contracts.auth.user import AuthenticatedUserProtocol
16 from lexigram.contracts.core.result import Result
19@dataclass(frozen=True)
20class VerifiedToken:
21 """Decoded and validated JWT token payload.
23 Returned when token verification succeeds. All fields are extracted from
24 the verified JWT claims so callers never need to inspect raw ``dict``
25 payloads.
27 Attributes:
28 user_id: Subject claim (``sub``), identifying the token owner.
29 email: Email address of the token owner.
30 name: Display name of the token owner.
31 roles: List of role identifiers granted to the user.
32 permissions: List of permission identifiers granted to the user.
33 expires_at: Absolute UTC datetime at which the token expires.
34 key_id: Key ID (``kid`` header) used to sign this token.
35 token_type: Token kind — ``"access"`` or ``"refresh"``.
36 audience: Audience claim (``aud``), or ``None`` if absent.
37 """
39 user_id: str
40 email: str
41 name: str
42 roles: list[str]
43 permissions: list[str]
44 expires_at: datetime
45 key_id: str
46 token_type: str # "access" or "refresh"
47 audience: str | None = None
50@runtime_checkable
51class TokenManagerProtocol(Protocol):
52 """Protocol for token management implementations.
54 Defines the contract for JWT token creation, verification,
55 and refresh operations.
57 Example:
58 ```python
59 class JWTTokenManager:
60 def create_token(self, user: AuthenticatedUserProtocol) -> AuthToken:
61 payload = {"sub": user.user_id, "roles": user.roles}
62 access = jwt.encode(payload, self._secret, algorithm="HS256")
63 return AuthToken(access_token=access, ...)
64 ```
65 """
67 def create_token(self, user: AuthenticatedUserProtocol) -> Any:
68 """Create an authentication token for a user.
70 Args:
71 user: The authenticated user.
73 Returns:
74 AuthToken containing access and refresh tokens.
75 """
76 ...
78 def verify_token(self, token: str) -> Result[VerifiedToken, TokenError]:
79 """Verify and decode a token.
81 Returns a ``Result`` rather than raising domain exceptions so that
82 the caller can pattern-match on success vs. failure explicitly.
83 Infrastructure errors (cache unavailable, network failure) are still
84 raised as exceptions and must not be wrapped in ``Result``.
86 Args:
87 token: The JWT token string.
89 Returns:
90 ``Ok(VerifiedToken)`` if the token is valid and not revoked,
91 or ``Err(TokenError)`` for any expected domain failure.
92 """
93 ...
95 def refresh_token(self, refresh_token: str) -> Result[Any, TokenError]:
96 """Refresh an access token using a refresh token.
98 Args:
99 refresh_token: The refresh token string.
101 Returns:
102 ``Ok(AuthToken)`` if the refresh token is valid, or
103 ``Err(TokenError)`` for expected domain failures.
104 """
105 ...
108__all__ = [
109 "TokenManagerProtocol",
110 "VerifiedToken",
111]