amazon-creatorsapi-python-sdk 1.0.0__py3-none-any.whl → 1.2.0__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.
- {amazon_creatorsapi_python_sdk-1.0.0.dist-info → amazon_creatorsapi_python_sdk-1.2.0.dist-info}/METADATA +11 -5
- amazon_creatorsapi_python_sdk-1.2.0.dist-info/RECORD +109 -0
- {amazon_creatorsapi_python_sdk-1.0.0.dist-info → amazon_creatorsapi_python_sdk-1.2.0.dist-info}/WHEEL +1 -1
- creatorsapi_python_sdk/__init__.py +128 -127
- creatorsapi_python_sdk/api/__init__.py +5 -5
- creatorsapi_python_sdk/api/default_api.py +2427 -2412
- creatorsapi_python_sdk/api_client.py +915 -912
- creatorsapi_python_sdk/api_response.py +21 -21
- creatorsapi_python_sdk/auth/__init__.py +21 -21
- creatorsapi_python_sdk/auth/oauth2_config.py +139 -123
- creatorsapi_python_sdk/auth/oauth2_token_manager.py +133 -120
- creatorsapi_python_sdk/configuration.py +455 -455
- creatorsapi_python_sdk/exceptions.py +204 -204
- creatorsapi_python_sdk/models/__init__.py +111 -110
- creatorsapi_python_sdk/models/access_denied_exception_response_content.py +97 -97
- creatorsapi_python_sdk/models/access_denied_reason.py +45 -45
- creatorsapi_python_sdk/models/availability.py +44 -44
- creatorsapi_python_sdk/models/browse_node.py +116 -116
- creatorsapi_python_sdk/models/browse_node_ancestor.py +103 -103
- creatorsapi_python_sdk/models/browse_node_child.py +96 -96
- creatorsapi_python_sdk/models/browse_node_info.py +106 -106
- creatorsapi_python_sdk/models/browse_nodes_result.py +100 -100
- creatorsapi_python_sdk/models/by_line_info.py +111 -111
- creatorsapi_python_sdk/models/classifications.py +101 -101
- creatorsapi_python_sdk/models/condition.py +44 -44
- creatorsapi_python_sdk/models/content_info.py +113 -113
- creatorsapi_python_sdk/models/content_rating.py +96 -96
- creatorsapi_python_sdk/models/contributor.py +98 -98
- creatorsapi_python_sdk/models/customer_reviews.py +98 -98
- creatorsapi_python_sdk/models/deal_details.py +102 -102
- creatorsapi_python_sdk/models/delivery_flag.py +46 -46
- creatorsapi_python_sdk/models/dimension_based_attribute.py +111 -111
- creatorsapi_python_sdk/models/error_data.py +94 -94
- creatorsapi_python_sdk/models/external_ids.py +106 -106
- creatorsapi_python_sdk/models/feed.py +98 -98
- creatorsapi_python_sdk/models/get_browse_nodes_request_content.py +107 -107
- creatorsapi_python_sdk/models/get_browse_nodes_resource.py +44 -44
- creatorsapi_python_sdk/models/get_browse_nodes_response_content.py +106 -106
- creatorsapi_python_sdk/models/get_feed_request_content.py +93 -93
- creatorsapi_python_sdk/models/get_feed_response_content.py +92 -92
- creatorsapi_python_sdk/models/get_items_request_content.py +124 -124
- creatorsapi_python_sdk/models/get_items_resource.py +76 -76
- creatorsapi_python_sdk/models/get_items_response_content.py +106 -106
- creatorsapi_python_sdk/models/get_report_request_content.py +93 -93
- creatorsapi_python_sdk/models/get_report_response_content.py +92 -92
- creatorsapi_python_sdk/models/get_variations_request_content.py +135 -135
- creatorsapi_python_sdk/models/get_variations_resource.py +79 -79
- creatorsapi_python_sdk/models/get_variations_response_content.py +106 -106
- creatorsapi_python_sdk/models/image_size.py +96 -96
- creatorsapi_python_sdk/models/image_type.py +111 -111
- creatorsapi_python_sdk/models/images.py +105 -105
- creatorsapi_python_sdk/models/internal_server_exception_response_content.py +94 -94
- creatorsapi_python_sdk/models/item.py +138 -138
- creatorsapi_python_sdk/models/item_info.py +156 -156
- creatorsapi_python_sdk/models/items_result.py +100 -100
- creatorsapi_python_sdk/models/language_type.py +94 -94
- creatorsapi_python_sdk/models/languages.py +104 -104
- creatorsapi_python_sdk/models/list_feeds_response_content.py +100 -100
- creatorsapi_python_sdk/models/list_reports_response_content.py +100 -100
- creatorsapi_python_sdk/models/manufacture_info.py +106 -106
- creatorsapi_python_sdk/models/money.py +96 -96
- creatorsapi_python_sdk/models/multi_valued_attribute.py +96 -96
- creatorsapi_python_sdk/models/offer_availability_v2.py +98 -98
- creatorsapi_python_sdk/models/offer_condition_v2.py +96 -96
- creatorsapi_python_sdk/models/offer_listing_v2.py +133 -133
- creatorsapi_python_sdk/models/offer_loyalty_points_v2.py +92 -92
- creatorsapi_python_sdk/models/offer_merchant_info_v2.py +94 -94
- creatorsapi_python_sdk/models/offer_price_v2.py +113 -113
- creatorsapi_python_sdk/models/offer_saving_basis.py +101 -101
- creatorsapi_python_sdk/models/offer_savings.py +98 -98
- creatorsapi_python_sdk/models/offer_type.py +45 -45
- creatorsapi_python_sdk/models/offers_v2.py +100 -100
- creatorsapi_python_sdk/models/product_info.py +124 -124
- creatorsapi_python_sdk/models/rating.py +92 -92
- creatorsapi_python_sdk/models/refinement.py +104 -104
- creatorsapi_python_sdk/models/refinement_bin.py +94 -94
- creatorsapi_python_sdk/models/report_metadata.py +98 -98
- creatorsapi_python_sdk/models/resource_not_found_exception_response_content.py +98 -98
- creatorsapi_python_sdk/models/saving_basis_type.py +46 -46
- creatorsapi_python_sdk/models/search_items_request_content.py +242 -242
- creatorsapi_python_sdk/models/search_items_resource.py +77 -77
- creatorsapi_python_sdk/models/search_items_response_content.py +106 -106
- creatorsapi_python_sdk/models/search_refinements.py +110 -110
- creatorsapi_python_sdk/models/search_result.py +110 -110
- creatorsapi_python_sdk/models/single_boolean_valued_attribute.py +96 -96
- creatorsapi_python_sdk/models/single_integer_valued_attribute.py +96 -96
- creatorsapi_python_sdk/models/single_string_valued_attribute.py +96 -96
- creatorsapi_python_sdk/models/sort_by.py +48 -48
- creatorsapi_python_sdk/models/technical_info.py +102 -102
- creatorsapi_python_sdk/models/throttle_exception_response_content.py +98 -98
- creatorsapi_python_sdk/models/trade_in_info.py +98 -98
- creatorsapi_python_sdk/models/trade_in_price.py +96 -96
- creatorsapi_python_sdk/models/unauthorized_exception_reason.py +51 -51
- creatorsapi_python_sdk/models/unauthorized_exception_response_content.py +97 -97
- creatorsapi_python_sdk/models/unit_based_attribute.py +98 -98
- creatorsapi_python_sdk/models/validation_exception_field.py +94 -94
- creatorsapi_python_sdk/models/validation_exception_reason.py +48 -48
- creatorsapi_python_sdk/models/validation_exception_response_content.py +107 -107
- creatorsapi_python_sdk/models/variation_attribute.py +94 -94
- creatorsapi_python_sdk/models/variation_dimension.py +98 -98
- creatorsapi_python_sdk/models/variation_summary.py +110 -104
- creatorsapi_python_sdk/models/variation_summary_price.py +101 -0
- creatorsapi_python_sdk/models/variations_result.py +106 -106
- creatorsapi_python_sdk/models/website_sales_rank.py +98 -98
- creatorsapi_python_sdk/rest.py +262 -262
- amazon_creatorsapi_python_sdk-1.0.0.dist-info/RECORD +0 -108
- {amazon_creatorsapi_python_sdk-1.0.0.dist-info → amazon_creatorsapi_python_sdk-1.2.0.dist-info}/licenses/LICENSE.txt +0 -0
- {amazon_creatorsapi_python_sdk-1.0.0.dist-info → amazon_creatorsapi_python_sdk-1.2.0.dist-info}/licenses/NOTICE.txt +0 -0
- {amazon_creatorsapi_python_sdk-1.0.0.dist-info → amazon_creatorsapi_python_sdk-1.2.0.dist-info}/top_level.txt +0 -0
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
"""API response object."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
from typing import Optional, Generic, Mapping, TypeVar
|
|
5
|
-
from pydantic import Field, StrictInt, StrictBytes, BaseModel
|
|
6
|
-
|
|
7
|
-
T = TypeVar("T")
|
|
8
|
-
|
|
9
|
-
class ApiResponse(BaseModel, Generic[T]):
|
|
10
|
-
"""
|
|
11
|
-
API response object
|
|
12
|
-
"""
|
|
13
|
-
|
|
14
|
-
status_code: StrictInt = Field(description="HTTP status code")
|
|
15
|
-
headers: Optional[Mapping[str, str]] = Field(None, description="HTTP headers")
|
|
16
|
-
data: T = Field(description="Deserialized data given the data type")
|
|
17
|
-
raw_data: StrictBytes = Field(description="Raw data (HTTP response body)")
|
|
18
|
-
|
|
19
|
-
model_config = {
|
|
20
|
-
"arbitrary_types_allowed": True
|
|
21
|
-
}
|
|
1
|
+
"""API response object."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
from typing import Optional, Generic, Mapping, TypeVar
|
|
5
|
+
from pydantic import Field, StrictInt, StrictBytes, BaseModel
|
|
6
|
+
|
|
7
|
+
T = TypeVar("T")
|
|
8
|
+
|
|
9
|
+
class ApiResponse(BaseModel, Generic[T]):
|
|
10
|
+
"""
|
|
11
|
+
API response object
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
status_code: StrictInt = Field(description="HTTP status code")
|
|
15
|
+
headers: Optional[Mapping[str, str]] = Field(None, description="HTTP headers")
|
|
16
|
+
data: T = Field(description="Deserialized data given the data type")
|
|
17
|
+
raw_data: StrictBytes = Field(description="Raw data (HTTP response body)")
|
|
18
|
+
|
|
19
|
+
model_config = {
|
|
20
|
+
"arbitrary_types_allowed": True
|
|
21
|
+
}
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
# coding: utf-8
|
|
2
|
-
|
|
3
|
-
"""
|
|
4
|
-
Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
5
|
-
|
|
6
|
-
Licensed under the Apache License, Version 2.0 (the "License").
|
|
7
|
-
You may not use this file except in compliance with the License.
|
|
8
|
-
A copy of the License is located at
|
|
9
|
-
|
|
10
|
-
http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
-
|
|
12
|
-
or in the "license" file accompanying this file. This file is distributed
|
|
13
|
-
on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
|
14
|
-
express or implied. See the License for the specific language governing
|
|
15
|
-
permissions and limitations under the License.
|
|
16
|
-
"""
|
|
17
|
-
|
|
18
|
-
from creatorsapi_python_sdk.auth.oauth2_config import OAuth2Config
|
|
19
|
-
from creatorsapi_python_sdk.auth.oauth2_token_manager import OAuth2TokenManager
|
|
20
|
-
|
|
21
|
-
__all__ = ['OAuth2Config', 'OAuth2TokenManager']
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
5
|
+
|
|
6
|
+
Licensed under the Apache License, Version 2.0 (the "License").
|
|
7
|
+
You may not use this file except in compliance with the License.
|
|
8
|
+
A copy of the License is located at
|
|
9
|
+
|
|
10
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
|
|
12
|
+
or in the "license" file accompanying this file. This file is distributed
|
|
13
|
+
on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
|
14
|
+
express or implied. See the License for the specific language governing
|
|
15
|
+
permissions and limitations under the License.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from creatorsapi_python_sdk.auth.oauth2_config import OAuth2Config
|
|
19
|
+
from creatorsapi_python_sdk.auth.oauth2_token_manager import OAuth2TokenManager
|
|
20
|
+
|
|
21
|
+
__all__ = ['OAuth2Config', 'OAuth2TokenManager']
|
|
@@ -1,123 +1,139 @@
|
|
|
1
|
-
# coding: utf-8
|
|
2
|
-
|
|
3
|
-
"""
|
|
4
|
-
Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
5
|
-
|
|
6
|
-
Licensed under the Apache License, Version 2.0 (the "License").
|
|
7
|
-
You may not use this file except in compliance with the License.
|
|
8
|
-
A copy of the License is located at
|
|
9
|
-
|
|
10
|
-
http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
-
|
|
12
|
-
or in the "license" file accompanying this file. This file is distributed
|
|
13
|
-
on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
|
14
|
-
express or implied. See the License for the specific language governing
|
|
15
|
-
permissions and limitations under the License.
|
|
16
|
-
"""
|
|
17
|
-
|
|
18
|
-
"""
|
|
19
|
-
OAuth2 configuration class that manages version-specific cognito endpoints
|
|
20
|
-
"""
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
class OAuth2Config:
|
|
24
|
-
"""OAuth2 configuration class that manages version-specific cognito endpoints"""
|
|
25
|
-
|
|
26
|
-
# Constants
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
:param
|
|
36
|
-
:param
|
|
37
|
-
:param
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
self.
|
|
41
|
-
self.
|
|
42
|
-
self.
|
|
43
|
-
self.
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
:param
|
|
51
|
-
:
|
|
52
|
-
:
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
""
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
:
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
:
|
|
90
|
-
"""
|
|
91
|
-
return self.
|
|
92
|
-
|
|
93
|
-
def
|
|
94
|
-
"""
|
|
95
|
-
Gets the credential
|
|
96
|
-
|
|
97
|
-
:return: The credential
|
|
98
|
-
"""
|
|
99
|
-
return self.
|
|
100
|
-
|
|
101
|
-
def
|
|
102
|
-
"""
|
|
103
|
-
Gets the
|
|
104
|
-
|
|
105
|
-
:return: The
|
|
106
|
-
"""
|
|
107
|
-
return self.
|
|
108
|
-
|
|
109
|
-
def
|
|
110
|
-
"""
|
|
111
|
-
Gets the
|
|
112
|
-
|
|
113
|
-
:return: The
|
|
114
|
-
"""
|
|
115
|
-
return
|
|
116
|
-
|
|
117
|
-
def
|
|
118
|
-
"""
|
|
119
|
-
Gets the
|
|
120
|
-
|
|
121
|
-
:return: The
|
|
122
|
-
"""
|
|
123
|
-
return
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
5
|
+
|
|
6
|
+
Licensed under the Apache License, Version 2.0 (the "License").
|
|
7
|
+
You may not use this file except in compliance with the License.
|
|
8
|
+
A copy of the License is located at
|
|
9
|
+
|
|
10
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
|
|
12
|
+
or in the "license" file accompanying this file. This file is distributed
|
|
13
|
+
on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
|
14
|
+
express or implied. See the License for the specific language governing
|
|
15
|
+
permissions and limitations under the License.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
"""
|
|
19
|
+
OAuth2 configuration class that manages version-specific cognito endpoints
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class OAuth2Config:
|
|
24
|
+
"""OAuth2 configuration class that manages version-specific cognito endpoints"""
|
|
25
|
+
|
|
26
|
+
# Constants
|
|
27
|
+
COGNITO_SCOPE = "creatorsapi/default"
|
|
28
|
+
LWA_SCOPE = "creatorsapi::default"
|
|
29
|
+
GRANT_TYPE = "client_credentials"
|
|
30
|
+
|
|
31
|
+
def __init__(self, credential_id, credential_secret, version, auth_endpoint):
|
|
32
|
+
"""
|
|
33
|
+
Creates an OAuth2Config instance
|
|
34
|
+
|
|
35
|
+
:param credential_id: The OAuth2 credential Id
|
|
36
|
+
:param credential_secret: The OAuth2 credential secret
|
|
37
|
+
:param version: The credential version (determines the token endpoint)
|
|
38
|
+
:param auth_endpoint: Optional custom auth endpoint URL
|
|
39
|
+
"""
|
|
40
|
+
self.credential_id = credential_id
|
|
41
|
+
self.credential_secret = credential_secret
|
|
42
|
+
self.version = version
|
|
43
|
+
self.auth_endpoint = auth_endpoint
|
|
44
|
+
self.cognito_endpoint = self.determine_token_endpoint(version, auth_endpoint)
|
|
45
|
+
|
|
46
|
+
def determine_token_endpoint(self, version, auth_endpoint):
|
|
47
|
+
"""
|
|
48
|
+
Determines the appropriate OAuth2 token endpoint based on version or custom endpoint
|
|
49
|
+
|
|
50
|
+
:param version: The credential version
|
|
51
|
+
:param auth_endpoint: Optional custom auth endpoint URL
|
|
52
|
+
:return: The OAuth2 token endpoint URL
|
|
53
|
+
:raises ValueError: If the version is not supported and no custom endpoint provided
|
|
54
|
+
"""
|
|
55
|
+
if auth_endpoint and auth_endpoint.strip():
|
|
56
|
+
return auth_endpoint
|
|
57
|
+
|
|
58
|
+
# Cognito endpoints (v2.x)
|
|
59
|
+
if version == "2.1":
|
|
60
|
+
return "https://creatorsapi.auth.us-east-1.amazoncognito.com/oauth2/token"
|
|
61
|
+
elif version == "2.2":
|
|
62
|
+
return "https://creatorsapi.auth.eu-south-2.amazoncognito.com/oauth2/token"
|
|
63
|
+
elif version == "2.3":
|
|
64
|
+
return "https://creatorsapi.auth.us-west-2.amazoncognito.com/oauth2/token"
|
|
65
|
+
# LWA endpoints (v3.x)
|
|
66
|
+
elif version == "3.1":
|
|
67
|
+
return "https://api.amazon.com/auth/o2/token"
|
|
68
|
+
elif version == "3.2":
|
|
69
|
+
return "https://api.amazon.co.uk/auth/o2/token"
|
|
70
|
+
elif version == "3.3":
|
|
71
|
+
return "https://api.amazon.co.jp/auth/o2/token"
|
|
72
|
+
else:
|
|
73
|
+
raise ValueError("Unsupported version: {}. Supported versions are: 2.1, 2.2, 2.3, 3.1, 3.2, 3.3".format(version))
|
|
74
|
+
|
|
75
|
+
def is_lwa(self):
|
|
76
|
+
"""
|
|
77
|
+
Checks if this is an LWA (v3.x) configuration
|
|
78
|
+
|
|
79
|
+
:return: True if using LWA authentication
|
|
80
|
+
"""
|
|
81
|
+
return self.version.startswith("3.")
|
|
82
|
+
|
|
83
|
+
def get_token_endpoint(self, version):
|
|
84
|
+
"""
|
|
85
|
+
Gets the appropriate OAuth2 token endpoint based on the credential version
|
|
86
|
+
|
|
87
|
+
:param version: The credential version
|
|
88
|
+
:return: The OAuth2 token endpoint URL
|
|
89
|
+
:raises ValueError: If the version is not supported
|
|
90
|
+
"""
|
|
91
|
+
return self.determine_token_endpoint(version, None)
|
|
92
|
+
|
|
93
|
+
def get_credential_id(self):
|
|
94
|
+
"""
|
|
95
|
+
Gets the credential Id
|
|
96
|
+
|
|
97
|
+
:return: The credential Id
|
|
98
|
+
"""
|
|
99
|
+
return self.credential_id
|
|
100
|
+
|
|
101
|
+
def get_credential_secret(self):
|
|
102
|
+
"""
|
|
103
|
+
Gets the credential secret
|
|
104
|
+
|
|
105
|
+
:return: The credential secret
|
|
106
|
+
"""
|
|
107
|
+
return self.credential_secret
|
|
108
|
+
|
|
109
|
+
def get_version(self):
|
|
110
|
+
"""
|
|
111
|
+
Gets the credential version
|
|
112
|
+
|
|
113
|
+
:return: The credential version
|
|
114
|
+
"""
|
|
115
|
+
return self.version
|
|
116
|
+
|
|
117
|
+
def get_cognito_endpoint(self):
|
|
118
|
+
"""
|
|
119
|
+
Gets the Cognito token endpoint URL
|
|
120
|
+
|
|
121
|
+
:return: The token endpoint URL
|
|
122
|
+
"""
|
|
123
|
+
return self.cognito_endpoint
|
|
124
|
+
|
|
125
|
+
def get_scope(self):
|
|
126
|
+
"""
|
|
127
|
+
Gets the OAuth2 scope
|
|
128
|
+
|
|
129
|
+
:return: The OAuth2 scope
|
|
130
|
+
"""
|
|
131
|
+
return OAuth2Config.LWA_SCOPE if self.is_lwa() else OAuth2Config.COGNITO_SCOPE
|
|
132
|
+
|
|
133
|
+
def get_grant_type(self):
|
|
134
|
+
"""
|
|
135
|
+
Gets the OAuth2 grant type
|
|
136
|
+
|
|
137
|
+
:return: The OAuth2 grant type
|
|
138
|
+
"""
|
|
139
|
+
return OAuth2Config.GRANT_TYPE
|
|
@@ -1,120 +1,133 @@
|
|
|
1
|
-
# coding: utf-8
|
|
2
|
-
|
|
3
|
-
"""
|
|
4
|
-
Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
5
|
-
|
|
6
|
-
Licensed under the Apache License, Version 2.0 (the "License").
|
|
7
|
-
You may not use this file except in compliance with the License.
|
|
8
|
-
A copy of the License is located at
|
|
9
|
-
|
|
10
|
-
http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
-
|
|
12
|
-
or in the "license" file accompanying this file. This file is distributed
|
|
13
|
-
on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
|
14
|
-
express or implied. See the License for the specific language governing
|
|
15
|
-
permissions and limitations under the License.
|
|
16
|
-
"""
|
|
17
|
-
|
|
18
|
-
"""
|
|
19
|
-
OAuth2 Token Manager for handling token refresh and caching.
|
|
20
|
-
|
|
21
|
-
Note: ApiClient automatically manages token caching for optimal performance.
|
|
22
|
-
Direct instantiation is only needed for advanced use cases.
|
|
23
|
-
"""
|
|
24
|
-
|
|
25
|
-
import requests
|
|
26
|
-
import time
|
|
27
|
-
import json
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
class OAuth2TokenManager:
|
|
31
|
-
"""Manages OAuth2 token lifecycle including acquisition, caching, and automatic refresh"""
|
|
32
|
-
|
|
33
|
-
def __init__(self, config):
|
|
34
|
-
"""
|
|
35
|
-
Creates an OAuth2TokenManager instance
|
|
36
|
-
|
|
37
|
-
:param config: The OAuth2Config instance
|
|
38
|
-
"""
|
|
39
|
-
self.config = config
|
|
40
|
-
self.access_token = None
|
|
41
|
-
self.expires_at = None
|
|
42
|
-
|
|
43
|
-
def get_token(self):
|
|
44
|
-
"""
|
|
45
|
-
Gets a valid OAuth2 access token, refreshing if necessary
|
|
46
|
-
|
|
47
|
-
:return: A valid access token
|
|
48
|
-
:raises Exception: If token acquisition fails
|
|
49
|
-
"""
|
|
50
|
-
if self.is_token_valid():
|
|
51
|
-
return self.access_token
|
|
52
|
-
return self.refresh_token()
|
|
53
|
-
|
|
54
|
-
def is_token_valid(self):
|
|
55
|
-
"""
|
|
56
|
-
Checks if the current token is valid and not expired
|
|
57
|
-
|
|
58
|
-
:return: True if the token is valid, false otherwise
|
|
59
|
-
"""
|
|
60
|
-
return self.access_token and self.expires_at and time.time() < self.expires_at
|
|
61
|
-
|
|
62
|
-
def refresh_token(self):
|
|
63
|
-
"""
|
|
64
|
-
Refreshes the OAuth2 access token using client credentials grant
|
|
65
|
-
|
|
66
|
-
:return: The new access token
|
|
67
|
-
:raises Exception: If token refresh fails
|
|
68
|
-
"""
|
|
69
|
-
try:
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
'Content-Type': 'application/
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
5
|
+
|
|
6
|
+
Licensed under the Apache License, Version 2.0 (the "License").
|
|
7
|
+
You may not use this file except in compliance with the License.
|
|
8
|
+
A copy of the License is located at
|
|
9
|
+
|
|
10
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
|
|
12
|
+
or in the "license" file accompanying this file. This file is distributed
|
|
13
|
+
on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
|
14
|
+
express or implied. See the License for the specific language governing
|
|
15
|
+
permissions and limitations under the License.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
"""
|
|
19
|
+
OAuth2 Token Manager for handling token refresh and caching.
|
|
20
|
+
|
|
21
|
+
Note: ApiClient automatically manages token caching for optimal performance.
|
|
22
|
+
Direct instantiation is only needed for advanced use cases.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
import requests
|
|
26
|
+
import time
|
|
27
|
+
import json
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class OAuth2TokenManager:
|
|
31
|
+
"""Manages OAuth2 token lifecycle including acquisition, caching, and automatic refresh"""
|
|
32
|
+
|
|
33
|
+
def __init__(self, config):
|
|
34
|
+
"""
|
|
35
|
+
Creates an OAuth2TokenManager instance
|
|
36
|
+
|
|
37
|
+
:param config: The OAuth2Config instance
|
|
38
|
+
"""
|
|
39
|
+
self.config = config
|
|
40
|
+
self.access_token = None
|
|
41
|
+
self.expires_at = None
|
|
42
|
+
|
|
43
|
+
def get_token(self):
|
|
44
|
+
"""
|
|
45
|
+
Gets a valid OAuth2 access token, refreshing if necessary
|
|
46
|
+
|
|
47
|
+
:return: A valid access token
|
|
48
|
+
:raises Exception: If token acquisition fails
|
|
49
|
+
"""
|
|
50
|
+
if self.is_token_valid():
|
|
51
|
+
return self.access_token
|
|
52
|
+
return self.refresh_token()
|
|
53
|
+
|
|
54
|
+
def is_token_valid(self):
|
|
55
|
+
"""
|
|
56
|
+
Checks if the current token is valid and not expired
|
|
57
|
+
|
|
58
|
+
:return: True if the token is valid, false otherwise
|
|
59
|
+
"""
|
|
60
|
+
return self.access_token and self.expires_at and time.time() < self.expires_at
|
|
61
|
+
|
|
62
|
+
def refresh_token(self):
|
|
63
|
+
"""
|
|
64
|
+
Refreshes the OAuth2 access token using client credentials grant
|
|
65
|
+
|
|
66
|
+
:return: The new access token
|
|
67
|
+
:raises Exception: If token refresh fails
|
|
68
|
+
"""
|
|
69
|
+
try:
|
|
70
|
+
if self.config.is_lwa():
|
|
71
|
+
# LWA (v3.x) uses JSON body
|
|
72
|
+
request_data = {
|
|
73
|
+
'grant_type': self.config.get_grant_type(),
|
|
74
|
+
'client_id': self.config.get_credential_id(),
|
|
75
|
+
'client_secret': self.config.get_credential_secret(),
|
|
76
|
+
'scope': self.config.get_scope()
|
|
77
|
+
}
|
|
78
|
+
headers = {'Content-Type': 'application/json'}
|
|
79
|
+
response = requests.post(
|
|
80
|
+
self.config.get_cognito_endpoint(),
|
|
81
|
+
json=request_data,
|
|
82
|
+
headers=headers
|
|
83
|
+
)
|
|
84
|
+
else:
|
|
85
|
+
# Cognito (v2.x) uses form-encoded
|
|
86
|
+
request_data = {
|
|
87
|
+
'grant_type': self.config.get_grant_type(),
|
|
88
|
+
'client_id': self.config.get_credential_id(),
|
|
89
|
+
'client_secret': self.config.get_credential_secret(),
|
|
90
|
+
'scope': self.config.get_scope()
|
|
91
|
+
}
|
|
92
|
+
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
|
|
93
|
+
response = requests.post(
|
|
94
|
+
self.config.get_cognito_endpoint(),
|
|
95
|
+
data=request_data,
|
|
96
|
+
headers=headers
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
if response.status_code != 200:
|
|
100
|
+
raise Exception("OAuth2 token request failed with status {}: {}".format(response.status_code, response.text))
|
|
101
|
+
|
|
102
|
+
data = response.json()
|
|
103
|
+
|
|
104
|
+
if 'access_token' not in data:
|
|
105
|
+
raise Exception('No access token received from OAuth2 endpoint')
|
|
106
|
+
|
|
107
|
+
self.access_token = data['access_token']
|
|
108
|
+
# Set expiration time with a 30-second buffer to avoid edge cases
|
|
109
|
+
expires_in = data.get('expires_in', 3600) # Default to 1 hour if not provided
|
|
110
|
+
expires_in_with_buffer = expires_in - 30
|
|
111
|
+
self.expires_at = time.time() + expires_in_with_buffer
|
|
112
|
+
|
|
113
|
+
return self.access_token
|
|
114
|
+
|
|
115
|
+
except requests.exceptions.RequestException as e:
|
|
116
|
+
# Clear existing token on failure
|
|
117
|
+
self.clear_token()
|
|
118
|
+
raise Exception("OAuth2 token request failed: {}".format(str(e)))
|
|
119
|
+
except json.JSONDecodeError as e:
|
|
120
|
+
# Clear existing token on failure
|
|
121
|
+
self.clear_token()
|
|
122
|
+
raise Exception("Failed to parse OAuth2 token response: {}".format(str(e)))
|
|
123
|
+
except Exception as e:
|
|
124
|
+
# Clear existing token on failure
|
|
125
|
+
self.clear_token()
|
|
126
|
+
raise e
|
|
127
|
+
|
|
128
|
+
def clear_token(self):
|
|
129
|
+
"""
|
|
130
|
+
Clears the cached token, forcing a refresh on the next get_token() call
|
|
131
|
+
"""
|
|
132
|
+
self.access_token = None
|
|
133
|
+
self.expires_at = None
|