stackit-core 0.3.0__tar.gz → 0.3.1__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.
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: stackit-core
3
- Version: 0.3.0
3
+ Version: v0.3.1
4
4
  Summary: Core functionality for the STACKIT SDK for Python
5
5
  Project-URL: Homepage, https://github.com/stackitcloud/stackit-sdk-python
6
6
  Project-URL: Issues, https://github.com/stackitcloud/stackit-sdk-python/issues
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "stackit-core"
3
- version = "v0.3.0"
3
+ version = "v0.3.1"
4
4
  description = "Core functionality for the STACKIT SDK for Python"
5
5
  authors = [{ name = "STACKIT Developer Tools", email = "developer-tools@stackit.cloud" }]
6
6
  requires-python = ">=3.10,<4.0"
@@ -79,6 +79,16 @@ class KeyAuth(AuthBase):
79
79
  if self.__is_token_expired(self.access_token):
80
80
  if self.refresh_future is None or self.refresh_future.done():
81
81
  self.refresh_future = self.executor.submit(self.__refresh_token)
82
+ refresh_future = self.refresh_future
83
+ else:
84
+ refresh_future = None
85
+
86
+ # Do not hold the lock while waiting. The refresh worker acquires it when
87
+ # updating the access token.
88
+ if refresh_future is not None:
89
+ refresh_future.result()
90
+
91
+ with self.lock:
82
92
  r.headers["Authorization"] = f"Bearer {self.access_token}"
83
93
  return r
84
94
 
@@ -108,8 +118,9 @@ class KeyAuth(AuthBase):
108
118
  response = requests.post(self.token_endpoint, data=body, timeout=self.timeout)
109
119
  response.raise_for_status()
110
120
  response_json = response.json()
111
- self.access_token = response_json["access_token"]
112
- self.refresh_token = response_json["refresh_token"]
121
+ with self.lock:
122
+ self.access_token = response_json["access_token"]
123
+ self.refresh_token = response_json["refresh_token"]
113
124
  except requests.RequestException as e:
114
125
  raise requests.RequestException("Initial token fetch failed") from e
115
126
 
@@ -130,14 +141,17 @@ class KeyAuth(AuthBase):
130
141
  thread.start()
131
142
 
132
143
  def __refresh_token(self):
133
- if self.__is_token_expired(self.refresh_token):
144
+ with self.lock:
145
+ refresh_token = self.refresh_token
146
+
147
+ if self.__is_token_expired(refresh_token):
134
148
  self.__create_initial_token()
135
149
  self.__fetch_token_from_endpoint()
136
150
  return
137
151
 
138
152
  body = {
139
153
  "grant_type": "refresh_token",
140
- "refresh_token": self.refresh_token,
154
+ "refresh_token": refresh_token,
141
155
  }
142
156
 
143
157
  last_exception = None
@@ -147,24 +161,23 @@ class KeyAuth(AuthBase):
147
161
  response.raise_for_status()
148
162
  response_data = response.json()
149
163
  new_token = response_data.get("access_token")
150
- self.access_token = new_token
164
+ with self.lock:
165
+ self.access_token = new_token
151
166
  return
152
167
  except requests.RequestException as e:
153
168
  last_exception = e
154
169
 
155
170
  raise requests.RequestException("Token refresh failed after retries") from last_exception
156
171
 
157
- def __is_token_expired(self, token: str) -> bool:
172
+ def __is_token_expired(self, token: Optional[str]) -> bool:
158
173
  try:
159
174
  decoded_token = jwt.decode(token, options={"verify_signature": False})
160
175
  exp = decoded_token.get("exp")
161
- if exp:
162
- return time.time() > (exp + self.EXPIRATION_LEEWAY.total_seconds())
163
- except jwt.ExpiredSignatureError:
164
- return True
165
- except jwt.DecodeError:
176
+ if exp is None:
177
+ return True
178
+ return time.time() > (float(exp) - self.EXPIRATION_LEEWAY.total_seconds())
179
+ except (jwt.InvalidTokenError, TypeError, ValueError):
166
180
  return True
167
- return False
168
181
 
169
182
  def __shutdown(self):
170
183
  self.executor.shutdown(wait=False)
File without changes
File without changes
File without changes
File without changes