petergardfjall / garminexport

Garmin Connect activity exporter and backup tool
Apache License 2.0
488 stars 83 forks source link

Improve authentication by migrating to Garth #102

Closed matin closed 8 months ago

matin commented 9 months ago

Garth uses the same API as the mobile app for login and request authentication. It's as close as we can get to proper Garmin Connect API. The migration eliminates the need for Cloudscraper.

Garth ...

  1. Uses OAuth1 and OAuth2 token authentication after initial login
  2. OAuth1 token survive for a year
  3. Supports MFA
  4. Auto-refresh of OAuth2 token when expired
  5. Works on Google Colab
  6. Responses return JSON (instead of needing to parse HTML)

garminconnect has already been migrated.

I'm happy to write the PR if you're interested in making the change.

app4g commented 9 months ago

@matin great work on garth. what sort of hoops did you have to go thru to get to use oAuth tokens? In fact, how did you get these tokens?

tx

matin commented 9 months ago

@app4g it was a painful process. GH is probably not the best forum to go into the details. It was worth it though. The code and consumer key and secret can be used by everyone for personal use. Let me know if I can be helpful in the integration.

SimonBaars commented 9 months ago

I opened a PR that implements this solution: https://github.com/petergardfjall/garminexport/pull/104

petergardfjall commented 9 months ago

Thanks for looking into this. Apologies for not being very responsive (my time to spend on this is very limited at the moment).

It sounds sensible to use a more stable authentication flow, if such a thing exists for GarminConnect. Using another library like garth to handle the authentication could be an option, alternatively borrowing it's principles.

I skimmed it's source code and got tripped up here. A request is made for https://thegarth.s3.amazonaws.com/oauth_consumer.json which contains:

{
    "consumer_key": "fc3e99d2-118c-44b8-8ae3-03370dde24c0",
    "consumer_secret": "E08WAR897WEy2knn7aFBrvegVAf0AFdWBBF"
}

I'm a bit concerned about (1) relying on some "random" (well) Internet endpoint (that may not be forever present) that (2) seems to hardcode an authentication secret.

Would someone knowledgable mind explaining?

matin commented 9 months ago

Garth maintainer here.

The keys in S3 are the same ones used by the latest version of the Garmin Connect Android app.

Mobile app endpoints like this now work: garth.connectapi("/mobile-gateway/heartRate/forDate/2023-09-28")

It's unlikely but possible Garmin could update the keys. Keeping the keys in S3 (vs hardcoding) means they can be updated without requiring a library version upgrade.

petergardfjall commented 9 months ago

Garth maintainer here.

Thanks for stopping by. :slightly_smiling_face:

The keys in S3 are the same ones used by the latest version of the Garmin Connect Android app.

How does one get hold of those?

petergardfjall commented 8 months ago

I will stick to the "browser-impersonating" authentication approach for the time being. As of garminexport 0.5.0 the authentication is once again working. I am also not comfortable using hard-coded authentication credentials located in some "random" S3 bucket.