pypomes-jwt 0.7.1__py3-none-any.whl → 0.7.2__py3-none-any.whl
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.
Potentially problematic release.
This version of pypomes-jwt might be problematic. Click here for more details.
- pypomes_jwt/__init__.py +4 -4
- pypomes_jwt/jwt_constants.py +28 -4
- pypomes_jwt/jwt_data.py +52 -14
- pypomes_jwt/jwt_pomes.py +76 -137
- {pypomes_jwt-0.7.1.dist-info → pypomes_jwt-0.7.2.dist-info}/METADATA +1 -1
- pypomes_jwt-0.7.2.dist-info/RECORD +8 -0
- pypomes_jwt-0.7.1.dist-info/RECORD +0 -8
- {pypomes_jwt-0.7.1.dist-info → pypomes_jwt-0.7.2.dist-info}/WHEEL +0 -0
- {pypomes_jwt-0.7.1.dist-info → pypomes_jwt-0.7.2.dist-info}/licenses/LICENSE +0 -0
pypomes_jwt/__init__.py
CHANGED
|
@@ -5,9 +5,9 @@ from .jwt_constants import (
|
|
|
5
5
|
JWT_ENCODING_KEY, JWT_DECODING_KEY
|
|
6
6
|
)
|
|
7
7
|
from .jwt_pomes import (
|
|
8
|
-
jwt_needed, jwt_verify_request,
|
|
8
|
+
jwt_needed, jwt_verify_request,
|
|
9
9
|
jwt_get_tokens, jwt_get_claims, jwt_validate_token,
|
|
10
|
-
jwt_assert_access, jwt_set_access, jwt_remove_access
|
|
10
|
+
jwt_assert_access, jwt_set_access, jwt_remove_access, jwt_revoke_tokens
|
|
11
11
|
)
|
|
12
12
|
|
|
13
13
|
__all__ = [
|
|
@@ -17,9 +17,9 @@ __all__ = [
|
|
|
17
17
|
"JWT_ACCESS_MAX_AGE", "JWT_REFRESH_MAX_AGE",
|
|
18
18
|
"JWT_ENCODING_KEY", "JWT_DECODING_KEY",
|
|
19
19
|
# jwt_pomes
|
|
20
|
-
"jwt_needed", "jwt_verify_request",
|
|
20
|
+
"jwt_needed", "jwt_verify_request",
|
|
21
21
|
"jwt_get_tokens", "jwt_get_claims", "jwt_validate_token",
|
|
22
|
-
"jwt_assert_access", "jwt_set_access", "jwt_remove_access"
|
|
22
|
+
"jwt_assert_access", "jwt_set_access", "jwt_remove_access", "jwt_revoke_tokens"
|
|
23
23
|
]
|
|
24
24
|
|
|
25
25
|
from importlib.metadata import version
|
pypomes_jwt/jwt_constants.py
CHANGED
|
@@ -9,16 +9,40 @@ from secrets import token_bytes
|
|
|
9
9
|
from typing import Final
|
|
10
10
|
|
|
11
11
|
# database specs for token persistence
|
|
12
|
-
JWT_DB_ENGINE: Final[str] = env_get_str(key=f"{APP_PREFIX}_JWT_DB_ENGINE")
|
|
13
12
|
JWT_DB_HOST: Final[str] = env_get_str(key=f"{APP_PREFIX}_JWT_DB_HOST")
|
|
14
13
|
JWT_DB_NAME: Final[str] = env_get_str(key=f"{APP_PREFIX}_JWT_DB_NAME")
|
|
15
14
|
JWT_DB_PORT: Final[int] = env_get_int(key=f"{APP_PREFIX}_JWT_DB_PORT")
|
|
16
15
|
JWT_DB_USER: Final[str] = env_get_str(key=f"{APP_PREFIX}_JWT_DB_USER")
|
|
17
16
|
JWT_DB_PWD: Final[str] = env_get_str(key=f"{APP_PREFIX}_JWT_DB_PWD")
|
|
17
|
+
JWT_DB_CLIENT: Final[str] = env_get_str(key=f"{APP_PREFIX}_JWT_DB_CLIENT") # for Oracle, only
|
|
18
|
+
JWT_DB_DRIVER: Final[str] = env_get_str(key=f"{APP_PREFIX}_JWT_DB_DRIVER") # for SQLServer, only
|
|
19
|
+
JWT_DB_TABLE: Final[str] = env_get_str(key=f"{APP_PREFIX}_JWT_DB_TABLE")
|
|
20
|
+
JWT_ROTATE_TOKENS: Final[bool] = env_get_bool(key=f"{APP_PREFIX}_JWT_ROTATE_TOKENS",
|
|
21
|
+
def_value=True)
|
|
18
22
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
23
|
+
__db_engine: str | None = env_get_str(key=f"{APP_PREFIX}_JWT_DB_ENGINE")
|
|
24
|
+
__rotate_tokens: bool = False
|
|
25
|
+
if __db_engine:
|
|
26
|
+
from pypomes_db import DbEngine, db_setup, db_assert_access, db_delete
|
|
27
|
+
from sys import stderr
|
|
28
|
+
if db_setup(engine=DbEngine(__db_engine),
|
|
29
|
+
db_name=JWT_DB_NAME,
|
|
30
|
+
db_user=JWT_DB_USER,
|
|
31
|
+
db_pwd=JWT_DB_PWD,
|
|
32
|
+
db_host=JWT_DB_HOST,
|
|
33
|
+
db_port=JWT_DB_PORT,
|
|
34
|
+
db_client=JWT_DB_CLIENT,
|
|
35
|
+
db_driver=JWT_DB_DRIVER):
|
|
36
|
+
__errors: list[str] = []
|
|
37
|
+
if not db_assert_access(errors=__errors) or \
|
|
38
|
+
db_delete(errors=__errors,
|
|
39
|
+
delete_stmt=f"DELETE FROM {JWT_DB_TABLE}") is None:
|
|
40
|
+
stderr.write(f"{'; '.join(__errors)}\n")
|
|
41
|
+
__db_engine = None
|
|
42
|
+
else:
|
|
43
|
+
stderr.write("Invalid database parameters\n")
|
|
44
|
+
__db_engine = None
|
|
45
|
+
JWT_DB_ENGINE: Final[DbEngine] = DbEngine(__db_engine) if __db_engine else None
|
|
22
46
|
|
|
23
47
|
# one of HS256, HS512, RSA256, RSA512
|
|
24
48
|
JWT_DEFAULT_ALGORITHM: Final[str] = env_get_str(key=f"{APP_PREFIX}_JWT_DEFAULT_ALGORITHM",
|
pypomes_jwt/jwt_data.py
CHANGED
|
@@ -9,7 +9,8 @@ from threading import Lock
|
|
|
9
9
|
from typing import Any
|
|
10
10
|
|
|
11
11
|
from .jwt_constants import (
|
|
12
|
-
JWT_DEFAULT_ALGORITHM, JWT_ENCODING_KEY
|
|
12
|
+
JWT_DEFAULT_ALGORITHM, JWT_ENCODING_KEY,
|
|
13
|
+
JWT_ROTATE_TOKENS, JWT_DB_ENGINE, JWT_DB_TABLE
|
|
13
14
|
)
|
|
14
15
|
|
|
15
16
|
|
|
@@ -19,7 +20,7 @@ class JwtData:
|
|
|
19
20
|
|
|
20
21
|
Instance variables:
|
|
21
22
|
- access_lock: lock for safe multi-threading access
|
|
22
|
-
- access_data:
|
|
23
|
+
- access_data: dictionary holding the JWT token data, organized by account id:
|
|
23
24
|
{
|
|
24
25
|
<account-id>: {
|
|
25
26
|
"reference-url": # the reference URL
|
|
@@ -178,7 +179,7 @@ class JwtData:
|
|
|
178
179
|
:raises InvalidIssuerError: 'iss' claim does not match the expected issuer
|
|
179
180
|
:raises InvalidIssuedAtError: 'iat' claim is non-numeric
|
|
180
181
|
:raises MissingRequiredClaimError: a required claim is not contained in the claimset
|
|
181
|
-
:raises RuntimeError:
|
|
182
|
+
:raises RuntimeError: error accessing the revocation database, or
|
|
182
183
|
the remote JWT provider failed to return a token
|
|
183
184
|
"""
|
|
184
185
|
# initialize the return variable
|
|
@@ -191,9 +192,10 @@ class JwtData:
|
|
|
191
192
|
# was the JWT data obtained ?
|
|
192
193
|
if account_data:
|
|
193
194
|
# yes, proceed
|
|
195
|
+
errors: list[str] = []
|
|
194
196
|
current_claims: dict[str, Any] = account_data.get("claims").copy()
|
|
195
197
|
if account_claims:
|
|
196
|
-
current_claims.update(
|
|
198
|
+
current_claims.update(account_claims)
|
|
197
199
|
|
|
198
200
|
# obtain new tokens
|
|
199
201
|
current_claims["jti"] = str_random(size=32,
|
|
@@ -203,7 +205,6 @@ class JwtData:
|
|
|
203
205
|
# where is the JWT service provider ?
|
|
204
206
|
if account_data.get("remote-provider"):
|
|
205
207
|
# JWT service is being provided by a remote server
|
|
206
|
-
errors: list[str] = []
|
|
207
208
|
# Structure of the return data:
|
|
208
209
|
# {
|
|
209
210
|
# "access_token": <jwt-token>,
|
|
@@ -221,15 +222,52 @@ class JwtData:
|
|
|
221
222
|
raise RuntimeError(" - ".join(errors))
|
|
222
223
|
else:
|
|
223
224
|
# JWT service is being provided locally
|
|
224
|
-
just_now:
|
|
225
|
+
just_now: int = int(datetime.now(tz=timezone.utc).timestamp())
|
|
225
226
|
current_claims["iat"] = just_now
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
227
|
+
|
|
228
|
+
# retrieve the refresh token associated with the account id
|
|
229
|
+
refresh_token: str | None = None
|
|
230
|
+
if JWT_DB_ENGINE:
|
|
231
|
+
from pypomes_db import db_select, db_delete
|
|
232
|
+
if JWT_ROTATE_TOKENS:
|
|
233
|
+
db_delete(errors=errors,
|
|
234
|
+
delete_stmt=f"DELETE FROM {JWT_DB_TABLE} "
|
|
235
|
+
f"WHERE account_id = '{account_id}'",
|
|
236
|
+
logger=logger)
|
|
237
|
+
else:
|
|
238
|
+
recs: list[tuple[str]] = db_select(errors=errors,
|
|
239
|
+
sel_stmt=f"SELECT jwt_token FROM {JWT_DB_TABLE} "
|
|
240
|
+
f"WHERE account_id = '{account_id}'",
|
|
241
|
+
max_count=1,
|
|
242
|
+
logger=logger)
|
|
243
|
+
if recs:
|
|
244
|
+
refresh_token = recs[0][0]
|
|
245
|
+
if errors:
|
|
246
|
+
raise RuntimeError(" - ".join(errors))
|
|
247
|
+
|
|
248
|
+
# was it obtained ?
|
|
249
|
+
if not refresh_token:
|
|
250
|
+
# no, issue a new one
|
|
251
|
+
current_claims["exp"] = just_now + account_data.get("refresh-max-age")
|
|
252
|
+
current_claims["nat"] = "R"
|
|
253
|
+
# may raise an exception
|
|
254
|
+
refresh_token: str = jwt.encode(payload=current_claims,
|
|
255
|
+
key=JWT_ENCODING_KEY,
|
|
256
|
+
algorithm=JWT_DEFAULT_ALGORITHM)
|
|
257
|
+
# persist the new refresh token
|
|
258
|
+
if JWT_DB_ENGINE:
|
|
259
|
+
from pypomes_db import db_insert
|
|
260
|
+
db_insert(errors=errors,
|
|
261
|
+
insert_stmt=f"INSERT INTO {JWT_DB_TABLE}",
|
|
262
|
+
insert_data={"account_id": account_id,
|
|
263
|
+
"jwt_token": refresh_token},
|
|
264
|
+
logger=logger)
|
|
265
|
+
if errors:
|
|
266
|
+
raise RuntimeError(" - ".join(errors))
|
|
267
|
+
|
|
268
|
+
# issue the access token
|
|
232
269
|
current_claims["nat"] = "A"
|
|
270
|
+
current_claims["exp"] = just_now + account_data.get("access-max-age")
|
|
233
271
|
# may raise an exception
|
|
234
272
|
access_token: str = jwt.encode(payload=current_claims,
|
|
235
273
|
key=JWT_ENCODING_KEY,
|
|
@@ -237,8 +275,8 @@ class JwtData:
|
|
|
237
275
|
# return the token data
|
|
238
276
|
result = {
|
|
239
277
|
"access_token": access_token,
|
|
240
|
-
"created_in":
|
|
241
|
-
"expires_in":
|
|
278
|
+
"created_in": current_claims.get("iat"),
|
|
279
|
+
"expires_in": current_claims.get("exp"),
|
|
242
280
|
"refresh_token": refresh_token
|
|
243
281
|
}
|
|
244
282
|
else:
|
pypomes_jwt/jwt_pomes.py
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import contextlib
|
|
2
1
|
import jwt
|
|
3
|
-
from flask import Request, Response, request
|
|
2
|
+
from flask import Request, Response, request
|
|
4
3
|
from logging import Logger
|
|
5
4
|
from typing import Any, Literal
|
|
6
5
|
|
|
7
6
|
from .jwt_constants import (
|
|
8
7
|
JWT_ACCESS_MAX_AGE, JWT_REFRESH_MAX_AGE,
|
|
9
|
-
JWT_DEFAULT_ALGORITHM, JWT_DECODING_KEY
|
|
8
|
+
JWT_DEFAULT_ALGORITHM, JWT_DECODING_KEY,
|
|
9
|
+
JWT_DB_ENGINE, JWT_DB_TABLE
|
|
10
10
|
)
|
|
11
11
|
from .jwt_data import JwtData
|
|
12
12
|
|
|
@@ -153,12 +153,57 @@ def jwt_validate_token(errors: list[str] | None,
|
|
|
153
153
|
return err_msg is None
|
|
154
154
|
|
|
155
155
|
|
|
156
|
+
def jwt_revoke_tokens(errors: list[str] | None,
|
|
157
|
+
account_id: str,
|
|
158
|
+
logger: Logger = None) -> bool:
|
|
159
|
+
"""
|
|
160
|
+
Revoke all refresh tokens associated with *account_id*.
|
|
161
|
+
|
|
162
|
+
Revoke operations require access to a database table defined by *JWT_DB_TABLE*.
|
|
163
|
+
|
|
164
|
+
:param errors: incidental error messages
|
|
165
|
+
:param account_id: the account identification
|
|
166
|
+
:param logger: optional logger
|
|
167
|
+
:return: *True* if operation could be performed, *False* otherwise
|
|
168
|
+
"""
|
|
169
|
+
# initialize the return variable
|
|
170
|
+
result: bool = False
|
|
171
|
+
|
|
172
|
+
if logger:
|
|
173
|
+
logger.debug(msg=f"Revoking refresh tokens of '{account_id}'")
|
|
174
|
+
|
|
175
|
+
op_errors: list[str] = []
|
|
176
|
+
if JWT_DB_ENGINE:
|
|
177
|
+
from pypomes_db import db_delete
|
|
178
|
+
delete_stmt: str = (f"DELETE FROM {JWT_DB_TABLE} "
|
|
179
|
+
f"WHERE account_id = '{account_id}'")
|
|
180
|
+
db_delete(errors=op_errors,
|
|
181
|
+
delete_stmt=delete_stmt,
|
|
182
|
+
logger=logger)
|
|
183
|
+
else:
|
|
184
|
+
op_errors.append("Database access for token revocation has not been specified")
|
|
185
|
+
|
|
186
|
+
if op_errors:
|
|
187
|
+
if logger:
|
|
188
|
+
logger.error(msg="; ".join(op_errors))
|
|
189
|
+
if isinstance(errors, list):
|
|
190
|
+
errors.extend(op_errors)
|
|
191
|
+
else:
|
|
192
|
+
result = True
|
|
193
|
+
|
|
194
|
+
return result
|
|
195
|
+
|
|
196
|
+
|
|
156
197
|
def jwt_get_tokens(errors: list[str] | None,
|
|
157
198
|
account_id: str,
|
|
158
199
|
account_claims: dict[str, Any] = None,
|
|
200
|
+
refresh_token: str = None,
|
|
159
201
|
logger: Logger = None) -> dict[str, Any]:
|
|
160
202
|
"""
|
|
161
|
-
Issue and return the JWT token data associated with *account_id*.
|
|
203
|
+
Issue or refresh, and return, the JWT token data associated with *account_id*.
|
|
204
|
+
|
|
205
|
+
If *refresh_token* is provided, its claims are used on issuing the new tokens,
|
|
206
|
+
and claims in *account_claims*, if any, are ignored.
|
|
162
207
|
|
|
163
208
|
Structure of the return data:
|
|
164
209
|
{
|
|
@@ -171,6 +216,7 @@ def jwt_get_tokens(errors: list[str] | None,
|
|
|
171
216
|
:param errors: incidental error messages
|
|
172
217
|
:param account_id: the account identification
|
|
173
218
|
:param account_claims: if provided, may supercede registered custom claims
|
|
219
|
+
:param refresh_token: if provided, defines a token refresh operation
|
|
174
220
|
:param logger: optional logger
|
|
175
221
|
:return: the JWT token data, or *None* if error
|
|
176
222
|
"""
|
|
@@ -179,17 +225,28 @@ def jwt_get_tokens(errors: list[str] | None,
|
|
|
179
225
|
|
|
180
226
|
if logger:
|
|
181
227
|
logger.debug(msg=f"Retrieve JWT token data for '{account_id}'")
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
if
|
|
187
|
-
|
|
188
|
-
|
|
228
|
+
op_errors: list[str] = []
|
|
229
|
+
if refresh_token:
|
|
230
|
+
account_claims = jwt_get_claims(errors=op_errors,
|
|
231
|
+
token=refresh_token)
|
|
232
|
+
if not op_errors and account_claims.get("nat") != "R":
|
|
233
|
+
op_errors.extend("Invalid parameters")
|
|
234
|
+
|
|
235
|
+
if not op_errors:
|
|
236
|
+
try:
|
|
237
|
+
result = __jwt_data.issue_tokens(account_id=account_id,
|
|
238
|
+
account_claims=account_claims)
|
|
239
|
+
if logger:
|
|
240
|
+
logger.debug(msg=f"Data is '{result}'")
|
|
241
|
+
except Exception as e:
|
|
242
|
+
# token issuing failed
|
|
243
|
+
op_errors.append(str(e))
|
|
244
|
+
|
|
245
|
+
if op_errors:
|
|
189
246
|
if logger:
|
|
190
|
-
logger.error(
|
|
247
|
+
logger.error("; ".join(op_errors))
|
|
191
248
|
if isinstance(errors, list):
|
|
192
|
-
errors.
|
|
249
|
+
errors.extend(op_errors)
|
|
193
250
|
|
|
194
251
|
return result
|
|
195
252
|
|
|
@@ -212,14 +269,14 @@ def jwt_get_claims(errors: list[str] | None,
|
|
|
212
269
|
logger.debug(msg=f"Retrieve claims for token '{token}'")
|
|
213
270
|
|
|
214
271
|
try:
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
if
|
|
272
|
+
claims: dict[str, Any] = jwt.decode(jwt=token,
|
|
273
|
+
options={"verify_signature": False})
|
|
274
|
+
if claims.get("nat") in ["A", "R"]:
|
|
218
275
|
result = jwt.decode(jwt=token,
|
|
219
276
|
key=JWT_DECODING_KEY,
|
|
220
277
|
algorithms=[JWT_DEFAULT_ALGORITHM])
|
|
221
278
|
else:
|
|
222
|
-
result =
|
|
279
|
+
result = claims
|
|
223
280
|
except Exception as e:
|
|
224
281
|
if logger:
|
|
225
282
|
logger.error(msg=str(e))
|
|
@@ -250,12 +307,13 @@ def jwt_verify_request(request: Request,
|
|
|
250
307
|
|
|
251
308
|
# was a 'Bearer' authorization obtained ?
|
|
252
309
|
if auth_header and auth_header.startswith("Bearer "):
|
|
253
|
-
# yes, extract and validate the JWT token
|
|
310
|
+
# yes, extract and validate the JWT access token
|
|
254
311
|
token: str = auth_header.split(" ")[1]
|
|
255
312
|
if logger:
|
|
256
313
|
logger.debug(msg=f"Token is '{token}'")
|
|
257
314
|
errors: list[str] = []
|
|
258
315
|
jwt_validate_token(errors=errors,
|
|
316
|
+
nature="A",
|
|
259
317
|
token=token)
|
|
260
318
|
if errors:
|
|
261
319
|
err_msg = "; ".join(errors)
|
|
@@ -271,122 +329,3 @@ def jwt_verify_request(request: Request,
|
|
|
271
329
|
status=401)
|
|
272
330
|
|
|
273
331
|
return result
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
def jwt_claims(token: str = None) -> Response:
|
|
277
|
-
"""
|
|
278
|
-
REST service entry point for retrieving the claims of a JWT token.
|
|
279
|
-
|
|
280
|
-
Structure of the return data:
|
|
281
|
-
{
|
|
282
|
-
"<claim-1>": <value-of-claim-1>,
|
|
283
|
-
...
|
|
284
|
-
"<claim-n>": <value-of-claim-n>
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
:param token: the JWT token
|
|
288
|
-
:return: a *Response* containing the requested JWT token claims, or reporting an error
|
|
289
|
-
"""
|
|
290
|
-
# declare the return variable
|
|
291
|
-
result: Response
|
|
292
|
-
|
|
293
|
-
# retrieve the token
|
|
294
|
-
# noinspection PyUnusedLocal
|
|
295
|
-
if not token:
|
|
296
|
-
token = request.values.get("token")
|
|
297
|
-
if not token:
|
|
298
|
-
with contextlib.suppress(Exception):
|
|
299
|
-
token = request.get_json().get("token")
|
|
300
|
-
|
|
301
|
-
# has the token been obtained ?
|
|
302
|
-
if token:
|
|
303
|
-
# yes, obtain the token data
|
|
304
|
-
errors: list[str] = []
|
|
305
|
-
token_claims: dict[str, Any] = jwt_get_claims(errors=errors,
|
|
306
|
-
token=token)
|
|
307
|
-
if errors:
|
|
308
|
-
result = Response(response=errors,
|
|
309
|
-
status=400)
|
|
310
|
-
else:
|
|
311
|
-
result = jsonify(token_claims)
|
|
312
|
-
else:
|
|
313
|
-
# no, report the problem
|
|
314
|
-
result = Response(response="Invalid parameters",
|
|
315
|
-
status=400)
|
|
316
|
-
|
|
317
|
-
return result
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
def jwt_tokens(service_params: dict[str, Any] = None) -> Response:
|
|
321
|
-
"""
|
|
322
|
-
REST service entry point for obtaining or refreshing JWT tokens.
|
|
323
|
-
|
|
324
|
-
The requester must send, as parameter *service_params* or in the body of the request:
|
|
325
|
-
{
|
|
326
|
-
"account-id": "<string>" - required account identification
|
|
327
|
-
"refresh_token": <string> - if refresh is being requested
|
|
328
|
-
"<account-claim-key-1>": "<account-claim-value-1>", - optional superceding account claims
|
|
329
|
-
...
|
|
330
|
-
"<account-claim-key-n>": "<account-claim-value-n>"
|
|
331
|
-
}
|
|
332
|
-
if provided, the refresh token will cause a token refresh operation to be carried out.
|
|
333
|
-
Otherwise, a regular token issue operation is carried out, with the optional superceding
|
|
334
|
-
account claims being used (claims currently registered for the account may be overridden).
|
|
335
|
-
|
|
336
|
-
Structure of the return data:
|
|
337
|
-
{
|
|
338
|
-
"access_token": <jwt-token>,
|
|
339
|
-
"created_in": <timestamp>,
|
|
340
|
-
"expires_in": <seconds-to-expiration>,
|
|
341
|
-
"refresh_token": <jwt-token>
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
:param service_params: the optional JSON containing the request parameters (defaults to JSON in body)
|
|
345
|
-
:return: a *Response* containing the requested JWT token data, or reporting an error
|
|
346
|
-
"""
|
|
347
|
-
# declare the return variable
|
|
348
|
-
result: Response
|
|
349
|
-
|
|
350
|
-
# retrieve the parameters
|
|
351
|
-
# noinspection PyUnusedLocal
|
|
352
|
-
params: dict[str, Any] = service_params or {}
|
|
353
|
-
if not params:
|
|
354
|
-
with contextlib.suppress(Exception):
|
|
355
|
-
params = request.get_json()
|
|
356
|
-
account_id: str | None = params.pop("account-id", None)
|
|
357
|
-
refresh_token: str | None = params.pop("refresh-token", None)
|
|
358
|
-
err_msg: str | None = None
|
|
359
|
-
token_data: dict[str, Any] | None = None
|
|
360
|
-
|
|
361
|
-
# has the account been identified ?
|
|
362
|
-
if account_id:
|
|
363
|
-
# yes, proceed
|
|
364
|
-
if refresh_token:
|
|
365
|
-
errors: list[str] = []
|
|
366
|
-
claims: dict[str, Any] = jwt_get_claims(errors=errors,
|
|
367
|
-
token=refresh_token)
|
|
368
|
-
if errors:
|
|
369
|
-
err_msg = "; ".join(errors)
|
|
370
|
-
elif claims.get("nat") != "R":
|
|
371
|
-
err_msg = "Invalid parameters"
|
|
372
|
-
else:
|
|
373
|
-
params = claims
|
|
374
|
-
|
|
375
|
-
if not err_msg:
|
|
376
|
-
try:
|
|
377
|
-
token_data = __jwt_data.issue_tokens(account_id=account_id,
|
|
378
|
-
account_claims=params)
|
|
379
|
-
except Exception as e:
|
|
380
|
-
# token issuing failed
|
|
381
|
-
err_msg = str(e)
|
|
382
|
-
else:
|
|
383
|
-
# no, report the problem
|
|
384
|
-
err_msg = "Invalid parameters"
|
|
385
|
-
|
|
386
|
-
if err_msg:
|
|
387
|
-
result = Response(response=err_msg,
|
|
388
|
-
status=401)
|
|
389
|
-
else:
|
|
390
|
-
result = jsonify(token_data)
|
|
391
|
-
|
|
392
|
-
return result
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pypomes_jwt
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.2
|
|
4
4
|
Summary: A collection of Python pomes, penyeach (JWT module)
|
|
5
5
|
Project-URL: Homepage, https://github.com/TheWiseCoder/PyPomes-JWT
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/TheWiseCoder/PyPomes-JWT/issues
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
pypomes_jwt/__init__.py,sha256=Op7UEyEDniIkvk65ro8JUPHjGCV_q35k0YL_Ql_DjBc,1010
|
|
2
|
+
pypomes_jwt/jwt_constants.py,sha256=MGuIKc9tFsbWjx3wBlNbdibzytbndK9uhL2kVPW7X2A,4086
|
|
3
|
+
pypomes_jwt/jwt_data.py,sha256=e5KX0slUtrXbbyCtbdjycuqdQwVrvE8BK-_-XhVvHIs,16403
|
|
4
|
+
pypomes_jwt/jwt_pomes.py,sha256=uyhwZzI781yGzWbHKfI-aM9dVXHBB28okQzlvfT4D00,12130
|
|
5
|
+
pypomes_jwt-0.7.2.dist-info/METADATA,sha256=WamGD3ya5b3Ut04oVeFX8TzEeTHRZra6cjpmxJVkeBI,599
|
|
6
|
+
pypomes_jwt-0.7.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
7
|
+
pypomes_jwt-0.7.2.dist-info/licenses/LICENSE,sha256=NdakochSXm_H_-DSL_x2JlRCkYikj3snYYvTwgR5d_c,1086
|
|
8
|
+
pypomes_jwt-0.7.2.dist-info/RECORD,,
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
pypomes_jwt/__init__.py,sha256=4dBUGZTw1c-TeZukYjwAM7VWFzoFBSEyAN26jgjQRtM,1022
|
|
2
|
-
pypomes_jwt/jwt_constants.py,sha256=k1PFqBF7KI2Ie8ErOW1zw9IWTgqjkxvU4m2eKGr_1EA,2927
|
|
3
|
-
pypomes_jwt/jwt_data.py,sha256=npKZqHZbftvvOGCRAl-2yovUbqCQW0FvcQvyuYGXA_U,14189
|
|
4
|
-
pypomes_jwt/jwt_pomes.py,sha256=w2sgJUF4CZibBCxU_-PZvrQyMm1saP0FBnf1yCCUSak,14247
|
|
5
|
-
pypomes_jwt-0.7.1.dist-info/METADATA,sha256=S092HRvlJYZVEgHbzJyZ3o1bAqlIqUwEri37srho9jA,599
|
|
6
|
-
pypomes_jwt-0.7.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
7
|
-
pypomes_jwt-0.7.1.dist-info/licenses/LICENSE,sha256=NdakochSXm_H_-DSL_x2JlRCkYikj3snYYvTwgR5d_c,1086
|
|
8
|
-
pypomes_jwt-0.7.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|