matin / garth

Garmin SSO auth + Connect Python client
MIT License
274 stars 20 forks source link

login or save session fail #59

Closed Thomas-Tsai closed 2 months ago

Thomas-Tsai commented 2 months ago

Hi, I am trying to log in to my Garmin Connect using your sample code, but I got the error message:

the sample code:

import garth
from getpass import getpass

email = input("Enter email address: ")
password = getpass("Enter password: ")
# If there's MFA, you'll be prompted during the login
garth.login(email, password)

garth.save("garth_test")

ERROR MESSAGE:

python ./test.py
Enter email address: .......@gmail.com
Enter password: 
Traceback (most recent call last):
  File "/home//tmp/garth/GARTH/lib/python3.11/site-packages/requests/models.py", line 963, in json
    return complexjson.loads(self.content.decode(encoding), **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/json/__init__.py", line 346, in loads
    return _default_decoder.decode(s)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/json/decoder.py", line 337, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/json/decoder.py", line 355, in raw_decode
    raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home//tmp/garth/garth/./test.py", line 7, in <module>
    garth.login(email, password)
  File "/home//tmp/garth/garth/garth/http.py", line 160, in login
    self.oauth1_token, self.oauth2_token = sso.login(
                                           ^^^^^^^^^^
  File "/home//tmp/garth/garth/garth/sso.py", line 110, in login
    oauth1 = get_oauth1_token(ticket, client)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home//tmp/garth/garth/garth/sso.py", line 117, in get_oauth1_token
    sess = GarminOAuth1Session(parent=client.sess)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home//tmp/garth/garth/garth/sso.py", line 31, in __init__
    OAUTH_CONSUMER = requests.get(OAUTH_CONSUMER_URL).json()
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home//tmp/garth/GARTH/lib/python3.11/site-packages/requests/models.py", line 971, in json
    raise RequestsJSONDecodeError(e.msg, e.doc, e.pos)
requests.exceptions.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

The pip list result is:

Package            Version
------------------ --------
annotated-types    0.7.0
certifi            2024.6.2
charset-normalizer 3.3.2
garth              0.4.46
idna               3.7
oauthlib           3.2.2
pip                23.0.1
pydantic           2.7.4
pydantic_core      2.18.4
requests           2.32.3
requests-oauthlib  1.3.1
setuptools         66.1.1
typing_extensions  4.12.2
urllib3            2.2.2

Running on my debian host machine with kernel Linux debian-lab 6.1.0-21-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.90-1 (2024-05-03) x86_64 GNU/Linux

any idea?

matin commented 2 months ago

are you able to reproduce the error in a test with vcr?

I'm not able to reproduce the error, but if I can see the vcr cassette, I can see what the issue is

Thomas-Tsai commented 2 months ago

yes, this is the screencast link https://drive.google.com/file/d/1kzgJaraRU7OrWQLZ3Z3LLx5fqV8uVQvQ/view?usp=sharing

I am also trying to get the latest code from git master branch but got the same result.

Thomas-Tsai commented 2 months ago

get message from self.content in requests/models.py: line 955

b'<?xml version="1.0" encoding="UTF-8"?>\n<Error><Code>InvalidArgument</Code><Message>Unsupported Authorization Type</Message><ArgumentName>Authorization</ArgumentName><ArgumentValue>Basic dGhvbWFzOm9rb2s3NDgw</ArgumentValue><RequestId>DTX5AFE0WJY72Y4Y</RequestId><HostId>0NnwVBihhvipKcl2+KZp9+i5C8DWBya749aAb9QRPnJNJpRgmUV13xXH5eJS0On3THdIJpnhVuU=</HostId></Error>'

and also try to access oauth_consumer.json is fine....

curl https://thegarth.s3.amazonaws.com/oauth_consumer.json
{
    "consumer_key": "fc3e99d2-118c-44b8-8ae3-03370dde24c0",
    "consumer_secret": "E08WAR897WEy2knn7aFBrvegVAf0AFdWBBF"
}

finally, manually add this json data to OAUTH_CONSUMER(gather/sso.py: 18) then get a successful login and create t 2 files (oauth1_token.json oauth2_token.json )

no idea why requests.get(OAUTH_CONSUMER_URL).json() can not get the right JSON data but curl works fine with me.

matin commented 2 months ago

What happens if you manually run these line?

import requests

OAUTH_CONSUMER_URL = "https://thegarth.s3.amazonaws.com/oauth_consumer.json"
requests.get(OAUTH_CONSUMER_URL).json()
Thomas-Tsai commented 2 months ago

The result:

Python 3.11.2 (main, Mar 13 2023, 12:18:29) [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import requests
>>> 
>>> OAUTH_CONSUMER_URL = "https://thegarth.s3.amazonaws.com/oauth_consumer.json"
>>> requests.get(OAUTH_CONSUMER_URL).json()
Traceback (most recent call last):
  File "/home/thomas/newtest/lib/python3.11/site-packages/requests/models.py", line 963, in json
    return complexjson.loads(self.content.decode(encoding), **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/json/__init__.py", line 346, in loads
    return _default_decoder.decode(s)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/json/decoder.py", line 337, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/json/decoder.py", line 355, in raw_decode
    raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/thomas/newtest/lib/python3.11/site-packages/requests/models.py", line 971, in json
    raise RequestsJSONDecodeError(e.msg, e.doc, e.pos)
requests.exceptions.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

which is run with a clean virtual environment.

(newtest) thomas@debian-lab:~/newtest$ pip list
Package    Version
---------- -------
pip        23.0.1
setuptools 66.1.1
(newtest) thomas@debian-lab:~/newtest$ pip install requests
Collecting requests
  Using cached requests-2.32.3-py3-none-any.whl (64 kB)
Collecting charset-normalizer<4,>=2
  Using cached charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (140 kB)
Collecting idna<4,>=2.5
  Using cached idna-3.7-py3-none-any.whl (66 kB)
Collecting urllib3<3,>=1.21.1
  Using cached urllib3-2.2.2-py3-none-any.whl (121 kB)
Collecting certifi>=2017.4.17
  Using cached certifi-2024.6.2-py3-none-any.whl (164 kB)
Installing collected packages: urllib3, idna, charset-normalizer, certifi, requests
Successfully installed certifi-2024.6.2 charset-normalizer-3.3.2 idna-3.7 requests-2.32.3 urllib3-2.2.2
Thomas-Tsai commented 2 months ago

more tests here:

>>> r=requests.get(OAUTH_CONSUMER_URL)
>>> r.content
b'<?xml version="1.0" encoding="UTF-8"?>\n<Error><Code>InvalidArgument</Code><Message>Unsupported Authorization Type</Message><ArgumentName>Authorization</ArgumentName><ArgumentValue>Basic dGhvbWFzOm9rb2s3NDgw</ArgumentValue><RequestId>9ABBTPSJRQ6EAFPE</RequestId><HostId>7lkaDVbpMP1Nz8i66D3/UhzVgFOqZtZ6Dyc+Y7nu+Ou2KjLXMDAM6/ZieuqULGWU6nmLtxqZxMQ=</HostId></Error>'
>>> r.request.headers
{'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Authorization': 'Basic XXXXXX'}

Why Authorization in headers? try to remove that

>>> req = requests.Request('GET',OAUTH_CONSUMER_URL ,headers={})
>>> prepared = req.prepare()
>>> s = requests.Session()
>>> nr=s.send(prepared)
>>> nr
<Response [200]>
>>> nr.content
b'{\n    "consumer_key": "",\n    "consumer_secret": "E08WAR897WEy2knn7aFBrvegVAf0AFdWBBF"\n}'
>>> 

I believe the root cause is here and I have no idea why requests auto-add auth in this headers.

matin commented 2 months ago

Basic dGhvbWFzOm9rb2s3NDgw decodes to thomas:okok7480. does that seem familiar to you?

Thomas-Tsai commented 2 months ago

sure, I am super familiar with this. It's my secret when I am a student. This is my environmental issue, and thanks for your help!