@@ -121,6 +121,10 @@ async def _post_login(self, data: Mapping[str, Any]) -> None:
121121 f"Login failed for { self .server .name } : { response .status } "
122122 )
123123
124+ # A 204 No Content response cannot have a body, so skip JSON parsing.
125+ if response .status == 204 :
126+ return
127+
124128 result = await response .json ()
125129 if not result .get ("success" ):
126130 raise BadCredentialsException ("Login failed: bad credentials" )
@@ -200,9 +204,9 @@ async def _request_access_token(
200204 self .context .refresh_token = token .get ("refresh_token" )
201205 expires_in = token .get ("expires_in" )
202206 if expires_in :
203- self .context .expires_at = datetime .datetime .now () + datetime . timedelta (
204- seconds = cast ( int , expires_in ) - 5
205- )
207+ self .context .expires_at = datetime .datetime .now (
208+ datetime . UTC
209+ ) + datetime . timedelta ( seconds = cast ( int , expires_in ) - 5 )
206210
207211
208212class CozytouchAuthStrategy (SessionLoginStrategy ):
@@ -394,6 +398,18 @@ async def _exchange_token(self, payload: Mapping[str, str]) -> None:
394398 ) as response :
395399 token = await response .json ()
396400
401+ # Handle OAuth error responses explicitly before accessing the access token.
402+ error = token .get ("error" )
403+ if error :
404+ description = token .get ("error_description" ) or token .get ("message" )
405+ if description :
406+ raise InvalidTokenException (
407+ f"Error retrieving Rexel access token: { description } "
408+ )
409+ raise InvalidTokenException (
410+ f"Error retrieving Rexel access token: { error } "
411+ )
412+
397413 access_token = token .get ("access_token" )
398414 if not access_token :
399415 raise InvalidTokenException ("No Rexel access token provided." )
@@ -403,9 +419,9 @@ async def _exchange_token(self, payload: Mapping[str, str]) -> None:
403419 self .context .refresh_token = token .get ("refresh_token" )
404420 expires_in = token .get ("expires_in" )
405421 if expires_in :
406- self .context .expires_at = datetime .datetime .now () + datetime . timedelta (
407- seconds = cast ( int , expires_in ) - 5
408- )
422+ self .context .expires_at = datetime .datetime .now (
423+ datetime . UTC
424+ ) + datetime . timedelta ( seconds = cast ( int , expires_in ) - 5 )
409425
410426 @staticmethod
411427 def _ensure_consent (access_token : str ) -> None :
0 commit comments