@@ -173,39 +173,76 @@ def request_tokens(self) -> bool:
173
173
except (KeyError , TypeError ) as err :
174
174
_LOGGER .debug (f"Error obtaining tokens from ecobee: { err } " )
175
175
return False
176
-
176
+
177
177
def request_tokens_web (self ) -> bool :
178
- assert self .auth0_token is not None , "auth0 token must be set before calling request_tokens_web"
178
+ # Keep all cookies in a session
179
+ session = requests .Session ()
179
180
180
- resp = requests .get (ECOBEE_AUTH_BASE_URL + "/" + ECOBEE_ENDPOINT_AUTH , cookies = {"auth0" : self .auth0_token }, params = {
181
- "client_id" : ECOBEE_WEB_CLIENT_ID ,
182
- "scope" : "smartWrite" ,
183
- "response_type" : "token" ,
184
- "response_mode" : "form_post" ,
185
- "redirect_uri" : "https://www.ecobee.com/home/authCallback" ,
186
- "audience" : "https://prod.ecobee.com/api/v1" ,
187
- }, timeout = ECOBEE_DEFAULT_TIMEOUT )
181
+ # Get the auth0 token and redirect to the identifier step of the login flow
182
+ auth0_url = f"{ ECOBEE_AUTH_BASE_URL } /{ ECOBEE_ENDPOINT_AUTH } "
183
+ resp = session .get (
184
+ auth0_url ,
185
+ params = {
186
+ "response_type" : "token" ,
187
+ "response_mode" : "form_post" ,
188
+ "client_id" : ECOBEE_WEB_CLIENT_ID ,
189
+ "redirect_uri" : "https://www.ecobee.com/home/authCallback" ,
190
+ "audience" : "https://prod.ecobee.com/api/v1" ,
191
+ "scope" : "openid smartWrite piiWrite piiRead smartRead deleteGrants" ,
192
+ },
193
+ )
194
+ if "auth0" not in session .cookies :
195
+ _LOGGER .error (
196
+ f"Failed to obtain auth0 token from { auth0_url } : { resp .status_code } { resp .text } "
197
+ )
198
+ return False
199
+ else :
200
+ self .auth0_token = session .cookies ["auth0" ]
188
201
202
+ # Submit the identifier/username and redirect to the password step
203
+ identifier_url = resp .url
204
+ resp = session .post (
205
+ identifier_url ,
206
+ data = {
207
+ "username" : self .username ,
208
+ },
209
+ )
189
210
if resp .status_code != 200 :
190
- _LOGGER .error (f"Failed to refresh access token: { resp .status_code } { resp .text } " )
211
+ _LOGGER .error (f"Failed to submit username: { resp .status_code } { resp .text } " )
212
+ return False
213
+
214
+ # Submit the password and get the access_token
215
+ password_url = resp .url
216
+ resp = session .post (
217
+ password_url ,
218
+ data = {
219
+ "username" : self .username ,
220
+ "password" : self .password ,
221
+ },
222
+ )
223
+ if resp .status_code != 200 :
224
+ _LOGGER .error (f"Failed to submit password: { resp .status_code } { resp .text } " )
191
225
return False
192
-
193
- if (auth0 := resp .cookies .get ("auth0" )) is None :
194
- _LOGGER .error ("Failed to refresh access token: no auth0 cookie in response" )
195
- self .auth0_token = auth0
196
226
197
- # Parse the response HTML for the access token and expiration
198
- if (access_token := resp .text .split ('name="access_token" value="' )[1 ].split ('"' )[0 ]) is None :
227
+ if (
228
+ access_token := resp .text .split ('name="access_token" value="' )[1 ].split (
229
+ '"'
230
+ )[0 ]
231
+ ) is None :
199
232
_LOGGER .error ("Failed to refresh bearer token: no access token in response" )
200
233
return False
201
-
234
+
202
235
self .access_token = access_token
203
236
204
- if (expires_in := resp .text .split ('name="expires_in" value="' )[1 ].split ('"' )[0 ]) is None :
237
+ if (
238
+ expires_in := resp .text .split ('name="expires_in" value="' )[1 ].split ('"' )[0 ]
239
+ ) is None :
205
240
_LOGGER .error ("Failed to refresh bearer token: no expiration in response" )
206
241
return False
207
242
208
- expires_at = datetime .datetime .now () + datetime .timedelta (seconds = int (expires_in ))
243
+ expires_at = datetime .datetime .now () + datetime .timedelta (
244
+ seconds = int (expires_in )
245
+ )
209
246
_LOGGER .debug (f"Access token expires at { expires_at } " )
210
247
211
248
self ._write_config ()
@@ -214,9 +251,6 @@ def request_tokens_web(self) -> bool:
214
251
215
252
def refresh_tokens (self ) -> bool :
216
253
if self .username and self .password :
217
- self .request_auth0_token ()
218
-
219
- if self .auth0_token is not None :
220
254
return self .request_tokens_web ()
221
255
222
256
"""Refreshes ecobee API tokens."""
@@ -246,46 +280,6 @@ def refresh_tokens(self) -> bool:
246
280
_LOGGER .debug (f"Error refreshing tokens from ecobee: { err } " )
247
281
return False
248
282
249
- def request_auth0_token (self ) -> bool :
250
- """Get the auth0 token via username/password."""
251
- session = requests .Session ()
252
- url = f"{ ECOBEE_AUTH_BASE_URL } /{ ECOBEE_ENDPOINT_AUTH } "
253
- resp = session .get (
254
- url ,
255
- params = {
256
- "response_type" : "token" ,
257
- "response_mode" : "form_post" ,
258
- "client_id" : ECOBEE_WEB_CLIENT_ID ,
259
- "redirect_uri" : "https://www.ecobee.com/home/authCallback" ,
260
- "audience" : "https://prod.ecobee.com/api/v1" ,
261
- "scope" : "openid smartWrite piiWrite piiRead smartRead deleteGrants" ,
262
- }
263
- )
264
- if resp .status_code != 200 :
265
- _LOGGER .error (f"Failed to obtain auth0 token from { url } : { resp .status_code } { resp .text } " )
266
- return False
267
-
268
- redirect_url = resp .url
269
- resp = session .post (
270
- redirect_url ,
271
- data = {
272
- "username" : self .username ,
273
- "password" : self .password ,
274
- "action" : "default"
275
- }
276
- )
277
- if resp .status_code != 200 :
278
- _LOGGER .error (f"Failed to obtain auth0 token from { redirect_url } : { resp .status_code } { resp .text } " )
279
- return False
280
- if (auth0 := resp .cookies .get ("auth0" )) is None :
281
- _LOGGER .error (f"Failed to obtain auth0 token from { redirect_url } : no auth0 cookie in response" )
282
- self .auth0_token = None
283
- return False
284
-
285
- _LOGGER .debug (f"Obtained auth0 token: { auth0 } " )
286
- self .auth0_token = auth0
287
- return True
288
-
289
283
def get_thermostats (self ) -> bool :
290
284
"""Gets a json-list of thermostats from ecobee and caches in self.thermostats."""
291
285
param_string = {
0 commit comments