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.
Files changed (109) hide show
  1. {amazon_creatorsapi_python_sdk-1.0.0.dist-info → amazon_creatorsapi_python_sdk-1.2.0.dist-info}/METADATA +11 -5
  2. amazon_creatorsapi_python_sdk-1.2.0.dist-info/RECORD +109 -0
  3. {amazon_creatorsapi_python_sdk-1.0.0.dist-info → amazon_creatorsapi_python_sdk-1.2.0.dist-info}/WHEEL +1 -1
  4. creatorsapi_python_sdk/__init__.py +128 -127
  5. creatorsapi_python_sdk/api/__init__.py +5 -5
  6. creatorsapi_python_sdk/api/default_api.py +2427 -2412
  7. creatorsapi_python_sdk/api_client.py +915 -912
  8. creatorsapi_python_sdk/api_response.py +21 -21
  9. creatorsapi_python_sdk/auth/__init__.py +21 -21
  10. creatorsapi_python_sdk/auth/oauth2_config.py +139 -123
  11. creatorsapi_python_sdk/auth/oauth2_token_manager.py +133 -120
  12. creatorsapi_python_sdk/configuration.py +455 -455
  13. creatorsapi_python_sdk/exceptions.py +204 -204
  14. creatorsapi_python_sdk/models/__init__.py +111 -110
  15. creatorsapi_python_sdk/models/access_denied_exception_response_content.py +97 -97
  16. creatorsapi_python_sdk/models/access_denied_reason.py +45 -45
  17. creatorsapi_python_sdk/models/availability.py +44 -44
  18. creatorsapi_python_sdk/models/browse_node.py +116 -116
  19. creatorsapi_python_sdk/models/browse_node_ancestor.py +103 -103
  20. creatorsapi_python_sdk/models/browse_node_child.py +96 -96
  21. creatorsapi_python_sdk/models/browse_node_info.py +106 -106
  22. creatorsapi_python_sdk/models/browse_nodes_result.py +100 -100
  23. creatorsapi_python_sdk/models/by_line_info.py +111 -111
  24. creatorsapi_python_sdk/models/classifications.py +101 -101
  25. creatorsapi_python_sdk/models/condition.py +44 -44
  26. creatorsapi_python_sdk/models/content_info.py +113 -113
  27. creatorsapi_python_sdk/models/content_rating.py +96 -96
  28. creatorsapi_python_sdk/models/contributor.py +98 -98
  29. creatorsapi_python_sdk/models/customer_reviews.py +98 -98
  30. creatorsapi_python_sdk/models/deal_details.py +102 -102
  31. creatorsapi_python_sdk/models/delivery_flag.py +46 -46
  32. creatorsapi_python_sdk/models/dimension_based_attribute.py +111 -111
  33. creatorsapi_python_sdk/models/error_data.py +94 -94
  34. creatorsapi_python_sdk/models/external_ids.py +106 -106
  35. creatorsapi_python_sdk/models/feed.py +98 -98
  36. creatorsapi_python_sdk/models/get_browse_nodes_request_content.py +107 -107
  37. creatorsapi_python_sdk/models/get_browse_nodes_resource.py +44 -44
  38. creatorsapi_python_sdk/models/get_browse_nodes_response_content.py +106 -106
  39. creatorsapi_python_sdk/models/get_feed_request_content.py +93 -93
  40. creatorsapi_python_sdk/models/get_feed_response_content.py +92 -92
  41. creatorsapi_python_sdk/models/get_items_request_content.py +124 -124
  42. creatorsapi_python_sdk/models/get_items_resource.py +76 -76
  43. creatorsapi_python_sdk/models/get_items_response_content.py +106 -106
  44. creatorsapi_python_sdk/models/get_report_request_content.py +93 -93
  45. creatorsapi_python_sdk/models/get_report_response_content.py +92 -92
  46. creatorsapi_python_sdk/models/get_variations_request_content.py +135 -135
  47. creatorsapi_python_sdk/models/get_variations_resource.py +79 -79
  48. creatorsapi_python_sdk/models/get_variations_response_content.py +106 -106
  49. creatorsapi_python_sdk/models/image_size.py +96 -96
  50. creatorsapi_python_sdk/models/image_type.py +111 -111
  51. creatorsapi_python_sdk/models/images.py +105 -105
  52. creatorsapi_python_sdk/models/internal_server_exception_response_content.py +94 -94
  53. creatorsapi_python_sdk/models/item.py +138 -138
  54. creatorsapi_python_sdk/models/item_info.py +156 -156
  55. creatorsapi_python_sdk/models/items_result.py +100 -100
  56. creatorsapi_python_sdk/models/language_type.py +94 -94
  57. creatorsapi_python_sdk/models/languages.py +104 -104
  58. creatorsapi_python_sdk/models/list_feeds_response_content.py +100 -100
  59. creatorsapi_python_sdk/models/list_reports_response_content.py +100 -100
  60. creatorsapi_python_sdk/models/manufacture_info.py +106 -106
  61. creatorsapi_python_sdk/models/money.py +96 -96
  62. creatorsapi_python_sdk/models/multi_valued_attribute.py +96 -96
  63. creatorsapi_python_sdk/models/offer_availability_v2.py +98 -98
  64. creatorsapi_python_sdk/models/offer_condition_v2.py +96 -96
  65. creatorsapi_python_sdk/models/offer_listing_v2.py +133 -133
  66. creatorsapi_python_sdk/models/offer_loyalty_points_v2.py +92 -92
  67. creatorsapi_python_sdk/models/offer_merchant_info_v2.py +94 -94
  68. creatorsapi_python_sdk/models/offer_price_v2.py +113 -113
  69. creatorsapi_python_sdk/models/offer_saving_basis.py +101 -101
  70. creatorsapi_python_sdk/models/offer_savings.py +98 -98
  71. creatorsapi_python_sdk/models/offer_type.py +45 -45
  72. creatorsapi_python_sdk/models/offers_v2.py +100 -100
  73. creatorsapi_python_sdk/models/product_info.py +124 -124
  74. creatorsapi_python_sdk/models/rating.py +92 -92
  75. creatorsapi_python_sdk/models/refinement.py +104 -104
  76. creatorsapi_python_sdk/models/refinement_bin.py +94 -94
  77. creatorsapi_python_sdk/models/report_metadata.py +98 -98
  78. creatorsapi_python_sdk/models/resource_not_found_exception_response_content.py +98 -98
  79. creatorsapi_python_sdk/models/saving_basis_type.py +46 -46
  80. creatorsapi_python_sdk/models/search_items_request_content.py +242 -242
  81. creatorsapi_python_sdk/models/search_items_resource.py +77 -77
  82. creatorsapi_python_sdk/models/search_items_response_content.py +106 -106
  83. creatorsapi_python_sdk/models/search_refinements.py +110 -110
  84. creatorsapi_python_sdk/models/search_result.py +110 -110
  85. creatorsapi_python_sdk/models/single_boolean_valued_attribute.py +96 -96
  86. creatorsapi_python_sdk/models/single_integer_valued_attribute.py +96 -96
  87. creatorsapi_python_sdk/models/single_string_valued_attribute.py +96 -96
  88. creatorsapi_python_sdk/models/sort_by.py +48 -48
  89. creatorsapi_python_sdk/models/technical_info.py +102 -102
  90. creatorsapi_python_sdk/models/throttle_exception_response_content.py +98 -98
  91. creatorsapi_python_sdk/models/trade_in_info.py +98 -98
  92. creatorsapi_python_sdk/models/trade_in_price.py +96 -96
  93. creatorsapi_python_sdk/models/unauthorized_exception_reason.py +51 -51
  94. creatorsapi_python_sdk/models/unauthorized_exception_response_content.py +97 -97
  95. creatorsapi_python_sdk/models/unit_based_attribute.py +98 -98
  96. creatorsapi_python_sdk/models/validation_exception_field.py +94 -94
  97. creatorsapi_python_sdk/models/validation_exception_reason.py +48 -48
  98. creatorsapi_python_sdk/models/validation_exception_response_content.py +107 -107
  99. creatorsapi_python_sdk/models/variation_attribute.py +94 -94
  100. creatorsapi_python_sdk/models/variation_dimension.py +98 -98
  101. creatorsapi_python_sdk/models/variation_summary.py +110 -104
  102. creatorsapi_python_sdk/models/variation_summary_price.py +101 -0
  103. creatorsapi_python_sdk/models/variations_result.py +106 -106
  104. creatorsapi_python_sdk/models/website_sales_rank.py +98 -98
  105. creatorsapi_python_sdk/rest.py +262 -262
  106. amazon_creatorsapi_python_sdk-1.0.0.dist-info/RECORD +0 -108
  107. {amazon_creatorsapi_python_sdk-1.0.0.dist-info → amazon_creatorsapi_python_sdk-1.2.0.dist-info}/licenses/LICENSE.txt +0 -0
  108. {amazon_creatorsapi_python_sdk-1.0.0.dist-info → amazon_creatorsapi_python_sdk-1.2.0.dist-info}/licenses/NOTICE.txt +0 -0
  109. {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
- SCOPE = "creatorsapi/default"
28
- GRANT_TYPE = "client_credentials"
29
-
30
- def __init__(self, credential_id, credential_secret, version, auth_endpoint):
31
- """
32
- Creates an OAuth2Config instance
33
-
34
- :param credential_id: The OAuth2 credential Id
35
- :param credential_secret: The OAuth2 credential secret
36
- :param version: The credential version (determines the token endpoint)
37
- :param auth_endpoint: Optional custom auth endpoint URL
38
- """
39
- self.credential_id = credential_id
40
- self.credential_secret = credential_secret
41
- self.version = version
42
- self.auth_endpoint = auth_endpoint
43
- self.cognito_endpoint = self.determine_token_endpoint(version, auth_endpoint)
44
-
45
- def determine_token_endpoint(self, version, auth_endpoint):
46
- """
47
- Determines the appropriate OAuth2 token endpoint based on version or custom endpoint
48
-
49
- :param version: The credential version
50
- :param auth_endpoint: Optional custom auth endpoint URL
51
- :return: The OAuth2 token endpoint URL
52
- :raises ValueError: If the version is not supported and no custom endpoint provided
53
- """
54
- if auth_endpoint and auth_endpoint.strip():
55
- return auth_endpoint
56
-
57
- # Fall back to version-based defaults
58
- if version == "2.1":
59
- return "https://creatorsapi.auth.us-east-1.amazoncognito.com/oauth2/token"
60
- elif version == "2.2":
61
- return "https://creatorsapi.auth.eu-south-2.amazoncognito.com/oauth2/token"
62
- elif version == "2.3":
63
- return "https://creatorsapi.auth.us-west-2.amazoncognito.com/oauth2/token"
64
- else:
65
- raise ValueError("Unsupported version: {}. Supported versions are: 2.1, 2.2, 2.3".format(version))
66
-
67
- def get_token_endpoint(self, version):
68
- """
69
- Gets the appropriate OAuth2 token endpoint based on the credential version
70
-
71
- :param version: The credential version
72
- :return: The OAuth2 token endpoint URL
73
- :raises ValueError: If the version is not supported
74
- """
75
- return self.determine_token_endpoint(version, None)
76
-
77
- def get_credential_id(self):
78
- """
79
- Gets the credential Id
80
-
81
- :return: The credential Id
82
- """
83
- return self.credential_id
84
-
85
- def get_credential_secret(self):
86
- """
87
- Gets the credential secret
88
-
89
- :return: The credential secret
90
- """
91
- return self.credential_secret
92
-
93
- def get_version(self):
94
- """
95
- Gets the credential version
96
-
97
- :return: The credential version
98
- """
99
- return self.version
100
-
101
- def get_cognito_endpoint(self):
102
- """
103
- Gets the Cognito token endpoint URL
104
-
105
- :return: The token endpoint URL
106
- """
107
- return self.cognito_endpoint
108
-
109
- def get_scope(self):
110
- """
111
- Gets the OAuth2 scope
112
-
113
- :return: The OAuth2 scope
114
- """
115
- return OAuth2Config.SCOPE
116
-
117
- def get_grant_type(self):
118
- """
119
- Gets the OAuth2 grant type
120
-
121
- :return: The OAuth2 grant type
122
- """
123
- return OAuth2Config.GRANT_TYPE
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
- request_data = {
71
- 'grant_type': self.config.get_grant_type(),
72
- 'client_id': self.config.get_credential_id(),
73
- 'client_secret': self.config.get_credential_secret(),
74
- 'scope': self.config.get_scope()
75
- }
76
-
77
- headers = {
78
- 'Content-Type': 'application/x-www-form-urlencoded'
79
- }
80
-
81
- response = requests.post(
82
- self.config.get_cognito_endpoint(),
83
- data=request_data,
84
- headers=headers
85
- )
86
- if response.status_code != 200:
87
- raise Exception("OAuth2 token request failed with status {}: {}".format(response.status_code, response.text))
88
-
89
- data = response.json()
90
-
91
- if 'access_token' not in data:
92
- raise Exception('No access token received from OAuth2 endpoint')
93
-
94
- self.access_token = data['access_token']
95
- # Set expiration time with a 30-second buffer to avoid edge cases
96
- expires_in = data.get('expires_in', 3600) # Default to 1 hour if not provided
97
- expires_in_with_buffer = expires_in - 30
98
- self.expires_at = time.time() + expires_in_with_buffer
99
-
100
- return self.access_token
101
-
102
- except requests.exceptions.RequestException as e:
103
- # Clear existing token on failure
104
- self.clear_token()
105
- raise Exception("OAuth2 token request failed: {}".format(str(e)))
106
- except json.JSONDecodeError as e:
107
- # Clear existing token on failure
108
- self.clear_token()
109
- raise Exception("Failed to parse OAuth2 token response: {}".format(str(e)))
110
- except Exception as e:
111
- # Clear existing token on failure
112
- self.clear_token()
113
- raise e
114
-
115
- def clear_token(self):
116
- """
117
- Clears the cached token, forcing a refresh on the next get_token() call
118
- """
119
- self.access_token = None
120
- self.expires_at = None
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