jamlib 3.1.0__tar.gz → 3.2.0b1__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.
- {jamlib-3.1.0/src/jamlib.egg-info → jamlib-3.2.0b1}/PKG-INFO +1 -1
- {jamlib-3.1.0 → jamlib-3.2.0b1}/pyproject.toml +1 -1
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/__base__.py +29 -22
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/__deprecated__.py +1 -1
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/__init__.py +1 -1
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/aio/__base__.py +36 -1
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/aio/instance.py +76 -7
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/exceptions/__init__.py +26 -21
- jamlib-3.2.0b1/src/jam/exceptions/jose.py +23 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/exceptions/jwt.py +9 -2
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/instance.py +79 -10
- jamlib-3.2.0b1/src/jam/jose/__algorithms__.py +1161 -0
- jamlib-3.2.0b1/src/jam/jose/__base__.py +338 -0
- jamlib-3.2.0b1/src/jam/jose/__init__.py +19 -0
- jamlib-3.2.0b1/src/jam/jose/jwe.py +199 -0
- jamlib-3.2.0b1/src/jam/jose/jwk.py +506 -0
- jamlib-3.2.0b1/src/jam/jose/jws.py +192 -0
- jamlib-3.2.0b1/src/jam/jose/jwt.py +544 -0
- jamlib-3.2.0b1/src/jam/jose/lists/__base__.py +40 -0
- jamlib-3.2.0b1/src/jam/jose/lists/__init__.py +11 -0
- jamlib-3.2.0b1/src/jam/jose/lists/json.py +136 -0
- jamlib-3.2.0b1/src/jam/jose/lists/memory.py +111 -0
- jamlib-3.2.0b1/src/jam/jose/lists/redis.py +161 -0
- {jamlib-3.1.0/src/jam/jwt → jamlib-3.2.0b1/src/jam/jose}/utils.py +3 -2
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/jwt/__base__.py +2 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/jwt/lists/__base__.py +3 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/jwt/lists/json.py +2 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/jwt/lists/redis.py +2 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/jwt/module.py +2 -0
- jamlib-3.2.0b1/src/jam/jwt/utils.py +36 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/tests/clients.py +56 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1/src/jamlib.egg-info}/PKG-INFO +1 -1
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jamlib.egg-info/SOURCES.txt +14 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/LICENSE.md +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/README.md +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/setup.cfg +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/__base_encoder__.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/aio/__init__.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/aio/jwt/__init__.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/aio/oauth2/__base__.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/aio/oauth2/__init__.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/aio/oauth2/builtin/__init__.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/aio/oauth2/builtin/github.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/aio/oauth2/builtin/gitlab.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/aio/oauth2/builtin/google.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/aio/oauth2/builtin/yandex.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/aio/oauth2/client.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/aio/sessions/__base__.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/aio/sessions/__init__.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/aio/sessions/json.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/aio/sessions/redis.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/cli/__init__.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/cli/cli.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/cli/commands/__init__.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/cli/commands/keys.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/cli/commands/password.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/encoders.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/exceptions/base.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/exceptions/oauth2.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/exceptions/paseto.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/exceptions/plugins.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/exceptions/sessions.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/ext/__init__.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/ext/fastapi/__init__.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/ext/flask/__init__.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/ext/flask/extensions.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/ext/flask/objects.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/ext/litestar/__init__.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/ext/litestar/middleware.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/ext/litestar/objects.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/ext/litestar/plugins.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/ext/starlette/__init__.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/ext/starlette/backends.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/ext/starlette/objects.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/jwt/__algorithms__.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/jwt/__init__.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/jwt/__types__.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/jwt/lists/__init__.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/logger.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/oauth2/__base__.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/oauth2/__init__.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/oauth2/builtin/__init__.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/oauth2/builtin/github.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/oauth2/builtin/gitlab.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/oauth2/builtin/google.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/oauth2/builtin/yandex.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/oauth2/client.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/otp/__base__.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/otp/__init__.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/otp/hotp.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/otp/totp.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/paseto/__base__.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/paseto/__init__.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/paseto/utils.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/paseto/v1.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/paseto/v2.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/paseto/v3.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/paseto/v4.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/py.typed +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/sessions/__base__.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/sessions/__init__.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/sessions/json.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/sessions/redis.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/tests/__init__.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/tests/fakers.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/utils/__init__.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/utils/aes.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/utils/await_maybe.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/utils/basic_auth.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/utils/config_maker.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/utils/ed.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/utils/otp_keys.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/utils/rsa.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/utils/salt_hash.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/utils/symmetric.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/utils/xchacha20poly1305.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jam/utils/xor.py +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jamlib.egg-info/dependency_links.txt +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jamlib.egg-info/entry_points.txt +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jamlib.egg-info/requires.txt +0 -0
- {jamlib-3.1.0 → jamlib-3.2.0b1}/src/jamlib.egg-info/top_level.txt +0 -0
|
@@ -6,7 +6,7 @@ from typing import Any, Literal
|
|
|
6
6
|
|
|
7
7
|
from jam.encoders import BaseEncoder, JsonEncoder
|
|
8
8
|
from jam.exceptions import JamConfigurationError
|
|
9
|
-
from jam.
|
|
9
|
+
from jam.jose.__base__ import BaseJWT
|
|
10
10
|
from jam.logger import BaseLogger, JamLogger
|
|
11
11
|
from jam.oauth2.__base__ import BaseOAuth2Client
|
|
12
12
|
from jam.otp.__base__ import BaseOTP, OTPConfig
|
|
@@ -189,36 +189,41 @@ class BaseJam(ABC):
|
|
|
189
189
|
raise JamConfigurationError(message="Unknown OTP type.")
|
|
190
190
|
|
|
191
191
|
@abstractmethod
|
|
192
|
-
def
|
|
193
|
-
self,
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
"""
|
|
204
|
-
raise NotImplementedError
|
|
205
|
-
|
|
206
|
-
@abstractmethod
|
|
207
|
-
def jwt_create(self, payload: dict[str, Any]) -> str:
|
|
208
|
-
"""Create JWT token.
|
|
192
|
+
def jwt_encode(
|
|
193
|
+
self,
|
|
194
|
+
iss: str | None = None,
|
|
195
|
+
sub: str | None = None,
|
|
196
|
+
aud: str | None = None,
|
|
197
|
+
exp: int | None = None,
|
|
198
|
+
nbf: int | None = None,
|
|
199
|
+
*,
|
|
200
|
+
payload: dict[str, Any] | None = None,
|
|
201
|
+
header: dict[str, Any] | None = None,
|
|
202
|
+
) -> str:
|
|
203
|
+
"""Encode the JWT with the given expire, header, and payload.
|
|
209
204
|
|
|
210
205
|
Args:
|
|
211
|
-
|
|
206
|
+
exp (int | None): The expiration time in seconds.
|
|
207
|
+
nbf (int | None): The not-before time in seconds.
|
|
208
|
+
iss (str | None): The issuer.
|
|
209
|
+
sub (str | None): The subject.
|
|
210
|
+
aud (str | None): The audience.
|
|
211
|
+
header (dict[str, Any] | None): The header to include in the JWT.
|
|
212
|
+
payload (dict[str, Any] | None): The payload to include in the JWT.
|
|
212
213
|
|
|
213
214
|
Returns:
|
|
214
|
-
str:
|
|
215
|
-
|
|
215
|
+
str: The encoded JWT.
|
|
216
216
|
"""
|
|
217
217
|
raise NotImplementedError
|
|
218
218
|
|
|
219
219
|
@abstractmethod
|
|
220
220
|
def jwt_decode(
|
|
221
|
-
self,
|
|
221
|
+
self,
|
|
222
|
+
token: str,
|
|
223
|
+
check_exp: bool = True,
|
|
224
|
+
check_list: bool = True,
|
|
225
|
+
check_nbf: bool = False,
|
|
226
|
+
include_headers: bool = False,
|
|
222
227
|
) -> dict[str, Any]:
|
|
223
228
|
"""Verify and decode JWT token.
|
|
224
229
|
|
|
@@ -226,6 +231,8 @@ class BaseJam(ABC):
|
|
|
226
231
|
token (str): JWT token
|
|
227
232
|
check_exp (bool): Check expire
|
|
228
233
|
check_list (bool): Check white/black list. Docs: https://jam.makridenko.ru/jwt/lists/what/
|
|
234
|
+
check_nbf (bool): Check not-before time
|
|
235
|
+
include_headers (bool): Include headers in the decoded payload
|
|
229
236
|
|
|
230
237
|
Returns:
|
|
231
238
|
dict[str, Any]: Decoded payload
|
|
@@ -45,9 +45,42 @@ class BaseAsyncJam(BaseJam):
|
|
|
45
45
|
"""
|
|
46
46
|
raise NotImplementedError
|
|
47
47
|
|
|
48
|
+
@abstractmethod
|
|
49
|
+
async def jwt_encode(
|
|
50
|
+
self,
|
|
51
|
+
iss: str | None = None,
|
|
52
|
+
sub: str | None = None,
|
|
53
|
+
aud: str | None = None,
|
|
54
|
+
exp: int | None = None,
|
|
55
|
+
nbf: int | None = None,
|
|
56
|
+
*,
|
|
57
|
+
payload: dict[str, Any] | None = None,
|
|
58
|
+
header: dict[str, Any] | None = None,
|
|
59
|
+
) -> str:
|
|
60
|
+
"""Encode the JWT with the given expire, header, and payload.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
exp (int | None): The expiration time in seconds.
|
|
64
|
+
nbf (int | None): The not-before time in seconds.
|
|
65
|
+
iss (str | None): The issuer.
|
|
66
|
+
sub (str | None): The subject.
|
|
67
|
+
aud (str | None): The audience.
|
|
68
|
+
header (dict[str, Any] | None): The header to include in the JWT.
|
|
69
|
+
payload (dict[str, Any] | None): The payload to include in the JWT.
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
str: The encoded JWT.
|
|
73
|
+
"""
|
|
74
|
+
raise NotImplementedError
|
|
75
|
+
|
|
48
76
|
@abstractmethod
|
|
49
77
|
async def jwt_decode( # type: ignore[override]
|
|
50
|
-
self,
|
|
78
|
+
self,
|
|
79
|
+
token: str,
|
|
80
|
+
check_exp: bool = True,
|
|
81
|
+
check_list: bool = True,
|
|
82
|
+
check_nbf: bool = False,
|
|
83
|
+
include_headers: bool = False,
|
|
51
84
|
) -> dict[str, Any]:
|
|
52
85
|
"""Verify and decode JWT token.
|
|
53
86
|
|
|
@@ -55,6 +88,8 @@ class BaseAsyncJam(BaseJam):
|
|
|
55
88
|
token (str): JWT token
|
|
56
89
|
check_exp (bool): Check expire
|
|
57
90
|
check_list (bool): Check white/black list. Docs: https://jam.makridenko.ru/jwt/lists/what/
|
|
91
|
+
check_nbf (bool): Check not-before time
|
|
92
|
+
include_headers (bool): Include headers in the decoded payload
|
|
58
93
|
|
|
59
94
|
Returns:
|
|
60
95
|
dict[str, Any]: Decoded payload
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
|
|
3
3
|
import datetime
|
|
4
|
+
import time
|
|
4
5
|
from typing import Any
|
|
5
6
|
import uuid
|
|
6
7
|
|
|
@@ -10,6 +11,7 @@ from jam.exceptions import (
|
|
|
10
11
|
JamJWTExpired,
|
|
11
12
|
JamJWTInBlackList,
|
|
12
13
|
JamJWTNotInWhiteList,
|
|
14
|
+
JamJWTNotYetValid,
|
|
13
15
|
)
|
|
14
16
|
|
|
15
17
|
|
|
@@ -68,8 +70,52 @@ class Jam(BaseAsyncJam):
|
|
|
68
70
|
|
|
69
71
|
return token
|
|
70
72
|
|
|
73
|
+
async def jwt_encode(
|
|
74
|
+
self,
|
|
75
|
+
iss: str | None = None,
|
|
76
|
+
sub: str | None = None,
|
|
77
|
+
aud: str | None = None,
|
|
78
|
+
exp: int | None = None,
|
|
79
|
+
nbf: int | None = None,
|
|
80
|
+
*,
|
|
81
|
+
payload: dict[str, Any] | None = None,
|
|
82
|
+
header: dict[str, Any] | None = None,
|
|
83
|
+
) -> str:
|
|
84
|
+
"""Encode the JWT with the given expire, header, and payload.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
exp (int | None): The expiration time in seconds.
|
|
88
|
+
nbf (int | None): The not-before time in seconds.
|
|
89
|
+
iss (str | None): The issuer.
|
|
90
|
+
sub (str | None): The subject.
|
|
91
|
+
aud (str | None): The audience.
|
|
92
|
+
header (dict[str, Any] | None): The header to include in the JWT.
|
|
93
|
+
payload (dict[str, Any] | None): The payload to include in the JWT.
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
str: The encoded JWT.
|
|
97
|
+
"""
|
|
98
|
+
assert self.jwt is not None
|
|
99
|
+
token = self.jwt.encode(
|
|
100
|
+
iss=iss,
|
|
101
|
+
sub=sub,
|
|
102
|
+
aud=aud,
|
|
103
|
+
exp=exp,
|
|
104
|
+
nbf=nbf,
|
|
105
|
+
payload=payload,
|
|
106
|
+
header=header,
|
|
107
|
+
)
|
|
108
|
+
if self.jwt.list and self.jwt.list.__list_type__ == "white":
|
|
109
|
+
self.jwt.list.add(token)
|
|
110
|
+
return token
|
|
111
|
+
|
|
71
112
|
async def jwt_decode(
|
|
72
|
-
self,
|
|
113
|
+
self,
|
|
114
|
+
token: str,
|
|
115
|
+
check_exp: bool = True,
|
|
116
|
+
check_list: bool = True,
|
|
117
|
+
check_nbf: bool = False,
|
|
118
|
+
include_headers: bool = False,
|
|
73
119
|
) -> dict[str, Any]:
|
|
74
120
|
"""Verify and decode JWT token.
|
|
75
121
|
|
|
@@ -77,23 +123,43 @@ class Jam(BaseAsyncJam):
|
|
|
77
123
|
token (str): JWT token
|
|
78
124
|
check_exp (bool): Check expire
|
|
79
125
|
check_list (bool): Check white/black list. Docs: https://jam.makridenko.ru/jwt/lists/what/
|
|
126
|
+
check_nbf (bool): Check not-before time
|
|
127
|
+
include_headers (bool): Include headers in the decoded payload
|
|
80
128
|
|
|
81
129
|
Returns:
|
|
82
130
|
dict[str, Any]: Decoded payload
|
|
131
|
+
|
|
132
|
+
Raises:
|
|
133
|
+
JamJWTExpired: If token is expired
|
|
134
|
+
JamJWTNotYetValid: If token is not yet valid (nbf claim)
|
|
135
|
+
JamConfigurationError: If JWT list is not connected
|
|
136
|
+
JamJWTNotInWhiteList: If token is not in white list
|
|
137
|
+
JamJWTInBlackList: If token is in black list
|
|
83
138
|
"""
|
|
84
139
|
assert self.jwt is not None
|
|
85
140
|
self._logger.debug(
|
|
86
|
-
f"Verifying JWT token (length: {len(token)} chars), check_exp={check_exp}, check_list={check_list}"
|
|
141
|
+
f"Verifying JWT token (length: {len(token)} chars), check_exp={check_exp}, check_list={check_list}, check_nbf={check_nbf}"
|
|
87
142
|
)
|
|
88
|
-
|
|
143
|
+
data = self.jwt.decode(token)
|
|
144
|
+
if "payload" in data:
|
|
145
|
+
payload = data["payload"]
|
|
146
|
+
headers = data.get("header")
|
|
147
|
+
else:
|
|
148
|
+
payload = data
|
|
149
|
+
headers = None
|
|
150
|
+
|
|
151
|
+
if check_exp and "exp" in payload:
|
|
152
|
+
if payload["exp"] < time.time():
|
|
153
|
+
raise JamJWTExpired
|
|
154
|
+
|
|
155
|
+
if check_nbf and "nbf" in payload:
|
|
156
|
+
if payload["nbf"] > time.time():
|
|
157
|
+
raise JamJWTNotYetValid
|
|
158
|
+
|
|
89
159
|
self._logger.debug(
|
|
90
160
|
f"JWT token verified successfully, payload keys: {list(payload.keys())}"
|
|
91
161
|
)
|
|
92
162
|
|
|
93
|
-
if check_exp:
|
|
94
|
-
if payload["exp"] < datetime.datetime.now().timestamp():
|
|
95
|
-
raise JamJWTExpired
|
|
96
|
-
|
|
97
163
|
if check_list:
|
|
98
164
|
if not self.jwt.list:
|
|
99
165
|
raise JamConfigurationError(
|
|
@@ -113,6 +179,9 @@ class Jam(BaseAsyncJam):
|
|
|
113
179
|
message="Invalid JWT list type",
|
|
114
180
|
error_code="configuration.jwt.unknown_list_type",
|
|
115
181
|
)
|
|
182
|
+
|
|
183
|
+
if include_headers and headers is not None:
|
|
184
|
+
return {"header": headers, "payload": payload}
|
|
116
185
|
return payload
|
|
117
186
|
|
|
118
187
|
async def session_create(
|
|
@@ -1,49 +1,49 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
|
|
3
|
-
"""
|
|
4
|
-
All Jam exceptions
|
|
5
|
-
"""
|
|
3
|
+
"""All Jam exceptions"""
|
|
6
4
|
|
|
7
|
-
from .base import
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
5
|
+
from .base import JamConfigurationError, JamError, JamValidationError
|
|
6
|
+
from .jose import (
|
|
7
|
+
JamJWEEncryptionError,
|
|
8
|
+
JamJWEDecryptionError,
|
|
9
|
+
JamJWKValidationError,
|
|
10
|
+
JamJWSVerificationError,
|
|
13
11
|
)
|
|
14
|
-
|
|
15
12
|
from .jwt import (
|
|
13
|
+
JamJWTEmptyPrivateKey,
|
|
14
|
+
JamJWTEmptySecretKey,
|
|
16
15
|
JamJWTExpired,
|
|
17
16
|
JamJWTInBlackList,
|
|
18
17
|
JamJWTNotInWhiteList,
|
|
19
|
-
|
|
20
|
-
JamJWTEmptySecretKey,
|
|
18
|
+
JamJWTNotYetValid,
|
|
21
19
|
JamJWTUnsupportedAlgorithm,
|
|
22
20
|
JamJWTValidationError,
|
|
23
21
|
)
|
|
24
|
-
|
|
22
|
+
from .oauth2 import (
|
|
23
|
+
JamOAuth2EmptyRaw,
|
|
24
|
+
JamOAuth2Error,
|
|
25
|
+
JamOAuth2ProviderNotConfigured,
|
|
26
|
+
)
|
|
25
27
|
from .paseto import (
|
|
26
|
-
JamPASETOInvalidSymmetricKey,
|
|
27
|
-
JamPASETOInvalidRSAKey,
|
|
28
28
|
JamPASETOInvalidED25519Key,
|
|
29
|
-
JamPASETOInvalidSecp384r1Key,
|
|
30
|
-
JamPASTOKeyVerificationError,
|
|
31
29
|
JamPASETOInvalidPurpose,
|
|
30
|
+
JamPASETOInvalidRSAKey,
|
|
31
|
+
JamPASETOInvalidSecp384r1Key,
|
|
32
|
+
JamPASETOInvalidSymmetricKey,
|
|
32
33
|
JamPASETOInvalidTokenFormat,
|
|
34
|
+
JamPASTOKeyVerificationError,
|
|
33
35
|
)
|
|
34
|
-
|
|
35
36
|
from .plugins import (
|
|
36
37
|
JamFlaskPluginConfigError,
|
|
37
38
|
JamFlaskPluginError,
|
|
38
39
|
JamLitestarPluginConfigError,
|
|
39
40
|
JamLitestarPluginError,
|
|
40
41
|
JamStarlettePluginConfigError,
|
|
41
|
-
JamStarlettePluginError
|
|
42
|
+
JamStarlettePluginError,
|
|
42
43
|
)
|
|
43
|
-
|
|
44
44
|
from .sessions import (
|
|
45
|
-
JamSessionNotFound,
|
|
46
45
|
JamSessionEmptyAESKey,
|
|
46
|
+
JamSessionNotFound,
|
|
47
47
|
)
|
|
48
48
|
|
|
49
49
|
|
|
@@ -57,10 +57,15 @@ __all__ = [
|
|
|
57
57
|
"JamJWTExpired",
|
|
58
58
|
"JamJWTInBlackList",
|
|
59
59
|
"JamJWTNotInWhiteList",
|
|
60
|
+
"JamJWTNotYetValid",
|
|
60
61
|
"JamJWTEmptyPrivateKey",
|
|
61
62
|
"JamJWTEmptySecretKey",
|
|
62
63
|
"JamJWTUnsupportedAlgorithm",
|
|
63
64
|
"JamJWTValidationError",
|
|
65
|
+
"JamJWSVerificationError",
|
|
66
|
+
"JamJWKValidationError",
|
|
67
|
+
"JamJWEEncryptionError",
|
|
68
|
+
"JamJWEDecryptionError",
|
|
64
69
|
"JamPASETOInvalidSymmetricKey",
|
|
65
70
|
"JamPASETOInvalidRSAKey",
|
|
66
71
|
"JamPASETOInvalidED25519Key",
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from .base import JamValidationError
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class JamJWSVerificationError(JamValidationError):
|
|
7
|
+
default_message = "JWS signature verification failed."
|
|
8
|
+
default_code = "jws.verification_error"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class JamJWKValidationError(JamValidationError):
|
|
12
|
+
default_message = "JWK validation failed."
|
|
13
|
+
default_code = "jwk.validation_error"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class JamJWEEncryptionError(JamValidationError):
|
|
17
|
+
default_message = "JWE encryption failed."
|
|
18
|
+
default_code = "jwe.encryption_error"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class JamJWEDecryptionError(JamValidationError):
|
|
22
|
+
default_message = "JWE decryption failed."
|
|
23
|
+
default_code = "jwe.decryption_error"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
|
|
3
|
-
from .base import JamError, JamValidationError
|
|
3
|
+
from .base import JamConfigurationError, JamError, JamValidationError
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
class JamJWTExpired(JamError):
|
|
@@ -8,6 +8,11 @@ class JamJWTExpired(JamError):
|
|
|
8
8
|
default_code = "jwt.token_expired"
|
|
9
9
|
|
|
10
10
|
|
|
11
|
+
class JamJWTNotYetValid(JamError):
|
|
12
|
+
default_message = "Token is not yet valid (nbf claim)."
|
|
13
|
+
default_code = "jwt.token_not_yet_valid"
|
|
14
|
+
|
|
15
|
+
|
|
11
16
|
class JamJWTInBlackList(JamError):
|
|
12
17
|
default_message = "Token in blacklist."
|
|
13
18
|
default_code = "jwt.blacklist"
|
|
@@ -24,7 +29,9 @@ class JamJWTEmptySecretKey(JamConfigurationError):
|
|
|
24
29
|
|
|
25
30
|
|
|
26
31
|
class JamJWTEmptyPrivateKey(JamConfigurationError):
|
|
27
|
-
default_message =
|
|
32
|
+
default_message = (
|
|
33
|
+
"For asymmetric encryption, you must specify `private_key`."
|
|
34
|
+
)
|
|
28
35
|
default_code = "jwt.config.empty_private_key"
|
|
29
36
|
|
|
30
37
|
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
|
|
3
3
|
import datetime
|
|
4
|
+
import time
|
|
4
5
|
from typing import Any
|
|
5
6
|
import uuid
|
|
6
7
|
|
|
7
8
|
from jam.__base__ import BaseJam
|
|
9
|
+
from jam.__deprecated__ import deprecated
|
|
8
10
|
from jam.exceptions import (
|
|
9
11
|
JamConfigurationError,
|
|
10
12
|
JamJWTExpired,
|
|
11
13
|
JamJWTInBlackList,
|
|
12
14
|
JamJWTNotInWhiteList,
|
|
15
|
+
JamJWTNotYetValid,
|
|
13
16
|
)
|
|
14
17
|
|
|
15
18
|
|
|
@@ -17,18 +20,24 @@ class Jam(BaseJam):
|
|
|
17
20
|
"""Main instance."""
|
|
18
21
|
|
|
19
22
|
MODULES: dict[str, str] = {
|
|
20
|
-
"jwt": "jam.
|
|
23
|
+
"jwt": "jam.jose.JWT",
|
|
21
24
|
"session": "jam.sessions.create_instance",
|
|
22
25
|
"oauth2": "jam.oauth2.create_instance",
|
|
23
26
|
"paseto": "jam.paseto.create_instance",
|
|
24
27
|
"otp": "jam.otp.__base__.OTPConfig",
|
|
25
28
|
}
|
|
26
29
|
|
|
30
|
+
@deprecated(
|
|
31
|
+
"This method is deprecated; the JWT payload is generated automatically in accordance with the specification."
|
|
32
|
+
)
|
|
27
33
|
def jwt_make_payload(
|
|
28
34
|
self, exp: int | None, data: dict[str, Any]
|
|
29
35
|
) -> dict[str, Any]:
|
|
30
36
|
"""Make JWT-specific payload.
|
|
31
37
|
|
|
38
|
+
!!! Deprecated
|
|
39
|
+
This method is deprecated; the JWT payload is generated automatically in accordance with the specification.
|
|
40
|
+
|
|
32
41
|
Args:
|
|
33
42
|
exp (int | None): Token expire
|
|
34
43
|
data (dict[str, Any]): Data to payload
|
|
@@ -44,9 +53,13 @@ class Jam(BaseJam):
|
|
|
44
53
|
payload = payload | data
|
|
45
54
|
return payload
|
|
46
55
|
|
|
56
|
+
@deprecated("Use jam.jwt_encode")
|
|
47
57
|
def jwt_create(self, payload: dict[str, Any]) -> str:
|
|
48
58
|
"""Create JWT token.
|
|
49
59
|
|
|
60
|
+
!!! Deprecated
|
|
61
|
+
Use Jam.jwt_encode
|
|
62
|
+
|
|
50
63
|
Args:
|
|
51
64
|
payload (dict[str, Any]): Data payload
|
|
52
65
|
|
|
@@ -68,8 +81,52 @@ class Jam(BaseJam):
|
|
|
68
81
|
|
|
69
82
|
return token
|
|
70
83
|
|
|
84
|
+
def jwt_encode(
|
|
85
|
+
self,
|
|
86
|
+
iss: str | None = None,
|
|
87
|
+
sub: str | None = None,
|
|
88
|
+
aud: str | None = None,
|
|
89
|
+
exp: int | None = None,
|
|
90
|
+
nbf: int | None = None,
|
|
91
|
+
*,
|
|
92
|
+
payload: dict[str, Any] | None = None,
|
|
93
|
+
header: dict[str, Any] | None = None,
|
|
94
|
+
) -> str:
|
|
95
|
+
"""Encode the JWT with the given expire, header, and payload.
|
|
96
|
+
|
|
97
|
+
Args:
|
|
98
|
+
exp (int | None): The expiration time in seconds.
|
|
99
|
+
nbf (int | None): The not-before time in seconds.
|
|
100
|
+
iss (str | None): The issuer.
|
|
101
|
+
sub (str | None): The subject.
|
|
102
|
+
aud (str | None): The audience.
|
|
103
|
+
header (dict[str, Any] | None): The header to include in the JWT.
|
|
104
|
+
payload (dict[str, Any] | None): The payload to include in the JWT.
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
str: The encoded JWT.
|
|
108
|
+
"""
|
|
109
|
+
assert self.jwt is not None
|
|
110
|
+
token = self.jwt.encode(
|
|
111
|
+
iss=iss,
|
|
112
|
+
sub=sub,
|
|
113
|
+
aud=aud,
|
|
114
|
+
exp=exp,
|
|
115
|
+
nbf=nbf,
|
|
116
|
+
payload=payload,
|
|
117
|
+
header=header,
|
|
118
|
+
)
|
|
119
|
+
if self.jwt.list and self.jwt.list.__list_type__ == "white":
|
|
120
|
+
self.jwt.list.add(token)
|
|
121
|
+
return token
|
|
122
|
+
|
|
71
123
|
def jwt_decode(
|
|
72
|
-
self,
|
|
124
|
+
self,
|
|
125
|
+
token: str,
|
|
126
|
+
check_exp: bool = True,
|
|
127
|
+
check_list: bool = True,
|
|
128
|
+
check_nbf: bool = False,
|
|
129
|
+
include_headers: bool = False,
|
|
73
130
|
) -> dict[str, Any]:
|
|
74
131
|
"""Verify and decode JWT token.
|
|
75
132
|
|
|
@@ -77,29 +134,38 @@ class Jam(BaseJam):
|
|
|
77
134
|
token (str): JWT token
|
|
78
135
|
check_exp (bool): Check expire
|
|
79
136
|
check_list (bool): Check white/black list. Docs: https://jam.makridenko.ru/jwt/lists/what/
|
|
137
|
+
check_nbf (bool): Check not-before time
|
|
138
|
+
include_headers (bool): Include headers in the decoded payload
|
|
80
139
|
|
|
81
140
|
Returns:
|
|
82
141
|
dict[str, Any]: Decoded payload
|
|
83
142
|
|
|
84
143
|
Raises:
|
|
85
144
|
JamJWTExpired: If token is expired
|
|
145
|
+
JamJWTNotYetValid: If token is not yet valid (nbf claim)
|
|
86
146
|
JamConfigurationError: If JWT list is not connected
|
|
87
147
|
JamJWTNotInWhiteList: If token is not in white list
|
|
88
148
|
JamJWTInBlackList: If token is in black list
|
|
89
149
|
"""
|
|
90
150
|
self._logger.debug(
|
|
91
|
-
f"Verifying JWT token (length: {len(token)} chars), check_exp={check_exp}, check_list={check_list}"
|
|
151
|
+
f"Verifying JWT token (length: {len(token)} chars), check_exp={check_exp}, check_list={check_list}, check_nbf={check_nbf}"
|
|
92
152
|
)
|
|
93
153
|
assert self.jwt is not None
|
|
94
|
-
|
|
154
|
+
data = self.jwt.decode(token)
|
|
155
|
+
payload = data["payload"]
|
|
156
|
+
|
|
157
|
+
if check_exp and "exp" in payload:
|
|
158
|
+
if payload["exp"] < time.time():
|
|
159
|
+
raise JamJWTExpired
|
|
160
|
+
|
|
161
|
+
if check_nbf and "nbf" in payload:
|
|
162
|
+
if payload["nbf"] > time.time():
|
|
163
|
+
raise JamJWTNotYetValid
|
|
164
|
+
|
|
95
165
|
self._logger.debug(
|
|
96
166
|
f"JWT token verified successfully, payload keys: {list(payload.keys())}"
|
|
97
167
|
)
|
|
98
168
|
|
|
99
|
-
if check_exp:
|
|
100
|
-
if payload["exp"] < datetime.datetime.now().timestamp():
|
|
101
|
-
raise JamJWTExpired
|
|
102
|
-
|
|
103
169
|
if check_list:
|
|
104
170
|
if not self.jwt.list:
|
|
105
171
|
raise JamConfigurationError(
|
|
@@ -119,6 +185,9 @@ class Jam(BaseJam):
|
|
|
119
185
|
message="Invalid JWT list type",
|
|
120
186
|
error_code="configuration.jwt.unknown_list_type",
|
|
121
187
|
)
|
|
188
|
+
|
|
189
|
+
if include_headers:
|
|
190
|
+
return data
|
|
122
191
|
return payload
|
|
123
192
|
|
|
124
193
|
def session_create(self, session_key: str, data: dict[str, Any]) -> str:
|
|
@@ -391,9 +460,9 @@ class Jam(BaseJam):
|
|
|
391
460
|
Returns:
|
|
392
461
|
dict: Payload
|
|
393
462
|
"""
|
|
394
|
-
from jam.paseto.utils import payload_maker
|
|
463
|
+
from jam.paseto.utils import payload_maker as pm
|
|
395
464
|
|
|
396
|
-
return
|
|
465
|
+
return pm(expire=exp, data=data)
|
|
397
466
|
|
|
398
467
|
def paseto_create(
|
|
399
468
|
self,
|