jamlib 3.1.2__tar.gz → 3.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. {jamlib-3.1.2/src/jamlib.egg-info → jamlib-3.2.0}/PKG-INFO +4 -4
  2. {jamlib-3.1.2 → jamlib-3.2.0}/README.md +3 -3
  3. {jamlib-3.1.2 → jamlib-3.2.0}/pyproject.toml +1 -1
  4. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/__base__.py +160 -39
  5. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/__deprecated__.py +1 -1
  6. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/__init__.py +2 -4
  7. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/aio/__base__.py +119 -2
  8. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/aio/instance.py +177 -17
  9. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/aio/sessions/__base__.py +5 -1
  10. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/exceptions/__init__.py +26 -21
  11. jamlib-3.2.0/src/jam/exceptions/jose.py +73 -0
  12. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/exceptions/jwt.py +9 -2
  13. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/ext/flask/extensions.py +5 -2
  14. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/ext/litestar/middleware.py +4 -3
  15. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/ext/litestar/plugins.py +4 -1
  16. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/ext/starlette/backends.py +5 -2
  17. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/instance.py +165 -14
  18. jamlib-3.2.0/src/jam/jose/__algorithms__.py +1263 -0
  19. jamlib-3.2.0/src/jam/jose/__base__.py +418 -0
  20. jamlib-3.2.0/src/jam/jose/__init__.py +113 -0
  21. jamlib-3.2.0/src/jam/jose/jwe.py +204 -0
  22. jamlib-3.2.0/src/jam/jose/jwk.py +527 -0
  23. jamlib-3.2.0/src/jam/jose/jws.py +211 -0
  24. jamlib-3.2.0/src/jam/jose/jwt.py +608 -0
  25. jamlib-3.2.0/src/jam/jose/lists/__base__.py +40 -0
  26. jamlib-3.2.0/src/jam/jose/lists/__init__.py +11 -0
  27. jamlib-3.2.0/src/jam/jose/lists/json.py +136 -0
  28. jamlib-3.2.0/src/jam/jose/lists/memory.py +111 -0
  29. jamlib-3.2.0/src/jam/jose/lists/redis.py +164 -0
  30. {jamlib-3.1.2/src/jam/jwt → jamlib-3.2.0/src/jam/jose}/utils.py +3 -2
  31. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/jwt/__base__.py +2 -0
  32. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/jwt/__init__.py +1 -1
  33. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/jwt/lists/__base__.py +3 -0
  34. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/jwt/lists/json.py +2 -0
  35. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/jwt/lists/redis.py +2 -0
  36. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/jwt/module.py +2 -0
  37. jamlib-3.2.0/src/jam/jwt/utils.py +36 -0
  38. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/paseto/v1.py +4 -0
  39. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/paseto/v2.py +4 -0
  40. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/paseto/v3.py +4 -0
  41. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/paseto/v4.py +4 -0
  42. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/sessions/__base__.py +5 -1
  43. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/tests/clients.py +302 -28
  44. jamlib-3.2.0/src/jam/tests/fakers.py +187 -0
  45. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/utils/config_maker.py +50 -4
  46. {jamlib-3.1.2 → jamlib-3.2.0/src/jamlib.egg-info}/PKG-INFO +4 -4
  47. {jamlib-3.1.2 → jamlib-3.2.0}/src/jamlib.egg-info/SOURCES.txt +14 -0
  48. jamlib-3.1.2/src/jam/tests/fakers.py +0 -102
  49. {jamlib-3.1.2 → jamlib-3.2.0}/LICENSE.md +0 -0
  50. {jamlib-3.1.2 → jamlib-3.2.0}/setup.cfg +0 -0
  51. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/__base_encoder__.py +0 -0
  52. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/aio/__init__.py +0 -0
  53. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/aio/jwt/__init__.py +0 -0
  54. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/aio/oauth2/__base__.py +0 -0
  55. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/aio/oauth2/__init__.py +0 -0
  56. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/aio/oauth2/builtin/__init__.py +0 -0
  57. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/aio/oauth2/builtin/github.py +0 -0
  58. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/aio/oauth2/builtin/gitlab.py +0 -0
  59. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/aio/oauth2/builtin/google.py +0 -0
  60. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/aio/oauth2/builtin/yandex.py +0 -0
  61. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/aio/oauth2/client.py +0 -0
  62. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/aio/sessions/__init__.py +0 -0
  63. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/aio/sessions/json.py +0 -0
  64. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/aio/sessions/redis.py +0 -0
  65. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/cli/__init__.py +0 -0
  66. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/cli/cli.py +0 -0
  67. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/cli/commands/__init__.py +0 -0
  68. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/cli/commands/keys.py +0 -0
  69. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/cli/commands/password.py +0 -0
  70. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/encoders.py +0 -0
  71. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/exceptions/base.py +0 -0
  72. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/exceptions/oauth2.py +0 -0
  73. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/exceptions/paseto.py +0 -0
  74. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/exceptions/plugins.py +0 -0
  75. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/exceptions/sessions.py +0 -0
  76. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/ext/__init__.py +0 -0
  77. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/ext/fastapi/__init__.py +0 -0
  78. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/ext/flask/__init__.py +0 -0
  79. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/ext/flask/objects.py +0 -0
  80. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/ext/litestar/__init__.py +0 -0
  81. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/ext/litestar/objects.py +0 -0
  82. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/ext/starlette/__init__.py +0 -0
  83. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/ext/starlette/objects.py +0 -0
  84. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/jwt/__algorithms__.py +0 -0
  85. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/jwt/__types__.py +0 -0
  86. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/jwt/lists/__init__.py +0 -0
  87. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/logger.py +0 -0
  88. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/oauth2/__base__.py +0 -0
  89. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/oauth2/__init__.py +0 -0
  90. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/oauth2/builtin/__init__.py +0 -0
  91. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/oauth2/builtin/github.py +0 -0
  92. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/oauth2/builtin/gitlab.py +0 -0
  93. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/oauth2/builtin/google.py +0 -0
  94. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/oauth2/builtin/yandex.py +0 -0
  95. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/oauth2/client.py +0 -0
  96. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/otp/__base__.py +0 -0
  97. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/otp/__init__.py +0 -0
  98. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/otp/hotp.py +0 -0
  99. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/otp/totp.py +0 -0
  100. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/paseto/__base__.py +0 -0
  101. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/paseto/__init__.py +0 -0
  102. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/paseto/utils.py +0 -0
  103. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/plugins/__base__.py +0 -0
  104. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/plugins/__init__.py +0 -0
  105. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/py.typed +0 -0
  106. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/sessions/__init__.py +0 -0
  107. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/sessions/json.py +0 -0
  108. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/sessions/redis.py +0 -0
  109. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/tests/__init__.py +0 -0
  110. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/utils/__init__.py +0 -0
  111. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/utils/aes.py +0 -0
  112. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/utils/await_maybe.py +0 -0
  113. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/utils/basic_auth.py +0 -0
  114. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/utils/ed.py +0 -0
  115. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/utils/otp_keys.py +0 -0
  116. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/utils/rsa.py +0 -0
  117. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/utils/salt_hash.py +0 -0
  118. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/utils/symmetric.py +0 -0
  119. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/utils/version_check.py +0 -0
  120. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/utils/xchacha20poly1305.py +0 -0
  121. {jamlib-3.1.2 → jamlib-3.2.0}/src/jam/utils/xor.py +0 -0
  122. {jamlib-3.1.2 → jamlib-3.2.0}/src/jamlib.egg-info/dependency_links.txt +0 -0
  123. {jamlib-3.1.2 → jamlib-3.2.0}/src/jamlib.egg-info/entry_points.txt +0 -0
  124. {jamlib-3.1.2 → jamlib-3.2.0}/src/jamlib.egg-info/requires.txt +0 -0
  125. {jamlib-3.1.2 → jamlib-3.2.0}/src/jamlib.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jamlib
3
- Version: 3.1.2
3
+ Version: 3.2.0
4
4
  Summary: Simple and universal library for authorization.
5
5
  Author-email: Makridenko Adrian <adrianmakridenko@duck.com>, Ksenia Travnikova <kseniatravnikova@duck.com>
6
6
  License: Apache-2.0
@@ -77,7 +77,7 @@ from jam import Jam
77
77
 
78
78
  jam = Jam(config="config.toml")
79
79
 
80
- jwt = jam.jwt_create({"user": 1})
80
+ jwt = jam.jwt_encode(payload={"user": 1})
81
81
  session_id = jam.session_create(session_key="username", data={"user": 1})
82
82
  otp_code = jam.otp_code(secret="3DB7FOAOFBCI3WFDRE7EPF43CA")
83
83
  ```
@@ -85,7 +85,7 @@ otp_code = jam.otp_code(secret="3DB7FOAOFBCI3WFDRE7EPF43CA")
85
85
  ## Why Jam?
86
86
  Jam is a library that provides the most popular AUTH* mechanisms right out of the box.
87
87
 
88
- * [JWT](https://jam.makridenko.ru/usage/jwt/)
88
+ * [JOSE](https://jam.makridenko.ru/usage/jose/)
89
89
  * [PASETO](https://jam.makridenko.ru/usage/paseto/)
90
90
  * [Server side sessions](https://jam.makridenko.ru/usage/sessions/)
91
91
  * [OTP](https://jam.makridenko.ru/usage/otp/)
@@ -109,7 +109,7 @@ Here is a comparison with other libraries:
109
109
 
110
110
  | Features / Library | **Jam** | [Authx](https://authx.yezz.me/) | [PyJWT](https://pyjwt.readthedocs.io) | [AuthLib](https://docs.authlib.org) | [OTP Auth](https://otp.authlib.org/) |
111
111
  |-----------------------|--------|----------------------------------|---------------------------------------|-------------------------------------|--------------------------------------|
112
- | JWT | ✅ | | | ✅ | ❌ |
112
+ | JOSE | ✅ | ❌ only JWT | ❌ only JWT | ✅ | ❌ |
113
113
  | JWT black/white lists | ✅ | ❌ | ❌ | ❌ | ❌ |
114
114
  | PASETO | ✅ | ❌ | ❌ | ❌ | ❌ |
115
115
  | Server side sessions | ✅ | ✅ | ❌ | ❌ | ❌ |
@@ -24,7 +24,7 @@ from jam import Jam
24
24
 
25
25
  jam = Jam(config="config.toml")
26
26
 
27
- jwt = jam.jwt_create({"user": 1})
27
+ jwt = jam.jwt_encode(payload={"user": 1})
28
28
  session_id = jam.session_create(session_key="username", data={"user": 1})
29
29
  otp_code = jam.otp_code(secret="3DB7FOAOFBCI3WFDRE7EPF43CA")
30
30
  ```
@@ -32,7 +32,7 @@ otp_code = jam.otp_code(secret="3DB7FOAOFBCI3WFDRE7EPF43CA")
32
32
  ## Why Jam?
33
33
  Jam is a library that provides the most popular AUTH* mechanisms right out of the box.
34
34
 
35
- * [JWT](https://jam.makridenko.ru/usage/jwt/)
35
+ * [JOSE](https://jam.makridenko.ru/usage/jose/)
36
36
  * [PASETO](https://jam.makridenko.ru/usage/paseto/)
37
37
  * [Server side sessions](https://jam.makridenko.ru/usage/sessions/)
38
38
  * [OTP](https://jam.makridenko.ru/usage/otp/)
@@ -56,7 +56,7 @@ Here is a comparison with other libraries:
56
56
 
57
57
  | Features / Library | **Jam** | [Authx](https://authx.yezz.me/) | [PyJWT](https://pyjwt.readthedocs.io) | [AuthLib](https://docs.authlib.org) | [OTP Auth](https://otp.authlib.org/) |
58
58
  |-----------------------|--------|----------------------------------|---------------------------------------|-------------------------------------|--------------------------------------|
59
- | JWT | ✅ | | | ✅ | ❌ |
59
+ | JOSE | ✅ | ❌ only JWT | ❌ only JWT | ✅ | ❌ |
60
60
  | JWT black/white lists | ✅ | ❌ | ❌ | ❌ | ❌ |
61
61
  | PASETO | ✅ | ❌ | ❌ | ❌ | ❌ |
62
62
  | Server side sessions | ✅ | ✅ | ❌ | ❌ | ❌ |
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "jamlib"
3
- version = "3.1.2"
3
+ version = "3.2.0"
4
4
  description = "Simple and universal library for authorization."
5
5
  authors = [
6
6
  {name = "Makridenko Adrian",email = "adrianmakridenko@duck.com"},
@@ -10,7 +10,7 @@ from typing import Any, Literal
10
10
  from jam.__base_encoder__ import BaseEncoder
11
11
  from jam.encoders import JsonEncoder
12
12
  from jam.exceptions import JamConfigurationError
13
- from jam.jwt.__base__ import BaseJWT
13
+ from jam.jose.__base__ import BaseJWE, BaseJWS, BaseJWT
14
14
  from jam.logger import BaseLogger, JamLogger
15
15
  from jam.oauth2.__base__ import BaseOAuth2Client
16
16
  from jam.otp.__base__ import BaseOTP, OTPConfig
@@ -23,7 +23,7 @@ from jam.utils.config_maker import __config_maker__, __module_loader__
23
23
  class BaseJam(ABC):
24
24
  """Base jam instance."""
25
25
 
26
- MODULES: dict[str, str] = {}
26
+ MODULES: dict[str, str | dict[str, str]] = {}
27
27
 
28
28
  def __init__(
29
29
  self,
@@ -64,6 +64,9 @@ class BaseJam(ABC):
64
64
  self._plugins = []
65
65
 
66
66
  self.jwt: BaseJWT | None = None
67
+ self.jws: BaseJWS | None = None
68
+ self.jwe: BaseJWE | None = None
69
+ self.jose: dict[str, Any] | None = None
67
70
  self.session: BaseSessionModule | None = None
68
71
  self.oauth2: dict[str, BaseOAuth2Client] | None = None
69
72
  self.otp: OTPConfig | None = None
@@ -78,7 +81,7 @@ class BaseJam(ABC):
78
81
  )
79
82
  self._logger.debug(
80
83
  "BaseJam initialization complete. Modules loaded:\n"
81
- f" jwt={self.jwt is not None}, session={self.session is not None}, oauth2={self.oauth2 is not None}"
84
+ f" jwt={self.jwt is not None}, jose={self.jose is not None}, session={self.session is not None}, oauth2={self.oauth2 is not None}"
82
85
  )
83
86
  if os.getenv("JAM_ENABLE_PLUGINS", "0") == "1":
84
87
  self._logger.warning("Experimental plugins are enabled!")
@@ -151,6 +154,7 @@ class BaseJam(ABC):
151
154
  """Build instance.
152
155
 
153
156
  Load modules from configuration and initialize them.
157
+ Supports both flat modules (name -> path) and nested modules (name -> {subname -> path}).
154
158
 
155
159
  Args:
156
160
  config (dict[str, Any]): Configuration
@@ -163,24 +167,68 @@ class BaseJam(ABC):
163
167
  self._logger.debug(f"Missing configuration for module {name}")
164
168
  continue
165
169
 
166
- try:
167
- module_cls = __module_loader__(path)
168
- self._logger.debug(f"Loading module {name} from {path}")
169
- params = config.get(name, {})
170
- self._logger.debug(
171
- f"Module {name} config params: {list(params.keys())}"
172
- )
173
- # params["logger"] = self._logger
174
- # params["serializer"] = self._serializer
175
- module_instance = module_cls(**params)
176
- self.__setattr__(name, module_instance)
177
- self._logger.debug(f"Module {name} initialized successfully")
178
-
179
- except Exception as e:
180
- self._logger.error(
181
- f"Failed to load module {name} from {path}: {e}",
182
- exc_info=True,
183
- )
170
+ if isinstance(path, dict):
171
+ subconfig = config.get(name, {})
172
+ if not isinstance(subconfig, dict):
173
+ subconfig = {}
174
+
175
+ for subname, subpath in path.items():
176
+ if subname not in subconfig:
177
+ self._logger.debug(
178
+ f"Missing configuration for module {name}.{subname}"
179
+ )
180
+ continue
181
+
182
+ try:
183
+ module_cls = __module_loader__(subpath)
184
+ self._logger.debug(
185
+ f"Loading module {name}.{subname} from {subpath}"
186
+ )
187
+ params = subconfig.get(subname, {})
188
+ self._logger.debug(
189
+ f"Module {name}.{subname} config params: {list(params.keys())}"
190
+ )
191
+ module_instance = module_cls(**params)
192
+
193
+ if self.jose is None:
194
+ self.jose = {}
195
+ self.jose[subname] = module_instance
196
+
197
+ if subname == "jwt":
198
+ self.jwt = module_instance
199
+ elif subname == "jws":
200
+ self.jws = module_instance
201
+ elif subname == "jwe":
202
+ self.jwe = module_instance
203
+
204
+ self._logger.debug(
205
+ f"Module {name}.{subname} initialized successfully"
206
+ )
207
+
208
+ except Exception as e:
209
+ self._logger.error(
210
+ f"Failed to load module {name}.{subname} from {subpath}: {e}",
211
+ exc_info=True,
212
+ )
213
+ else:
214
+ try:
215
+ module_cls = __module_loader__(path)
216
+ self._logger.debug(f"Loading module {name} from {path}")
217
+ params = config.get(name, {})
218
+ self._logger.debug(
219
+ f"Module {name} config params: {list(params.keys())}"
220
+ )
221
+ module_instance = module_cls(**params)
222
+ self.__setattr__(name, module_instance)
223
+ self._logger.debug(
224
+ f"Module {name} initialized successfully"
225
+ )
226
+
227
+ except Exception as e:
228
+ self._logger.error(
229
+ f"Failed to load module {name} from {path}: {e}",
230
+ exc_info=True,
231
+ )
184
232
 
185
233
  def __otp(
186
234
  self, type: Literal["totp", "hotp"] | None = None
@@ -235,47 +283,120 @@ class BaseJam(ABC):
235
283
  return kwargs
236
284
 
237
285
  @abstractmethod
238
- def jwt_make_payload(
239
- self, exp: int | None, data: dict[str, Any]
286
+ def jwt_encode(
287
+ self,
288
+ iss: str | None = None,
289
+ sub: str | None = None,
290
+ aud: str | None = None,
291
+ exp: int | None = None,
292
+ nbf: int | None = None,
293
+ jti: str | None = None,
294
+ *,
295
+ payload: dict[str, Any] | None = None,
296
+ header: dict[str, Any] | None = None,
297
+ ) -> str:
298
+ """Encode the JWT with the given expire, header, and payload.
299
+
300
+ Args:
301
+ exp (int | None): The expiration time in seconds.
302
+ nbf (int | None): The not-before time in seconds.
303
+ iss (str | None): The issuer.
304
+ sub (str | None): The subject.
305
+ aud (str | None): The audience.
306
+ jti (str | None): The JWT ID. If none use the JTI fabric function.
307
+ header (dict[str, Any] | None): The header to include in the JWT.
308
+ payload (dict[str, Any] | None): The payload to include in the JWT.
309
+
310
+ Returns:
311
+ str: The encoded JWT.
312
+ """
313
+ raise NotImplementedError
314
+
315
+ @abstractmethod
316
+ def jwt_decode(
317
+ self,
318
+ token: str,
319
+ check_exp: bool = True,
320
+ check_list: bool = True,
321
+ check_nbf: bool = False,
322
+ include_headers: bool = False,
240
323
  ) -> dict[str, Any]:
241
- """Make JWT-specific payload.
324
+ """Verify and decode JWT token.
242
325
 
243
326
  Args:
244
- exp (int | None): Token expire, if None -> use default
245
- data (dict[str, Any]): Data to payload
327
+ token (str): JWT token
328
+ check_exp (bool): Check expire
329
+ check_list (bool): Check white/black list. Docs: https://jam.makridenko.ru/jwt/lists/what/
330
+ check_nbf (bool): Check not-before time
331
+ include_headers (bool): Include headers in the decoded payload
246
332
 
247
333
  Returns:
248
- dict[str, Any]: Payload
334
+ dict[str, Any]: Decoded payload
335
+
249
336
  """
250
337
  raise NotImplementedError
251
338
 
252
339
  @abstractmethod
253
- def jwt_create(self, payload: dict[str, Any]) -> str:
254
- """Create JWT token.
340
+ def jws_sign(
341
+ self,
342
+ data: dict[str, Any] | str,
343
+ header: dict[str, Any] | None = None,
344
+ ) -> str:
345
+ """Sign data using JWS.
255
346
 
256
347
  Args:
257
- payload (dict[str, Any]): Data payload
348
+ data: Data to sign. If dict, will be JSON encoded.
349
+ header: JWS header.
258
350
 
259
351
  Returns:
260
- str: New token
352
+ str: JWS token.
353
+ """
354
+ raise NotImplementedError
355
+
356
+ @abstractmethod
357
+ def jws_verify(self, token: str) -> dict[str, Any]:
358
+ """Verify JWS token.
359
+
360
+ Args:
361
+ token: JWS token.
362
+
363
+ Returns:
364
+ dict[str, Any]: Decoded payload.
261
365
 
366
+ Raises:
367
+ JamJWSVerificationError: If verification fails.
262
368
  """
263
369
  raise NotImplementedError
264
370
 
265
371
  @abstractmethod
266
- def jwt_decode(
267
- self, token: str, check_exp: bool = True, check_list: bool = True
268
- ) -> dict[str, Any]:
269
- """Verify and decode JWT token.
372
+ def jwe_encrypt(
373
+ self,
374
+ data: dict[str, Any] | str,
375
+ header: dict[str, Any] | None = None,
376
+ ) -> str:
377
+ """Encrypt data using JWE.
270
378
 
271
379
  Args:
272
- token (str): JWT token
273
- check_exp (bool): Check expire
274
- check_list (bool): Check white/black list. Docs: https://jam.makridenko.ru/jwt/lists/what/
380
+ data: Data to encrypt. If dict, will be JSON encoded.
381
+ header: JWE header.
275
382
 
276
383
  Returns:
277
- dict[str, Any]: Decoded payload
384
+ str: JWE token.
385
+ """
386
+ raise NotImplementedError
387
+
388
+ @abstractmethod
389
+ def jwe_decrypt(self, token: str) -> bytes:
390
+ """Decrypt JWE token.
391
+
392
+ Args:
393
+ token: JWE token.
394
+
395
+ Returns:
396
+ bytes: Decrypted data.
278
397
 
398
+ Raises:
399
+ JamJWEDecryptionError: If decryption fails.
279
400
  """
280
401
  raise NotImplementedError
281
402
 
@@ -8,7 +8,7 @@ def deprecated(replacement: str | None = None):
8
8
  """Mark funcs are deprecated."""
9
9
 
10
10
  def decorator(func):
11
- msg = f"Function {func.__name__}() is deprecated."
11
+ msg = f"{func.__name__}() is deprecated."
12
12
  if replacement:
13
13
  msg += f" {replacement}"
14
14
 
@@ -7,10 +7,8 @@ Documentation: https://jam.makridenko.ru
7
7
  """
8
8
 
9
9
  from jam.__base__ import BaseJam
10
- from jam.__base_encoder__ import BaseEncoder
11
- from jam.encoders import JsonEncoder
12
10
  from jam.instance import Jam
13
11
 
14
12
 
15
- __version__ = "3.1.2"
16
- __all__ = ["Jam", "JsonEncoder", "BaseJam", "BaseEncoder"]
13
+ __version__ = "3.2.0"
14
+ __all__ = ["Jam", "BaseJam"]
@@ -4,24 +4,35 @@ from abc import abstractmethod
4
4
  from typing import Any
5
5
 
6
6
  from jam.__base__ import BaseJam
7
+ from jam.__deprecated__ import deprecated
7
8
  from jam.aio.oauth2.__base__ import BaseAsyncOAuth2Client
8
9
  from jam.aio.sessions.__base__ import BaseAsyncSessionModule
10
+ from jam.jose.__base__ import BaseJWE, BaseJWS
9
11
 
10
12
 
11
13
  class BaseAsyncJam(BaseJam):
12
14
  """Base async jam instance."""
13
15
 
14
- MODULES: dict[str, str] = {}
16
+ MODULES: dict[str, str | dict[str, str]] = {}
15
17
 
16
18
  session: BaseAsyncSessionModule | None = None # type: ignore[override]
17
19
  oauth2: dict[str, BaseAsyncOAuth2Client] | None = None # type: ignore[override]
20
+ jose: dict[str, Any] | None = None # type: ignore[override]
21
+ jws: BaseJWS | None = None # type: ignore[override]
22
+ jwe: BaseJWE | None = None # type: ignore[override]
18
23
 
19
24
  @abstractmethod
25
+ @deprecated(
26
+ "This method is deprecated; the JWT payload is generated automatically in accordance with the specification."
27
+ )
20
28
  async def jwt_make_payload( # type: ignore[override]
21
29
  self, exp: int | None, data: dict[str, Any]
22
30
  ) -> dict[str, Any]:
23
31
  """Make JWT-specific payload.
24
32
 
33
+ !!! Deprecated
34
+ This method is deprecated; the JWT payload is generated automatically in accordance with the specification.
35
+
25
36
  Args:
26
37
  exp (int | None): Token expire, if None -> use default
27
38
  data (dict[str, Any]): Data to payload
@@ -32,6 +43,7 @@ class BaseAsyncJam(BaseJam):
32
43
  raise NotImplementedError
33
44
 
34
45
  @abstractmethod
46
+ @deprecated("Use jam.jwt_encode")
35
47
  async def jwt_create( # type: ignore[override]
36
48
  self, payload: dict[str, Any]
37
49
  ) -> str:
@@ -45,9 +57,44 @@ class BaseAsyncJam(BaseJam):
45
57
  """
46
58
  raise NotImplementedError
47
59
 
60
+ @abstractmethod
61
+ async def jwt_encode( # type: ignore[override]
62
+ self,
63
+ iss: str | None = None,
64
+ sub: str | None = None,
65
+ aud: str | None = None,
66
+ exp: int | None = None,
67
+ nbf: int | None = None,
68
+ jti: str | None = None,
69
+ *,
70
+ payload: dict[str, Any] | None = None,
71
+ header: dict[str, Any] | None = None,
72
+ ) -> str:
73
+ """Encode the JWT with the given expire, header, and payload.
74
+
75
+ Args:
76
+ exp (int | None): The expiration time in seconds.
77
+ nbf (int | None): The not-before time in seconds.
78
+ iss (str | None): The issuer.
79
+ sub (str | None): The subject.
80
+ aud (str | None): The audience.
81
+ jti (str | None): The JWT ID. If none use the JTI fabric function.
82
+ header (dict[str, Any] | None): The header to include in the JWT.
83
+ payload (dict[str, Any] | None): The payload to include in the JWT.
84
+
85
+ Returns:
86
+ str: The encoded JWT.
87
+ """
88
+ raise NotImplementedError
89
+
48
90
  @abstractmethod
49
91
  async def jwt_decode( # type: ignore[override]
50
- self, token: str, check_exp: bool = True, check_list: bool = True
92
+ self,
93
+ token: str,
94
+ check_exp: bool = True,
95
+ check_list: bool = True,
96
+ check_nbf: bool = False,
97
+ include_headers: bool = False,
51
98
  ) -> dict[str, Any]:
52
99
  """Verify and decode JWT token.
53
100
 
@@ -55,6 +102,8 @@ class BaseAsyncJam(BaseJam):
55
102
  token (str): JWT token
56
103
  check_exp (bool): Check expire
57
104
  check_list (bool): Check white/black list. Docs: https://jam.makridenko.ru/jwt/lists/what/
105
+ check_nbf (bool): Check not-before time
106
+ include_headers (bool): Include headers in the decoded payload
58
107
 
59
108
  Returns:
60
109
  dict[str, Any]: Decoded payload
@@ -305,6 +354,74 @@ class BaseAsyncJam(BaseJam):
305
354
  """
306
355
  raise NotImplementedError
307
356
 
357
+ @abstractmethod
358
+ async def jws_sign( # type: ignore[override]
359
+ self,
360
+ data: dict[str, Any] | str,
361
+ header: dict[str, Any] | None = None,
362
+ ) -> str:
363
+ """Sign data using JWS.
364
+
365
+ Args:
366
+ data: Data to sign. If dict, will be JSON encoded.
367
+ header: JWS header.
368
+
369
+ Returns:
370
+ str: JWS token.
371
+ """
372
+ raise NotImplementedError
373
+
374
+ @abstractmethod
375
+ async def jws_verify( # type: ignore[override]
376
+ self, token: str
377
+ ) -> dict[str, Any]:
378
+ """Verify JWS token.
379
+
380
+ Args:
381
+ token: JWS token.
382
+
383
+ Returns:
384
+ dict[str, Any]: Decoded payload.
385
+
386
+ Raises:
387
+ JamJWSVerificationError: If verification fails.
388
+ """
389
+ raise NotImplementedError
390
+
391
+ @abstractmethod
392
+ async def jwe_encrypt( # type: ignore[override]
393
+ self,
394
+ data: dict[str, Any] | str,
395
+ header: dict[str, Any] | None = None,
396
+ ) -> str:
397
+ """Encrypt data using JWE.
398
+
399
+ Args:
400
+ data: Data to encrypt. If dict, will be JSON encoded.
401
+ header: JWE header.
402
+
403
+ Returns:
404
+ str: JWE token.
405
+ """
406
+ raise NotImplementedError
407
+
408
+ @abstractmethod
409
+ async def jwe_decrypt( # type: ignore[override]
410
+ self, token: str
411
+ ) -> bytes:
412
+ """Decrypt JWE token.
413
+
414
+ Args:
415
+ token: JWE token.
416
+
417
+ Returns:
418
+ bytes: Decrypted data.
419
+
420
+ Raises:
421
+ JamJWEDecryptionError: If decryption fails.
422
+ """
423
+ raise NotImplementedError
424
+
308
425
  @abstractmethod
309
426
  async def paseto_decode( # type: ignore[override]
310
427
  self, token: str, check_exp: bool = True, check_list: bool = True