pypomes-iam 0.5.0__tar.gz → 0.5.2__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.

Potentially problematic release.


This version of pypomes-iam might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pypomes_iam
3
- Version: 0.5.0
3
+ Version: 0.5.2
4
4
  Summary: A collection of Python pomes, penyeach (IAM modules)
5
5
  Project-URL: Homepage, https://github.com/TheWiseCoder/PyPomes-IAM
6
6
  Project-URL: Bug Tracker, https://github.com/TheWiseCoder/PyPomes-IAM/issues
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
6
6
 
7
7
  [project]
8
8
  name = "pypomes_iam"
9
- version = "0.5.0"
9
+ version = "0.5.2"
10
10
  authors = [
11
11
  { name="GT Nunes", email="wisecoder01@gmail.com" }
12
12
  ]
@@ -55,6 +55,64 @@ _IAM_SERVERS: Final[dict[IamServer, dict[str, Any]]] = {}
55
55
  _iam_lock: Final[RLock] = RLock()
56
56
 
57
57
 
58
+ def _iam_server_from_endpoint(endpoint: str,
59
+ errors: list[str] | None,
60
+ logger: Logger | None) -> IamServer | None:
61
+ """
62
+ Retrieve the registered *IAM* server associated with the service's invocation *endpoint*.
63
+
64
+ :param endpoint: the service's invocation endpoint
65
+ :param errors: incidental error messages
66
+ :param logger: optional logger
67
+ :return: the corresponding *IAM* server, or *None* if one could not be obtained
68
+ """
69
+ # declare the return variable
70
+ result: IamServer | None
71
+
72
+ if endpoint.startswith("jusbr"):
73
+ result = IamServer.IAM_JUSRBR
74
+ elif endpoint.startswith("keycloak"):
75
+ result = IamServer.IAM_KEYCLOAK
76
+ else:
77
+ result = None
78
+ msg: str = f"Unable to find a IAM server to service endpoint '{endpoint}'"
79
+ if logger:
80
+ logger.error(msg=msg)
81
+ if isinstance(errors, list):
82
+ errors.append(msg)
83
+
84
+ return result
85
+
86
+
87
+ def _iam_server_from_issuer(issuer: str,
88
+ errors: list[str] | None,
89
+ logger: Logger | None) -> IamServer | None:
90
+ """
91
+ Retrieve the registered *IAM* server associated with the token's *issuer*.
92
+
93
+ :param issuer: the token's issuer
94
+ :param errors: incidental error messages
95
+ :param logger: optional logger
96
+ :return: the corresponding *IAM* server, or *None* if one could not be obtained
97
+ """
98
+ # initialize the return variable
99
+ result: IamServer | None = None
100
+
101
+ for iam_server, server_data in _IAM_SERVERS.items():
102
+ if server_data["base-url"] == issuer:
103
+ result = IamServer(iam_server)
104
+ break
105
+
106
+ if not result:
107
+ msg: str = f"Unable to find a IAM server associated with token issuer '{issuer}'"
108
+ if logger:
109
+ logger.error(msg=msg)
110
+ if isinstance(errors, list):
111
+ errors.append(msg)
112
+
113
+ return result
114
+
115
+
58
116
  def _get_public_key(iam_server: IamServer,
59
117
  errors: list[str] | None,
60
118
  logger: Logger | None) -> str:
@@ -178,35 +236,6 @@ def _get_user_data(iam_server: IamServer,
178
236
  return result
179
237
 
180
238
 
181
- def _get_iam_server(endpoint: str,
182
- errors: list[str] | None,
183
- logger: Logger | None) -> IamServer | None:
184
- """
185
- Retrieve the registered *IAM* server associated with the service's invocation *endpoint*.
186
-
187
- :param endpoint: the service's invocation endpoint
188
- :param errors: incidental error messages
189
- :param logger: optional logger
190
- :return: the corresponding *IAM* server, or *None* if one could not be obtained
191
- """
192
- # declare the return variable
193
- result: IamServer | None
194
-
195
- if endpoint.startswith("jusbr"):
196
- result = IamServer.IAM_JUSRBR
197
- elif endpoint.startswith("keycloak"):
198
- result = IamServer.IAM_KEYCLOAK
199
- else:
200
- result = None
201
- msg: str = f"Unable to find a IAM server to service endpoint '{endpoint}'"
202
- if logger:
203
- logger.error(msg=msg)
204
- if isinstance(errors, list):
205
- errors.append(msg)
206
-
207
- return result
208
-
209
-
210
239
  def _get_iam_registry(iam_server: IamServer,
211
240
  errors: list[str] | None,
212
241
  logger: Logger | None) -> dict[str, Any]:
@@ -4,16 +4,34 @@ import secrets
4
4
  import string
5
5
  import sys
6
6
  from datetime import datetime
7
+ from flask import Request, Response, request
7
8
  from logging import Logger
8
9
  from pypomes_core import TZ_LOCAL, exc_format
9
10
  from typing import Any
10
11
 
11
12
  from .iam_common import (
12
13
  IamServer, _iam_lock,
13
- _get_iam_users, _get_iam_registry,
14
- _get_login_timeout, _get_user_data, # _get_public_key
14
+ _get_iam_users, _get_iam_registry, # _get_public_key,
15
+ _get_login_timeout, _get_user_data, _iam_server_from_issuer
15
16
  )
16
- from .token_pomes import token_validate
17
+ from .token_pomes import token_get_claims, token_validate
18
+
19
+
20
+ def jwt_required(func: callable) -> callable:
21
+ """
22
+ Create a decorator to authenticate service endpoints with JWT tokens.
23
+
24
+ :param func: the function being decorated
25
+ """
26
+ # ruff: noqa: ANN003 - Missing type annotation for *{name}
27
+ def wrapper(*args, **kwargs) -> Response:
28
+ response: Response = __request_validate(request=request)
29
+ return response if response else func(*args, **kwargs)
30
+
31
+ # prevent a rogue error ("View function mapping is overwriting an existing endpoint function")
32
+ wrapper.__name__ = func.__name__
33
+
34
+ return wrapper
17
35
 
18
36
 
19
37
  def user_login(iam_server: IamServer,
@@ -24,7 +42,7 @@ def user_login(iam_server: IamServer,
24
42
  Build the URL for redirecting the request to *iam_server*'s authentication page.
25
43
 
26
44
  These are the expected attributes in *args*:
27
- - user-id: optional, identifies the reference user (aliases: 'user_id', 'login')
45
+ - user-id: optional, identifies the reference user (alias: 'login')
28
46
  - redirect-uri: a parameter to be added to the query part of the returned URL
29
47
 
30
48
  If provided, the user identification will be validated against the authorization data
@@ -41,7 +59,7 @@ def user_login(iam_server: IamServer,
41
59
  result: str | None = None
42
60
 
43
61
  # obtain the optional user's identification
44
- user_id: str = args.get("user-id") or args.get("user_id") or args.get("login")
62
+ user_id: str = args.get("user-id") or args.get("login")
45
63
 
46
64
  # build the user data
47
65
  # ('oauth_state' is a randomly-generated string, thus 'user_data' is always a new entry)
@@ -84,7 +102,7 @@ def user_logout(iam_server: IamServer,
84
102
  """
85
103
  Logout the user, by removing all data associating it from *iam_server*'s registry.
86
104
 
87
- The user is identified by the attribute *user-id*, *user_id*, or "login", provided in *args*.
105
+ The user is identified by the attribute *user-id* or "login", provided in *args*.
88
106
  If successful, remove all data relating to the user from the *IAM* server's registry.
89
107
  Otherwise, this operation fails silently, unless an error has ocurred.
90
108
 
@@ -94,7 +112,7 @@ def user_logout(iam_server: IamServer,
94
112
  :param logger: optional logger
95
113
  """
96
114
  # obtain the user's identification
97
- user_id: str = args.get("user-id") or args.get("user_id") or args.get("login")
115
+ user_id: str = args.get("user-id") or args.get("login")
98
116
 
99
117
  if user_id:
100
118
  with _iam_lock:
@@ -115,19 +133,19 @@ def user_token(iam_server: IamServer,
115
133
  """
116
134
  Retrieve the authentication token for the user, from *iam_server*.
117
135
 
118
- The user is identified by the attribute *user-id*, *user_id*, or *login*, provided in *args*.
136
+ The user is identified by the attribute *user-id* or *login*, provided in *args*.
119
137
 
120
138
  :param iam_server: the reference registered *IAM* server
121
139
  :param args: the arguments passed when requesting the service
122
140
  :param errors: incidental error messages
123
141
  :param logger: optional logger
124
- :return: the token for *user_id*, or *None* if error
142
+ :return: the token for user indicated, or *None* if error
125
143
  """
126
144
  # initialize the return variable
127
145
  result: str | None = None
128
146
 
129
147
  # obtain the user's identification
130
- user_id: str = args.get("user-id") or args.get("user_id") or args.get("login")
148
+ user_id: str = args.get("user-id") or args.get("login")
131
149
 
132
150
  err_msg: str | None = None
133
151
  if user_id:
@@ -272,7 +290,7 @@ def token_exchange(iam_server: IamServer,
272
290
  Request *iam_server* to issue a token in exchange for the token obtained from another *IAM* server.
273
291
 
274
292
  The expected parameters in *args* are:
275
- - user-id: identification for the reference user (aliases: 'user_id', 'login')
293
+ - user-id: identification for the reference user (alias: 'login')
276
294
  - token: the token to be exchanged
277
295
 
278
296
  The typical data set returned contains the following attributes:
@@ -294,10 +312,10 @@ def token_exchange(iam_server: IamServer,
294
312
  result: dict[str, Any] | None = None
295
313
 
296
314
  # obtain the user's identification
297
- user_id: str = args.get("user-id") or args.get("user_id") or args.get("login")
315
+ user_id: str = args.get("user-id") or args.get("login")
298
316
 
299
- # obtain the token to be exchanges
300
- token: str = args.get("token")
317
+ # obtain the token to be exchanged
318
+ token: str = args.get("access-token")
301
319
 
302
320
  if user_id and token:
303
321
  # HAZARD: only 'IAM_KEYCLOAK' is currently supported
@@ -339,6 +357,63 @@ def token_exchange(iam_server: IamServer,
339
357
  return result
340
358
 
341
359
 
360
+ def __request_validate(request: Request) -> Response:
361
+ """
362
+ Verify whether the HTTP *request* has the proper authorization, as per the JWT standard.
363
+
364
+ This implementation assumes that HTTP requests are handled with the *Flask* framework.
365
+
366
+ :param request: the *request* to be verified
367
+ :return: *None* if the *request* is valid, otherwise a *Response* reporting the error
368
+ """
369
+ # initialize the return variable
370
+ result: Response | None = None
371
+
372
+ # retrieve the authorization from the request header
373
+ auth_header: str = request.headers.get("Authorization")
374
+
375
+ # validate the authorization token
376
+ bad_token: bool = True
377
+ if auth_header and auth_header.startswith("Bearer "):
378
+ # extract and validate the JWT access token
379
+ token: str = auth_header.split(" ")[1]
380
+ claims: dict[str, Any] = token_get_claims(token=token)
381
+ if claims:
382
+ issuer: str = claims["payload"].get("iss")
383
+ recipient_attr: str | None = None
384
+ recipient_id: str = request.values.get("user-id") or request.values.get("login")
385
+ with _iam_lock:
386
+ iam_server: IamServer = _iam_server_from_issuer(issuer=issuer,
387
+ errors=None,
388
+ logger=None)
389
+ # public_key: str = _get_public_key(iam_server=iam_server,
390
+ # errors=errors,
391
+ # logger=logger)
392
+ public_key = None
393
+
394
+ # validate the token's recipient only if a user identification is provided
395
+ if recipient_id:
396
+ registry: dict[str, Any] = _get_iam_registry(iam_server=iam_server,
397
+ errors=None,
398
+ logger=None)
399
+ recipient_attr = registry["recipient-attr"]
400
+
401
+ # validate the token
402
+ if token_validate(token=token,
403
+ issuer=issuer,
404
+ recipient_id=recipient_id,
405
+ recipient_attr=recipient_attr,
406
+ public_key=public_key):
407
+ # token is valid
408
+ bad_token = False
409
+
410
+ # deny the authorization
411
+ if bad_token:
412
+ result = Response(response="Authorization failed",
413
+ status=401)
414
+ return result
415
+
416
+
342
417
  def __post_for_token(iam_server: IamServer,
343
418
  body_data: dict[str, Any],
344
419
  errors: list[str] | None,
@@ -3,7 +3,7 @@ from flask import Request, Response, request, jsonify
3
3
  from logging import Logger
4
4
  from typing import Any
5
5
 
6
- from .iam_common import IamServer, _iam_lock, _get_iam_server
6
+ from .iam_common import IamServer, _iam_lock, _iam_server_from_endpoint
7
7
  from .iam_pomes import (
8
8
  user_login, user_logout,
9
9
  user_token, token_exchange, login_callback
@@ -33,7 +33,7 @@ def service_login() -> Response:
33
33
  Entry point for the IAM server's login service.
34
34
 
35
35
  These are the expected request parameters:
36
- - user-id: optional, identifies the reference user (aliases: 'user_id', 'login')
36
+ - user-id: optional, identifies the reference user (alias: 'login')
37
37
  - redirect-uri: a parameter to be added to the query part of the returned URL
38
38
 
39
39
  If provided, the user identification will be validated against the authorization data
@@ -55,9 +55,9 @@ def service_login() -> Response:
55
55
  errors: list[str] = []
56
56
  with _iam_lock:
57
57
  # retrieve the IAM server
58
- iam_server: IamServer = _get_iam_server(endpoint=request.endpoint,
59
- errors=errors,
60
- logger=__IAM_LOGGER)
58
+ iam_server: IamServer = _iam_server_from_endpoint(endpoint=request.endpoint,
59
+ errors=errors,
60
+ logger=__IAM_LOGGER)
61
61
  if iam_server:
62
62
  # obtain the login URL
63
63
  login_url: str = user_login(iam_server=iam_server,
@@ -67,8 +67,8 @@ def service_login() -> Response:
67
67
  if login_url:
68
68
  result = jsonify({"login-url": login_url})
69
69
  if errors:
70
- result = Response("; ".join(errors))
71
- result.status_code = 400
70
+ result = Response(response="; ".join(errors),
71
+ status=400)
72
72
 
73
73
  # log the response
74
74
  if __IAM_LOGGER:
@@ -85,7 +85,7 @@ def service_logout() -> Response:
85
85
  """
86
86
  Entry point for the JusBR logout service.
87
87
 
88
- The user is identified by the attribute *user-id*, *user_id*, or "login", provided as a request parameter.
88
+ The user is identified by the attribute *user-id* or "login", provided as a request parameter.
89
89
  If successful, remove all data relating to the user from the *IAM* server's registry.
90
90
  Otherwise, this operation fails silently, unless an error has ocurred.
91
91
 
@@ -101,9 +101,9 @@ def service_logout() -> Response:
101
101
  errors: list[str] = []
102
102
  with _iam_lock:
103
103
  # retrieve the IAM server
104
- iam_server: IamServer = _get_iam_server(endpoint=request.endpoint,
105
- errors=errors,
106
- logger=__IAM_LOGGER)
104
+ iam_server: IamServer = _iam_server_from_endpoint(endpoint=request.endpoint,
105
+ errors=errors,
106
+ logger=__IAM_LOGGER)
107
107
  if iam_server:
108
108
  # logout the user
109
109
  user_logout(iam_server=iam_server,
@@ -111,8 +111,8 @@ def service_logout() -> Response:
111
111
  errors=errors,
112
112
  logger=__IAM_LOGGER)
113
113
  if errors:
114
- result = Response("; ".join(errors))
115
- result.status_code = 400
114
+ result = Response(response="; ".join(errors),
115
+ status=400)
116
116
  else:
117
117
  result = Response(status=204)
118
118
 
@@ -142,7 +142,7 @@ def service_callback() -> Response:
142
142
  On success, the returned *Response* will contain the following JSON:
143
143
  {
144
144
  "user-id": <reference-user-identification>,
145
- "token": <token>
145
+ "access-token": <token>
146
146
  }
147
147
 
148
148
  :return: *Response* containing the reference user identification and the token, or *BAD REQUEST*
@@ -155,9 +155,9 @@ def service_callback() -> Response:
155
155
  token_data: tuple[str, str] | None = None
156
156
  with _iam_lock:
157
157
  # retrieve the IAM server
158
- iam_server: IamServer = _get_iam_server(endpoint=request.endpoint,
159
- errors=errors,
160
- logger=__IAM_LOGGER)
158
+ iam_server: IamServer = _iam_server_from_endpoint(endpoint=request.endpoint,
159
+ errors=errors,
160
+ logger=__IAM_LOGGER)
161
161
  if iam_server:
162
162
  # process the callback operation
163
163
  token_data = login_callback(iam_server=iam_server,
@@ -170,7 +170,7 @@ def service_callback() -> Response:
170
170
  result.status_code = 400
171
171
  else:
172
172
  result = jsonify({"user-id": token_data[0],
173
- "token": token_data[1]})
173
+ "access-token": token_data[1]})
174
174
  # log the response
175
175
  if __IAM_LOGGER:
176
176
  __IAM_LOGGER.debug(msg=f"Response {result}, {result.get_data(as_text=True)}")
@@ -186,12 +186,12 @@ def service_token() -> Response:
186
186
  """
187
187
  Entry point for retrieving a token from the *IAM* server.
188
188
 
189
- The user is identified by the attribute *user-id*, *user_id*, or "login", provided as a request parameter.
189
+ The user is identified by the attribute *user-id* or "login", provided as a request parameter.
190
190
 
191
191
  On success, the returned *Response* will contain the following JSON:
192
192
  {
193
193
  "user-id": <reference-user-identification>,
194
- "token": <token>
194
+ "access-token": <token>
195
195
  }
196
196
 
197
197
  :return: *Response* containing the user reference identification and the token, or *BAD REQUEST*
@@ -202,16 +202,16 @@ def service_token() -> Response:
202
202
 
203
203
  # obtain the user's identification
204
204
  args: dict[str, Any] = request.args
205
- user_id: str = args.get("user-id") or args.get("user_id") or args.get("login")
205
+ user_id: str = args.get("user-id") or args.get("login")
206
206
 
207
207
  errors: list[str] = []
208
208
  token: str | None = None
209
209
  if user_id:
210
210
  with _iam_lock:
211
211
  # retrieve the IAM server
212
- iam_server: IamServer = _get_iam_server(endpoint=request.endpoint,
213
- errors=errors,
214
- logger=__IAM_LOGGER)
212
+ iam_server: IamServer = _iam_server_from_endpoint(endpoint=request.endpoint,
213
+ errors=errors,
214
+ logger=__IAM_LOGGER)
215
215
  if iam_server:
216
216
  # retrieve the token
217
217
  errors: list[str] = []
@@ -227,11 +227,11 @@ def service_token() -> Response:
227
227
 
228
228
  result: Response
229
229
  if errors:
230
- result = Response("; ".join(errors))
231
- result.status_code = 400
230
+ result = Response(response="; ".join(errors),
231
+ status=400)
232
232
  else:
233
233
  result = jsonify({"user-id": user_id,
234
- "token": token})
234
+ "access-token": token})
235
235
  # log the response
236
236
  if __IAM_LOGGER:
237
237
  __IAM_LOGGER.debug(msg=f"Response {result}, {result.get_data(as_text=True)}")
@@ -247,8 +247,8 @@ def service_exchange() -> Response:
247
247
 
248
248
  This is currently limited to the *KEYCLOAK* server. The token itself is stored in *KEYCLOAK*'s registry.
249
249
  The expected request parameters are:
250
- - user-id: identification for the reference user (aliases: 'user_id', 'login')
251
- - token: the token to be exchanged
250
+ - user-id: identification for the reference user (alias: 'login')
251
+ - access-token: the token to be exchanged
252
252
 
253
253
  If the exchange is successful, the token data is stored in the *IAM* server's registry, and returned.
254
254
  Otherwise, *errors* will contain the appropriate error message.
@@ -271,9 +271,9 @@ def service_exchange() -> Response:
271
271
  errors: list[str] = []
272
272
  with _iam_lock:
273
273
  # retrieve the IAM server (currently, only 'IAM_KEYCLOAK' is supported)
274
- iam_server: IamServer = _get_iam_server(endpoint=request.endpoint,
275
- errors=errors,
276
- logger=__IAM_LOGGER)
274
+ iam_server: IamServer = _iam_server_from_endpoint(endpoint=request.endpoint,
275
+ errors=errors,
276
+ logger=__IAM_LOGGER)
277
277
  # exchange the token
278
278
  token_data: dict[str, Any] | None = None
279
279
  if iam_server:
@@ -284,8 +284,8 @@ def service_exchange() -> Response:
284
284
  logger=__IAM_LOGGER)
285
285
  result: Response
286
286
  if errors:
287
- result = Response("; ".join(errors))
288
- result.status_code = 400
287
+ result = Response(response="; ".join(errors),
288
+ status=400)
289
289
  else:
290
290
  result = jsonify(token_data)
291
291
 
@@ -24,6 +24,7 @@ JUSBR_ENDPOINT_TOKEN: Final[str] = env_get_str(key=f"{APP_PREFIX}_JUSBR_ENDPOINT
24
24
 
25
25
  JUSBR_PUBLIC_KEY_LIFETIME: Final[int] = env_get_int(key=f"{APP_PREFIX}_JUSBR_PUBLIC_KEY_LIFETIME",
26
26
  def_value=86400) # 24 hours
27
+ JUSBR_REALM: Final[str] = env_get_str(key=f"{APP_PREFIX}_JUSBR_REALM")
27
28
  JUSBR_RECIPIENT_ATTR: Final[str] = env_get_str(key=f"{APP_PREFIX}_JUSBR_RECIPIENT_ATTR",
28
29
  def_value="preferred_username")
29
30
  JUSBR_URL_AUTH_BASE: Final[str] = env_get_str(key=f"{APP_PREFIX}_JUSBR_URL_AUTH_BASE")
@@ -31,6 +32,7 @@ JUSBR_URL_AUTH_BASE: Final[str] = env_get_str(key=f"{APP_PREFIX}_JUSBR_URL_AUTH_
31
32
 
32
33
  def jusbr_setup(flask_app: Flask,
33
34
  base_url: str = JUSBR_URL_AUTH_BASE,
35
+ realm: str = JUSBR_REALM,
34
36
  client_id: str = JUSBR_CLIENT_ID,
35
37
  client_secret: str = JUSBR_CLIENT_SECRET,
36
38
  client_timeout: int = JUSBR_CLIENT_TIMEOUT,
@@ -47,6 +49,7 @@ def jusbr_setup(flask_app: Flask,
47
49
 
48
50
  :param flask_app: the Flask application
49
51
  :param base_url: base URL to request JusBR services
52
+ :param realm: the JusBR realm
50
53
  :param client_id: the client's identification with JusBR
51
54
  :param client_secret: the client's password with JusBR
52
55
  :param client_timeout: timeout for login authentication (in seconds,defaults to no timeout)
@@ -64,7 +67,7 @@ def jusbr_setup(flask_app: Flask,
64
67
  cache["users"] = {}
65
68
  with _iam_lock:
66
69
  _IAM_SERVERS[IamServer.IAM_JUSRBR] = {
67
- "base-url": base_url,
70
+ "base-url": f"{base_url}/realms/{realm}",
68
71
  "client-id": client_id,
69
72
  "client-secret": client_secret,
70
73
  "client-timeout": client_timeout,
@@ -7,6 +7,45 @@ from pypomes_core import exc_format
7
7
  from typing import Any
8
8
 
9
9
 
10
+ def token_get_claims(token: str,
11
+ errors: list[str] = None,
12
+ logger: Logger = None) -> dict[str, dict[str, Any]] | None:
13
+ """
14
+ Retrieve the claims set of a JWT *token*.
15
+
16
+ Any well-constructed JWT token may be provided in *token*.
17
+ Note that neither the token's signature nor its expiration is verified.
18
+
19
+ :param token: the refrence token
20
+ :param errors: incidental error messages
21
+ :param logger: optional logger
22
+ :return: the token's claimset, or *None* if error
23
+ """
24
+ # initialize the return variable
25
+ result: dict[str, dict[str, Any]] | None = None
26
+
27
+ if logger:
28
+ logger.debug(msg="Retrieve claims for token")
29
+
30
+ try:
31
+ header: dict[str, Any] = jwt.get_unverified_header(jwt=token)
32
+ payload: dict[str, Any] = jwt.decode(jwt=token,
33
+ options={"verify_signature": False})
34
+ result = {
35
+ "header": header,
36
+ "payload": payload
37
+ }
38
+ except Exception as e:
39
+ exc_err: str = exc_format(exc=e,
40
+ exc_info=sys.exc_info())
41
+ if logger:
42
+ logger.error(msg=f"Error retrieving the token's claims: {exc_err}")
43
+ if isinstance(errors, list):
44
+ errors.append(exc_err)
45
+
46
+ return result
47
+
48
+
10
49
  def token_validate(token: str,
11
50
  issuer: str = None,
12
51
  recipient_id: str = None,
File without changes
File without changes
File without changes