jamlib 3.2.0b3__tar.gz → 3.2.0.post0__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.2.0b3/src/jamlib.egg-info → jamlib-3.2.0.post0}/PKG-INFO +5 -5
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/README.md +3 -3
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/pyproject.toml +2 -2
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/__base__.py +54 -6
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/__init__.py +2 -4
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/aio/__base__.py +19 -5
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/aio/instance.py +26 -9
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/aio/sessions/__base__.py +5 -1
- jamlib-3.2.0.post0/src/jam/exceptions/jose.py +73 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/ext/flask/extensions.py +2 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/ext/litestar/plugins.py +3 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/ext/starlette/backends.py +2 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/instance.py +8 -3
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jose/__algorithms__.py +156 -54
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jose/__base__.py +116 -36
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jose/jwe.py +11 -6
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jose/jwk.py +31 -10
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jose/jws.py +20 -1
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jose/jwt.py +143 -79
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jose/lists/redis.py +4 -1
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/logger.py +8 -1
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/paseto/v1.py +4 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/paseto/v2.py +4 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/paseto/v3.py +4 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/paseto/v4.py +4 -0
- jamlib-3.2.0.post0/src/jam/plugins/__base__.py +58 -0
- jamlib-3.2.0.post0/src/jam/plugins/__init__.py +10 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/sessions/__base__.py +5 -1
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/tests/clients.py +271 -53
- jamlib-3.2.0.post0/src/jam/tests/fakers.py +187 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/utils/config_maker.py +15 -0
- jamlib-3.2.0.post0/src/jam/utils/version_check.py +18 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0/src/jamlib.egg-info}/PKG-INFO +5 -5
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jamlib.egg-info/SOURCES.txt +3 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jamlib.egg-info/requires.txt +1 -1
- jamlib-3.2.0b3/src/jam/exceptions/jose.py +0 -23
- jamlib-3.2.0b3/src/jam/tests/fakers.py +0 -102
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/LICENSE.md +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/setup.cfg +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/__base_encoder__.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/__deprecated__.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/aio/__init__.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/aio/jwt/__init__.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/aio/oauth2/__base__.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/aio/oauth2/__init__.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/aio/oauth2/builtin/__init__.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/aio/oauth2/builtin/github.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/aio/oauth2/builtin/gitlab.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/aio/oauth2/builtin/google.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/aio/oauth2/builtin/yandex.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/aio/oauth2/client.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/aio/sessions/__init__.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/aio/sessions/json.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/aio/sessions/redis.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/cli/__init__.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/cli/cli.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/cli/commands/__init__.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/cli/commands/keys.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/cli/commands/password.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/encoders.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/exceptions/__init__.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/exceptions/base.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/exceptions/jwt.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/exceptions/oauth2.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/exceptions/paseto.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/exceptions/plugins.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/exceptions/sessions.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/ext/__init__.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/ext/fastapi/__init__.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/ext/flask/__init__.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/ext/flask/objects.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/ext/litestar/__init__.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/ext/litestar/middleware.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/ext/litestar/objects.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/ext/starlette/__init__.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/ext/starlette/objects.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jose/__init__.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jose/lists/__base__.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jose/lists/__init__.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jose/lists/json.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jose/lists/memory.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jose/utils.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jwt/__algorithms__.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jwt/__base__.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jwt/__init__.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jwt/__types__.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jwt/lists/__base__.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jwt/lists/__init__.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jwt/lists/json.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jwt/lists/redis.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jwt/module.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jwt/utils.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/oauth2/__base__.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/oauth2/__init__.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/oauth2/builtin/__init__.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/oauth2/builtin/github.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/oauth2/builtin/gitlab.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/oauth2/builtin/google.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/oauth2/builtin/yandex.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/oauth2/client.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/otp/__base__.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/otp/__init__.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/otp/hotp.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/otp/totp.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/paseto/__base__.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/paseto/__init__.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/paseto/utils.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/py.typed +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/sessions/__init__.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/sessions/json.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/sessions/redis.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/tests/__init__.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/utils/__init__.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/utils/aes.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/utils/await_maybe.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/utils/basic_auth.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/utils/ed.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/utils/otp_keys.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/utils/rsa.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/utils/salt_hash.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/utils/symmetric.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/utils/xchacha20poly1305.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/utils/xor.py +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jamlib.egg-info/dependency_links.txt +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jamlib.egg-info/entry_points.txt +0 -0
- {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/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.2.
|
|
3
|
+
Version: 3.2.0.post0
|
|
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
|
|
@@ -30,7 +30,7 @@ Classifier: Framework :: FastAPI
|
|
|
30
30
|
Requires-Python: >=3.10
|
|
31
31
|
Description-Content-Type: text/markdown
|
|
32
32
|
License-File: LICENSE.md
|
|
33
|
-
Requires-Dist: cryptography>=
|
|
33
|
+
Requires-Dist: cryptography>=48.0.0
|
|
34
34
|
Provides-Extra: cli
|
|
35
35
|
Requires-Dist: click>=8.3.1; extra == "cli"
|
|
36
36
|
Provides-Extra: redis
|
|
@@ -77,7 +77,7 @@ from jam import Jam
|
|
|
77
77
|
|
|
78
78
|
jam = Jam(config="config.toml")
|
|
79
79
|
|
|
80
|
-
jwt = jam.
|
|
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
|
-
* [
|
|
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
|
-
|
|
|
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.
|
|
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
|
-
* [
|
|
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
|
-
|
|
|
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.2.
|
|
3
|
+
version = "3.2.0.post0"
|
|
4
4
|
description = "Simple and universal library for authorization."
|
|
5
5
|
authors = [
|
|
6
6
|
{name = "Makridenko Adrian",email = "adrianmakridenko@duck.com"},
|
|
@@ -23,7 +23,7 @@ keywords = [
|
|
|
23
23
|
]
|
|
24
24
|
requires-python = ">=3.10"
|
|
25
25
|
dependencies = [
|
|
26
|
-
"cryptography>=
|
|
26
|
+
"cryptography>=48.0.0",
|
|
27
27
|
]
|
|
28
28
|
|
|
29
29
|
classifiers = [
|
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
3
5
|
from abc import ABC, abstractmethod
|
|
4
6
|
import gc
|
|
7
|
+
import os
|
|
5
8
|
from typing import Any, Literal
|
|
6
9
|
|
|
7
|
-
from jam.
|
|
10
|
+
from jam.__base_encoder__ import BaseEncoder
|
|
11
|
+
from jam.encoders import JsonEncoder
|
|
8
12
|
from jam.exceptions import JamConfigurationError
|
|
9
13
|
from jam.jose.__base__ import BaseJWE, BaseJWS, BaseJWT
|
|
10
14
|
from jam.logger import BaseLogger, JamLogger
|
|
11
15
|
from jam.oauth2.__base__ import BaseOAuth2Client
|
|
12
16
|
from jam.otp.__base__ import BaseOTP, OTPConfig
|
|
13
17
|
from jam.paseto.__base__ import BasePASETO
|
|
18
|
+
from jam.plugins.__base__ import BasePlugin
|
|
14
19
|
from jam.sessions.__base__ import BaseSessionModule
|
|
15
20
|
from jam.utils.config_maker import __config_maker__, __module_loader__
|
|
16
21
|
|
|
@@ -30,15 +35,17 @@ class BaseJam(ABC):
|
|
|
30
35
|
"DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"
|
|
31
36
|
] = "INFO",
|
|
32
37
|
serializer: BaseEncoder | type[BaseEncoder] = JsonEncoder,
|
|
38
|
+
plugins: list[type[BasePlugin]] = [],
|
|
33
39
|
) -> None:
|
|
34
40
|
"""Initialize instance.
|
|
35
41
|
|
|
36
42
|
Args:
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
43
|
+
config (Union[str, dict[str, Any]]): Configuration
|
|
44
|
+
pointer (str): Pointer
|
|
45
|
+
logger (BaseLogger): Logger
|
|
46
|
+
log_level (Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]): Log level
|
|
47
|
+
serializer (Union[BaseEncoder, type[BaseBrowser]]): Serializer
|
|
48
|
+
plugins (list[type[BasePlugin]]): List of plugins
|
|
42
49
|
|
|
43
50
|
Returns:
|
|
44
51
|
None
|
|
@@ -54,6 +61,8 @@ class BaseJam(ABC):
|
|
|
54
61
|
|
|
55
62
|
self._logger = logger(log_level)
|
|
56
63
|
self._serializer = serializer
|
|
64
|
+
self._plugins = []
|
|
65
|
+
|
|
57
66
|
self.jwt: BaseJWT | None = None
|
|
58
67
|
self.jws: BaseJWS | None = None
|
|
59
68
|
self.jwe: BaseJWE | None = None
|
|
@@ -74,6 +83,9 @@ class BaseJam(ABC):
|
|
|
74
83
|
"BaseJam initialization complete. Modules loaded:\n"
|
|
75
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}"
|
|
76
85
|
)
|
|
86
|
+
if os.getenv("JAM_ENABLE_PLUGINS", "0") == "1":
|
|
87
|
+
self._logger.warning("Experimental plugins are enabled!")
|
|
88
|
+
self.__setup_plugins(plugins)
|
|
77
89
|
gc.collect()
|
|
78
90
|
|
|
79
91
|
def __build_main_config(
|
|
@@ -236,6 +248,40 @@ class BaseJam(ABC):
|
|
|
236
248
|
case _:
|
|
237
249
|
raise JamConfigurationError(message="Unknown OTP type.")
|
|
238
250
|
|
|
251
|
+
def __setup_plugins(self, plugins: list[type[BasePlugin]]) -> None:
|
|
252
|
+
"""Setup plugins."""
|
|
253
|
+
for plugin in plugins:
|
|
254
|
+
self._logger.debug(f"Setup plugin: {plugin.name}")
|
|
255
|
+
from jam.utils.version_check import __is_compatible__
|
|
256
|
+
|
|
257
|
+
if not __is_compatible__(None, plugin.jam_requires):
|
|
258
|
+
continue
|
|
259
|
+
|
|
260
|
+
_plugin = plugin(self)
|
|
261
|
+
_plugin.setup()
|
|
262
|
+
self._plugins.append(_plugin)
|
|
263
|
+
|
|
264
|
+
def emit(self, event: str, **kwargs) -> Any:
|
|
265
|
+
"""Emit event.
|
|
266
|
+
|
|
267
|
+
Args:
|
|
268
|
+
event (str): Event name,
|
|
269
|
+
**kwargs: Event data
|
|
270
|
+
"""
|
|
271
|
+
for plugin in self._plugins:
|
|
272
|
+
handler = getattr(plugin, f"on_{event}", None)
|
|
273
|
+
|
|
274
|
+
if handler:
|
|
275
|
+
try:
|
|
276
|
+
result = handler(**kwargs)
|
|
277
|
+
if isinstance(result, dict):
|
|
278
|
+
kwargs.update(result)
|
|
279
|
+
|
|
280
|
+
except Exception as e:
|
|
281
|
+
self._logger.error(f"Plugin:{plugin.name} | error: {e}")
|
|
282
|
+
|
|
283
|
+
return kwargs
|
|
284
|
+
|
|
239
285
|
@abstractmethod
|
|
240
286
|
def jwt_encode(
|
|
241
287
|
self,
|
|
@@ -244,6 +290,7 @@ class BaseJam(ABC):
|
|
|
244
290
|
aud: str | None = None,
|
|
245
291
|
exp: int | None = None,
|
|
246
292
|
nbf: int | None = None,
|
|
293
|
+
jti: str | None = None,
|
|
247
294
|
*,
|
|
248
295
|
payload: dict[str, Any] | None = None,
|
|
249
296
|
header: dict[str, Any] | None = None,
|
|
@@ -256,6 +303,7 @@ class BaseJam(ABC):
|
|
|
256
303
|
iss (str | None): The issuer.
|
|
257
304
|
sub (str | None): The subject.
|
|
258
305
|
aud (str | None): The audience.
|
|
306
|
+
jti (str | None): The JWT ID. If none use the JTI fabric function.
|
|
259
307
|
header (dict[str, Any] | None): The header to include in the JWT.
|
|
260
308
|
payload (dict[str, Any] | None): The payload to include in the JWT.
|
|
261
309
|
|
|
@@ -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.2.
|
|
16
|
-
__all__ = ["Jam", "
|
|
13
|
+
__version__ = "3.2.0"
|
|
14
|
+
__all__ = ["Jam", "BaseJam"]
|
|
@@ -4,6 +4,7 @@ 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
|
|
9
10
|
from jam.jose.__base__ import BaseJWE, BaseJWS
|
|
@@ -21,11 +22,17 @@ class BaseAsyncJam(BaseJam):
|
|
|
21
22
|
jwe: BaseJWE | None = None # type: ignore[override]
|
|
22
23
|
|
|
23
24
|
@abstractmethod
|
|
25
|
+
@deprecated(
|
|
26
|
+
"This method is deprecated; the JWT payload is generated automatically in accordance with the specification."
|
|
27
|
+
)
|
|
24
28
|
async def jwt_make_payload( # type: ignore[override]
|
|
25
29
|
self, exp: int | None, data: dict[str, Any]
|
|
26
30
|
) -> dict[str, Any]:
|
|
27
31
|
"""Make JWT-specific payload.
|
|
28
32
|
|
|
33
|
+
!!! Deprecated
|
|
34
|
+
This method is deprecated; the JWT payload is generated automatically in accordance with the specification.
|
|
35
|
+
|
|
29
36
|
Args:
|
|
30
37
|
exp (int | None): Token expire, if None -> use default
|
|
31
38
|
data (dict[str, Any]): Data to payload
|
|
@@ -36,6 +43,7 @@ class BaseAsyncJam(BaseJam):
|
|
|
36
43
|
raise NotImplementedError
|
|
37
44
|
|
|
38
45
|
@abstractmethod
|
|
46
|
+
@deprecated("Use jam.jwt_encode")
|
|
39
47
|
async def jwt_create( # type: ignore[override]
|
|
40
48
|
self, payload: dict[str, Any]
|
|
41
49
|
) -> str:
|
|
@@ -50,13 +58,14 @@ class BaseAsyncJam(BaseJam):
|
|
|
50
58
|
raise NotImplementedError
|
|
51
59
|
|
|
52
60
|
@abstractmethod
|
|
53
|
-
async def jwt_encode(
|
|
61
|
+
async def jwt_encode( # type: ignore[override]
|
|
54
62
|
self,
|
|
55
63
|
iss: str | None = None,
|
|
56
64
|
sub: str | None = None,
|
|
57
65
|
aud: str | None = None,
|
|
58
66
|
exp: int | None = None,
|
|
59
67
|
nbf: int | None = None,
|
|
68
|
+
jti: str | None = None,
|
|
60
69
|
*,
|
|
61
70
|
payload: dict[str, Any] | None = None,
|
|
62
71
|
header: dict[str, Any] | None = None,
|
|
@@ -69,6 +78,7 @@ class BaseAsyncJam(BaseJam):
|
|
|
69
78
|
iss (str | None): The issuer.
|
|
70
79
|
sub (str | None): The subject.
|
|
71
80
|
aud (str | None): The audience.
|
|
81
|
+
jti (str | None): The JWT ID. If none use the JTI fabric function.
|
|
72
82
|
header (dict[str, Any] | None): The header to include in the JWT.
|
|
73
83
|
payload (dict[str, Any] | None): The payload to include in the JWT.
|
|
74
84
|
|
|
@@ -345,7 +355,7 @@ class BaseAsyncJam(BaseJam):
|
|
|
345
355
|
raise NotImplementedError
|
|
346
356
|
|
|
347
357
|
@abstractmethod
|
|
348
|
-
async def jws_sign(
|
|
358
|
+
async def jws_sign( # type: ignore[override]
|
|
349
359
|
self,
|
|
350
360
|
data: dict[str, Any] | str,
|
|
351
361
|
header: dict[str, Any] | None = None,
|
|
@@ -362,7 +372,9 @@ class BaseAsyncJam(BaseJam):
|
|
|
362
372
|
raise NotImplementedError
|
|
363
373
|
|
|
364
374
|
@abstractmethod
|
|
365
|
-
async def jws_verify(
|
|
375
|
+
async def jws_verify( # type: ignore[override]
|
|
376
|
+
self, token: str
|
|
377
|
+
) -> dict[str, Any]:
|
|
366
378
|
"""Verify JWS token.
|
|
367
379
|
|
|
368
380
|
Args:
|
|
@@ -377,7 +389,7 @@ class BaseAsyncJam(BaseJam):
|
|
|
377
389
|
raise NotImplementedError
|
|
378
390
|
|
|
379
391
|
@abstractmethod
|
|
380
|
-
async def jwe_encrypt(
|
|
392
|
+
async def jwe_encrypt( # type: ignore[override]
|
|
381
393
|
self,
|
|
382
394
|
data: dict[str, Any] | str,
|
|
383
395
|
header: dict[str, Any] | None = None,
|
|
@@ -394,7 +406,9 @@ class BaseAsyncJam(BaseJam):
|
|
|
394
406
|
raise NotImplementedError
|
|
395
407
|
|
|
396
408
|
@abstractmethod
|
|
397
|
-
async def jwe_decrypt(
|
|
409
|
+
async def jwe_decrypt( # type: ignore[override]
|
|
410
|
+
self, token: str
|
|
411
|
+
) -> bytes:
|
|
398
412
|
"""Decrypt JWE token.
|
|
399
413
|
|
|
400
414
|
Args:
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
|
|
3
|
-
import datetime
|
|
4
3
|
import time
|
|
5
4
|
from typing import Any
|
|
6
5
|
import uuid
|
|
7
6
|
|
|
7
|
+
from jam.__deprecated__ import deprecated
|
|
8
8
|
from jam.aio.__base__ import BaseAsyncJam
|
|
9
9
|
from jam.exceptions import (
|
|
10
10
|
JamConfigurationError,
|
|
@@ -30,11 +30,17 @@ class Jam(BaseAsyncJam):
|
|
|
30
30
|
"otp": "jam.otp.__base__.OTPConfig",
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
@deprecated(
|
|
34
|
+
"This method is deprecated; the JWT payload is generated automatically in accordance with the specification."
|
|
35
|
+
)
|
|
33
36
|
async def jwt_make_payload(
|
|
34
37
|
self, exp: int | None, data: dict[str, Any]
|
|
35
38
|
) -> dict[str, Any]:
|
|
36
39
|
"""Make JWT-specific payload.
|
|
37
40
|
|
|
41
|
+
!!! Deprecated
|
|
42
|
+
This method is deprecated; the JWT payload is generated automatically in accordance with the specification.
|
|
43
|
+
|
|
38
44
|
Args:
|
|
39
45
|
exp (int | None): Token expire
|
|
40
46
|
data (dict[str, Any]): Data to payload
|
|
@@ -42,17 +48,22 @@ class Jam(BaseAsyncJam):
|
|
|
42
48
|
Returns:
|
|
43
49
|
dict[str, Any]: Payload
|
|
44
50
|
"""
|
|
51
|
+
now = time.time()
|
|
45
52
|
payload = {
|
|
46
|
-
"iat":
|
|
47
|
-
"exp": (
|
|
53
|
+
"iat": now,
|
|
54
|
+
"exp": (now + exp) if exp else None,
|
|
48
55
|
"jti": str(uuid.uuid4()),
|
|
49
56
|
}
|
|
50
57
|
payload = payload | data
|
|
51
58
|
return payload
|
|
52
59
|
|
|
60
|
+
@deprecated("Use jam.jwt_encode")
|
|
53
61
|
async def jwt_create(self, payload: dict[str, Any]) -> str:
|
|
54
62
|
"""Create JWT token.
|
|
55
63
|
|
|
64
|
+
!!! Deprecated
|
|
65
|
+
Use Jam.jwt_encode
|
|
66
|
+
|
|
56
67
|
Args:
|
|
57
68
|
payload (dict[str, Any]): Data payload
|
|
58
69
|
|
|
@@ -81,6 +92,7 @@ class Jam(BaseAsyncJam):
|
|
|
81
92
|
aud: str | None = None,
|
|
82
93
|
exp: int | None = None,
|
|
83
94
|
nbf: int | None = None,
|
|
95
|
+
jti: str | None = None,
|
|
84
96
|
*,
|
|
85
97
|
payload: dict[str, Any] | None = None,
|
|
86
98
|
header: dict[str, Any] | None = None,
|
|
@@ -93,6 +105,7 @@ class Jam(BaseAsyncJam):
|
|
|
93
105
|
iss (str | None): The issuer.
|
|
94
106
|
sub (str | None): The subject.
|
|
95
107
|
aud (str | None): The audience.
|
|
108
|
+
jti (str | None): The JWT ID. If none use the JTI fabric function.
|
|
96
109
|
header (dict[str, Any] | None): The header to include in the JWT.
|
|
97
110
|
payload (dict[str, Any] | None): The payload to include in the JWT.
|
|
98
111
|
|
|
@@ -100,12 +113,15 @@ class Jam(BaseAsyncJam):
|
|
|
100
113
|
str: The encoded JWT.
|
|
101
114
|
"""
|
|
102
115
|
assert self.jwt is not None
|
|
116
|
+
if not jti:
|
|
117
|
+
jti = self.jwt.jti
|
|
103
118
|
token = self.jwt.encode(
|
|
104
119
|
iss=iss,
|
|
105
120
|
sub=sub,
|
|
106
121
|
aud=aud,
|
|
107
122
|
exp=exp,
|
|
108
123
|
nbf=nbf,
|
|
124
|
+
jti=jti,
|
|
109
125
|
payload=payload,
|
|
110
126
|
header=header,
|
|
111
127
|
)
|
|
@@ -239,7 +255,10 @@ class Jam(BaseAsyncJam):
|
|
|
239
255
|
"""
|
|
240
256
|
assert self.jwe is not None
|
|
241
257
|
self._logger.debug(f"Encrypting data with JWE, header: {header}")
|
|
242
|
-
token = self.jwe.encrypt(
|
|
258
|
+
token = self.jwe.encrypt(
|
|
259
|
+
self._serializer.dumps(data) if isinstance(data, dict) else data,
|
|
260
|
+
header,
|
|
261
|
+
)
|
|
243
262
|
self._logger.debug(f"JWE token created, length: {len(token)}")
|
|
244
263
|
return token
|
|
245
264
|
|
|
@@ -364,8 +383,8 @@ class Jam(BaseAsyncJam):
|
|
|
364
383
|
async def otp_uri(
|
|
365
384
|
self,
|
|
366
385
|
secret: str,
|
|
367
|
-
name: str
|
|
368
|
-
issuer: str
|
|
386
|
+
name: str,
|
|
387
|
+
issuer: str,
|
|
369
388
|
counter: int | None = None,
|
|
370
389
|
) -> str:
|
|
371
390
|
"""Generates an otpauth:// URI for Google Authenticator.
|
|
@@ -383,9 +402,7 @@ class Jam(BaseAsyncJam):
|
|
|
383
402
|
assert self._otp is not None
|
|
384
403
|
return self._otp(
|
|
385
404
|
secret=secret, digits=self.otp.digits, digest=self.otp.digest
|
|
386
|
-
).provisioning_uri(
|
|
387
|
-
name=name or "", issuer=issuer or "", counter=counter
|
|
388
|
-
)
|
|
405
|
+
).provisioning_uri(name=name, issuer=issuer, counter=counter)
|
|
389
406
|
|
|
390
407
|
async def otp_verify_code(
|
|
391
408
|
self,
|
|
@@ -7,9 +7,11 @@ from uuid import uuid4
|
|
|
7
7
|
|
|
8
8
|
from cryptography.fernet import Fernet
|
|
9
9
|
|
|
10
|
-
from jam.
|
|
10
|
+
from jam.__base_encoder__ import BaseEncoder
|
|
11
|
+
from jam.encoders import JsonEncoder
|
|
11
12
|
from jam.exceptions import JamSessionEmptyAESKey
|
|
12
13
|
from jam.logger import BaseLogger
|
|
14
|
+
from jam.utils.config_maker import __key_loader__
|
|
13
15
|
|
|
14
16
|
|
|
15
17
|
class BaseAsyncSessionModule(ABC):
|
|
@@ -32,6 +34,8 @@ class BaseAsyncSessionModule(ABC):
|
|
|
32
34
|
raise JamSessionEmptyAESKey
|
|
33
35
|
if is_session_crypt:
|
|
34
36
|
assert session_aes_secret is not None
|
|
37
|
+
if isinstance(session_aes_secret, str):
|
|
38
|
+
session_aes_secret = __key_loader__(session_aes_secret)
|
|
35
39
|
self._code_session_key = Fernet(session_aes_secret)
|
|
36
40
|
|
|
37
41
|
def __encode_session_id__(self, data: str) -> str:
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from .base import JamConfigurationError, JamValidationError
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class JamJWSVerificationError(JamValidationError):
|
|
7
|
+
default_message = "JWS signature verification failed."
|
|
8
|
+
default_code = "jws.verification_error"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class JamJWSValidationError(JamValidationError):
|
|
12
|
+
default_message = "JWS validation failed."
|
|
13
|
+
default_code = "jws.validation_error"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class JamJWSInvalidFormatError(JamValidationError):
|
|
17
|
+
default_message = "Invalid JWS format."
|
|
18
|
+
default_code = "jws.invalid_format"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class JamJWSSigningError(JamValidationError):
|
|
22
|
+
default_message = "JWS signing failed."
|
|
23
|
+
default_code = "jws.signing_error"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class JamJWKValidationError(JamValidationError):
|
|
27
|
+
default_message = "JWK validation failed."
|
|
28
|
+
default_code = "jwk.validation_error"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class JamJWKInvalidKeyTypeError(JamValidationError):
|
|
32
|
+
default_message = "Unsupported JWK key type."
|
|
33
|
+
default_code = "jwk.invalid_key_type"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class JamJWKMissingParameterError(JamValidationError):
|
|
37
|
+
default_message = "Missing required JWK parameter."
|
|
38
|
+
default_code = "jwk.missing_parameter"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class JamJWEEncryptionError(JamValidationError):
|
|
42
|
+
default_message = "JWE encryption failed."
|
|
43
|
+
default_code = "jwe.encryption_error"
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class JamJWEDecryptionError(JamValidationError):
|
|
47
|
+
default_message = "JWE decryption failed."
|
|
48
|
+
default_code = "jwe.decryption_error"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class JamJWEInvalidFormatError(JamValidationError):
|
|
52
|
+
default_message = "Invalid JWE format."
|
|
53
|
+
default_code = "jwe.invalid_format"
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class JamInvalidKeyTypeError(JamConfigurationError):
|
|
57
|
+
default_message = "Invalid key type."
|
|
58
|
+
default_code = "jose.invalid_key_type"
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class JamAlgorithmError(JamConfigurationError):
|
|
62
|
+
default_message = "Algorithm error."
|
|
63
|
+
default_code = "jose.algorithm_error"
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class JamInvalidPaddingError(JamValidationError):
|
|
67
|
+
default_message = "Invalid padding."
|
|
68
|
+
default_code = "jose.invalid_padding"
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class JamRedisListConfigurationError(JamConfigurationError):
|
|
72
|
+
default_message = "Redis list configuration error."
|
|
73
|
+
default_code = "jose.redis_list_configuration_error"
|
|
@@ -89,6 +89,8 @@ class BaseAuthExtension(BaseExtension):
|
|
|
89
89
|
_config: dict[str, Any] | None = (
|
|
90
90
|
__config_maker__(config, pointer) if config else None
|
|
91
91
|
)
|
|
92
|
+
if _config and _config.get("jose", None) and self.MODULE == create_jwt:
|
|
93
|
+
_config = _config["jose"]
|
|
92
94
|
|
|
93
95
|
params = _config.pop(self._CONFIG_KEY) if _config else kwargs
|
|
94
96
|
super().__init__(app=app, **params)
|
|
@@ -76,6 +76,9 @@ class BasePlugin(InitPlugin):
|
|
|
76
76
|
__config_maker__(config, pointer) if config else None
|
|
77
77
|
)
|
|
78
78
|
|
|
79
|
+
# FIXME: Make config wrapper
|
|
80
|
+
if _config and _config.get("jose", None) and self.MODULE == create_jwt:
|
|
81
|
+
_config = _config["jose"]
|
|
79
82
|
params = _config.pop(self._CONFIG_KEY) if _config else kwargs
|
|
80
83
|
self._setup_config(params)
|
|
81
84
|
self._middleware = None
|
|
@@ -81,6 +81,8 @@ class BaseBackend(AuthenticationBackend):
|
|
|
81
81
|
try:
|
|
82
82
|
if config:
|
|
83
83
|
config_ = __config_maker__(config, pointer)[self._CONFIG_KEY]
|
|
84
|
+
if config_.get("jose", None) and self.MODULE == create_jwt:
|
|
85
|
+
config_ = config_["jose"]
|
|
84
86
|
self._auth = self.MODULE(**config_)
|
|
85
87
|
else:
|
|
86
88
|
self._auth = self.MODULE(**kwargs)
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
|
|
3
|
-
import datetime
|
|
4
3
|
import time
|
|
5
4
|
from typing import Any
|
|
6
5
|
import uuid
|
|
@@ -49,9 +48,10 @@ class Jam(BaseJam):
|
|
|
49
48
|
Returns:
|
|
50
49
|
dict[str, Any]: Payload
|
|
51
50
|
"""
|
|
51
|
+
now = time.time()
|
|
52
52
|
payload = {
|
|
53
|
-
"iat":
|
|
54
|
-
"exp": (
|
|
53
|
+
"iat": now,
|
|
54
|
+
"exp": (now + exp) if exp else None,
|
|
55
55
|
"jti": str(uuid.uuid4()),
|
|
56
56
|
}
|
|
57
57
|
payload = payload | data
|
|
@@ -92,6 +92,7 @@ class Jam(BaseJam):
|
|
|
92
92
|
aud: str | None = None,
|
|
93
93
|
exp: int | None = None,
|
|
94
94
|
nbf: int | None = None,
|
|
95
|
+
jti: str | None = None,
|
|
95
96
|
*,
|
|
96
97
|
payload: dict[str, Any] | None = None,
|
|
97
98
|
header: dict[str, Any] | None = None,
|
|
@@ -104,6 +105,7 @@ class Jam(BaseJam):
|
|
|
104
105
|
iss (str | None): The issuer.
|
|
105
106
|
sub (str | None): The subject.
|
|
106
107
|
aud (str | None): The audience.
|
|
108
|
+
jti (str | None): The JWT ID. If none use the JTI fabric function.
|
|
107
109
|
header (dict[str, Any] | None): The header to include in the JWT.
|
|
108
110
|
payload (dict[str, Any] | None): The payload to include in the JWT.
|
|
109
111
|
|
|
@@ -111,12 +113,15 @@ class Jam(BaseJam):
|
|
|
111
113
|
str: The encoded JWT.
|
|
112
114
|
"""
|
|
113
115
|
assert self.jwt is not None
|
|
116
|
+
if not jti:
|
|
117
|
+
jti = self.jwt.jti
|
|
114
118
|
token = self.jwt.encode(
|
|
115
119
|
iss=iss,
|
|
116
120
|
sub=sub,
|
|
117
121
|
aud=aud,
|
|
118
122
|
exp=exp,
|
|
119
123
|
nbf=nbf,
|
|
124
|
+
jti=jti,
|
|
120
125
|
payload=payload,
|
|
121
126
|
header=header,
|
|
122
127
|
)
|