Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ClientAuth stopped working after Netatmo discontinued the /oauth2/token API #435

Open
Lock128 opened this issue Jul 13, 2023 · 4 comments
Open

Comments

@Lock128
Copy link

Lock128 commented Jul 13, 2023

Hey

It looks like the /oauth2/token API was finally deprecated...and because of that the things described in usage.md dont work anymore
see marker here:
https://dev.netatmo.com/apidocumentation/oauth#client-credential

error message:

DEBUG:requests_oauthlib.oauth2_session:Encoding `client_id` "5ef5c45497729b1a4d7fe0c3" with `client_secret` as Basic auth credentials.
DEBUG:requests_oauthlib.oauth2_session:Requesting url https://api.netatmo.com/oauth2/token using method POST.
DEBUG:requests_oauthlib.oauth2_session:Supplying headers {'Accept': 'application/json', 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'} and data {'grant_type': 'password', 'username': 'user, 'password': 'password', 'scope': 'read_station'}
DEBUG:requests_oauthlib.oauth2_session:Passing through key word arguments {'timeout': None, 'auth': <requests.auth.HTTPBasicAuth object at 0xb59efa50>, 'verify': True, 'proxies': None}.
DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): api.netatmo.com:443
DEBUG:urllib3.connectionpool:https://api.netatmo.com:443 "POST /oauth2/token HTTP/1.1" 400 None
DEBUG:requests_oauthlib.oauth2_session:Request to fetch token completed with status 400.
DEBUG:requests_oauthlib.oauth2_session:Request url was https://api.netatmo.com/oauth2/token
DEBUG:requests_oauthlib.oauth2_session:Request headers were {'User-Agent': 'python-requests/2.21.0', 'Accept-Encoding': 'gzip, deflate', 'Accept': 'application/json', 'Connection': 'keep-alive', 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', 'Content-Length': '96', 'Authorization': 'Basic NWVmNWM0NTQ5NzcyOWIxYTRkN2ZlMGMzOjJIb2ZDdEx5RGtSQ1VXTG52eGxCYWVod2ZtdVJGWXgwR29VQ1A2aDdVQg=='}
DEBUG:requests_oauthlib.oauth2_session:Request body was grant_type=password&username=user&password=password&scope=read_station
DEBUG:requests_oauthlib.oauth2_session:Response headers were {'Server': 'nginx', 'Date': 'Thu, 13 Jul 2023 08:34:44 GMT', 'Content-Type': 'application/json', 'Transfer-Encoding': 'chunked', 'Connection': 'keep-alive', 'Expires': '0', 'Cache-Control': 'no-cache, must-revalidate', 'X-XSS-Protection': '1; mode=block', 'Access-Control-Allow-Origin': '*', 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains', 'X-Powered-By': 'Netatmo'} and content {"error":"unauthorized_client"}.
DEBUG:requests_oauthlib.oauth2_session:Invoking 0 token response hooks.
Traceback (most recent call last):
  File "lockatmo6.py", line 38, in <module>
    scope="read_station",
  File "/home/pi/.local/lib/python3.7/site-packages/pyatmo/auth.py", line 266, in __init__
    scope=scope,
  File "/home/pi/.local/lib/python3.7/site-packages/requests_oauthlib/oauth2_session.py", line 360, in fetch_token
    self._client.parse_request_body_response(r.text, scope=self.scope)
  File "/home/pi/.local/lib/python3.7/site-packages/oauthlib/oauth2/rfc6749/clients/base.py", line 421, in parse_request_body_response
    self.token = parse_token_response(body, scope=scope)
  File "/home/pi/.local/lib/python3.7/site-packages/oauthlib/oauth2/rfc6749/parameters.py", line 431, in parse_token_response
    validate_token_parameters(params)
  File "/home/pi/.local/lib/python3.7/site-packages/oauthlib/oauth2/rfc6749/parameters.py", line 438, in validate_token_parameters
    raise_from_error(params.get('error'), params)
  File "/home/pi/.local/lib/python3.7/site-packages/oauthlib/oauth2/rfc6749/errors.py", line 405, in raise_from_error
    raise cls(**kwargs)
oauthlib.oauth2.rfc6749.errors.UnauthorizedClientError: (unauthorized_client) ```

@Lock128
Copy link
Author

Lock128 commented Jul 14, 2023

@oscarsommerer
Copy link

I came across this error too in my ETL jobs.

So if anyone else is wondering how to implement a non-interactive authentication flow now:

First you have to generate a refresh token at https://dev.netatmo.com. Just select your app, scroll down to the "Token generator" and generate a new one with the appropriate scopes. Then grab the refresh token and pluck it into the following snippet:

auth = pyatmo.NetatmoOAuth2(
    client_id=client_id,
    client_secret=client_secret
)
auth.extra["refresh_token"] = "<refresh-token>"
auth.refresh_tokens()

client = pyatmo.WeatherStationData(auth) // or pyatmo.PublicData, pyatmo.HomeData, ...
...

Since refresh tokens don't seem to expire this should work for the foreseeable future. Although I'm not sure if we'll have to call refresh_tokens() manually again, once the access token expires - since I create a new client every time my jobs run.

@Lock128
Copy link
Author

Lock128 commented Jul 17, 2023

This worked well for me when I tried it, thanks a lot @oscarsommerer

Is there a documentation on when the tokens expire?

Are you "saving" the results of auth.refresh_tokens() somewhere?

@cgtobi
Copy link
Collaborator

cgtobi commented Nov 26, 2023

Is this still an issue?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants