Skip to content

Fix: updated POST Login headers to bypass new cloudflare block#226

Open
brunosantos wants to merge 3 commits intomatin:mainfrom
brunosantos:patch-1
Open

Fix: updated POST Login headers to bypass new cloudflare block#226
brunosantos wants to merge 3 commits intomatin:mainfrom
brunosantos:patch-1

Conversation

@brunosantos
Copy link
Copy Markdown

@brunosantos brunosantos commented Apr 2, 2026

Why

Garmin has made some changes around Auth and broke Garth and cyberjunky/python-garminconnect#332. As a result matin has deprecated the Garth project (#222).

What

This PR change follows #222 (comment) and seems to work by spoofing the user agent with new values to bypass the new cloudflare block

Summary by CodeRabbit

  • Chores

    • Improved SSO compatibility (user-agent update).
    • Package metadata updated (development status).
  • Documentation

    • Revamped README and docs with features, quick start, installation, examples, and MCP Server notes.
    • Removed deprecation notices.
  • Telemetry

    • Telemetry is now enabled by default and documents per-session IDs.
  • Misc

    • Version value adjusted.

spoofing user agent with new values to bypass new cloudflare blocks
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 2, 2026

Walkthrough

Bundle of mostly documentation updates plus behavioral defaults and small code changes: README/docs deprecation text removed and badges/quick-start added; telemetry defaults flipped to enabled; SSO User-Agent string updated; package version changed; deprecation warning removed; tests adjusted to new telemetry defaults.

Changes

Cohort / File(s) Summary
SSO headers
src/garth/sso.py
Replaced _SSO_UA User-Agent value used in SSO_PAGE_HEADERS (iPhone Safari → Windows 10 Chrome 131.0.0.0).
Telemetry behavior & tests
src/garth/telemetry.py, tests/test_telemetry.py
Telemetry defaults changed: Telemetry.enabled and Telemetry.send_to_logfire now default to True; tests updated to assert new defaults. Minor docstring/comment adjustments.
Documentation / README
README.md, docs/getting-started.md, docs/index.md, docs/telemetry.md
Removed deprecation notices; added badges, quick-start, features, MCP server and telemetry docs; telemetry doc now documents default-on telemetry and printed session_id guidance.
Package metadata & versioning
pyproject.toml, src/garth/version.py
Package classifier changed from Inactive → Production/Stable; __version__ updated from "0.8.0""0.7.12".
Module init (warnings)
src/garth/__init__.py
Removed module-level deprecation warnings.warn(...) emission.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • matin
  • felipao-mx
🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The PR title describes updating User-Agent headers to bypass Cloudflare blocks, which is the core technical change in src/garth/sso.py. However, it obscures the broader scope of the PR, which includes removing deprecation notices, updating documentation, changing telemetry defaults, and reverting a version downgrade—all aimed at un-deprecating the project. Revise the title to better reflect the primary objective: un-deprecating Garth and restoring functionality (e.g., 'Restore Garth: fix authentication and remove deprecation notices'). The User-Agent change is a technical detail supporting this larger goal.
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

cyberjunky added a commit to cyberjunky/aiogarmin that referenced this pull request Apr 3, 2026
Apply fix from matin/garth#226 — SSO sign-in pages require a desktop
browser User-Agent to avoid Cloudflare blocking. The mobile app UA is
kept for API calls only.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@cyberjunky
Copy link
Copy Markdown
Contributor

How can this work if old oauth endpoints are gone? Do you get oauth1/oauth2 tokens with this?

@brunosantos
Copy link
Copy Markdown
Author

I tested the lib by running:

terminal:uv run python
>>>
  import garth
  garth.login("your@email.com", "yourpassword")
  garth.save("~/.newstokensgarth")
  from garth import Activity
  activities = Activity.list(limit=10)
  for a in activities:
      print(f"{a.activity_id}: {a.activity_name} — {a.start_time_local}")

And got the oauth1/oauth2 tokens stored in the new folder and got activities back from the API calls.

From what I can see it's not that Garmin removed the existing OAuth endpoints, but that they do a basic user agent validation. By impersonating as a browser instead of a native app this works.
Let me know if I understood your question wrong.

@brunosantos
Copy link
Copy Markdown
Author

I'm also considering adding back the readme and other md files to the previous state (from this brunosantos@f99159a) given that the lib can work with a small change. But maybe it's beyond the scope of this PR and needs consent from @matin.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
README.md (3)

42-52: Remove import statements from code examples.

Same issue as above - remove import garth and from garth.exc import GarthException.

📝 Suggested fix
 ```python
-import garth
-from garth.exc import GarthException

 garth.resume("~/.garth")
 try:
     garth.client.username
 except GarthException:
     # Session is expired. You'll need to log in again
     pass

</details>

As per coding guidelines: "Code examples in documentation don't need import statements (e.g., don't show `import garth`)".

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against the current code and only fix it if needed.

In @README.md around lines 42 - 52, Remove the top-level import lines shown in
the example so the snippet only demonstrates usage; specifically delete the
import garth and from garth.exc import GarthException lines and leave the
example showing use of garth.resume, garth.client.username and the except
GarthException block unchanged so the documentation follows the guideline of
omitting import statements in code examples.


</details>

---

`62-66`: **Remove import statement from code example.**



<details>
<summary>📝 Suggested fix</summary>

```diff
 ```python
-import garth
 # Session is automatically loaded
 garth.client.username

</details>

As per coding guidelines: "Code examples in documentation don't need import statements (e.g., don't show `import garth`)".

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against the current code and only fix it if needed.

In @README.md around lines 62 - 66, Remove the top-level import from the README
code example so it matches the guideline; specifically edit the snippet that
references garth.client.username to delete the "import garth" line and leave the
comment and usage (i.e., the example containing garth.client.username and the
"Session is automatically loaded" comment) unchanged.


</details>

---

`32-38`: **Remove import statements from code examples.**

The code examples include `import garth` and `from getpass import getpass`, but the coding guidelines specify that code examples in documentation don't need import statements.



<details>
<summary>📝 Suggested fix</summary>

```diff
 ```python
-import garth
 from getpass import getpass

 garth.login(input("Email: "), getpass("Password: "))
 garth.save("~/.garth")

</details>

As per coding guidelines: "Code examples in documentation don't need import statements (e.g., don't show `import garth`)".

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against the current code and only fix it if needed.

In @README.md around lines 32 - 38, Remove the import lines from the README code
block: delete the "import garth" and "from getpass import getpass" statements
and leave the example calls (garth.login(...), getpass(...), garth.save(...)) so
the snippet shows usage without explicit imports.


</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>🤖 Prompt for all review comments with AI agents</summary>

Verify each finding against the current code and only fix it if needed.

Inline comments:
In @src/garth/telemetry.py:

  • Around line 112-113: The change flips telemetry defaults to opt-out-breaking
    behavior; revert the default booleans back to disabled by setting enabled: bool
    = False and send_to_logfire: bool = False (or make them driven by an explicit
    opt-in like an environment variable) so telemetry.Session creation (which
    triggers print(f"Garth session: {self.telemetry.session_id}") in http.py) and
    automatic Logfire sends do not occur at import time; update the configuration
    initialization in telemetry.py (the enabled and send_to_logfire symbols) to
    require explicit opt-in and ensure any env/config flag (e.g.,
    GARTH_TELEMETRY_ENABLED) is respected when constructing the telemetry object.

Nitpick comments:
In @README.md:

  • Around line 42-52: Remove the top-level import lines shown in the example so
    the snippet only demonstrates usage; specifically delete the import garth and
    from garth.exc import GarthException lines and leave the example showing use
    of garth.resume, garth.client.username and the except GarthException block
    unchanged so the documentation follows the guideline of omitting import
    statements in code examples.
  • Around line 62-66: Remove the top-level import from the README code example so
    it matches the guideline; specifically edit the snippet that references
    garth.client.username to delete the "import garth" line and leave the comment
    and usage (i.e., the example containing garth.client.username and the "Session
    is automatically loaded" comment) unchanged.
  • Around line 32-38: Remove the import lines from the README code block: delete
    the "import garth" and "from getpass import getpass" statements and leave the
    example calls (garth.login(...), getpass(...), garth.save(...)) so the snippet
    shows usage without explicit imports.

</details>

<details>
<summary>🪄 Autofix (Beta)</summary>

Fix all unresolved CodeRabbit comments on this PR:

- [ ] <!-- {"checkboxId": "4b0d0e0a-96d7-4f10-b296-3a18ea78f0b9"} --> Push a commit to this branch (recommended)
- [ ] <!-- {"checkboxId": "ff5b1114-7d8c-49e6-8ac1-43f82af23a33"} --> Create a new PR with the fixes

</details>

---

<details>
<summary>ℹ️ Review info</summary>

<details>
<summary>⚙️ Run configuration</summary>

**Configuration used**: Path: .coderabbit.yaml

**Review profile**: CHILL

**Plan**: Pro

**Run ID**: `7deee4ff-74ed-4bb9-9232-73c8ef00a6c3`

</details>

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 96f6cd8383905eba90a3d9e39d888266714c8aaa and 19b8bca64b04eb04ead113b39b93a3c1b5667d3e.

</details>

<details>
<summary>⛔ Files ignored due to path filters (1)</summary>

* `uv.lock` is excluded by `!**/*.lock`

</details>

<details>
<summary>📒 Files selected for processing (9)</summary>

* `README.md`
* `docs/getting-started.md`
* `docs/index.md`
* `docs/telemetry.md`
* `pyproject.toml`
* `src/garth/__init__.py`
* `src/garth/telemetry.py`
* `src/garth/version.py`
* `tests/test_telemetry.py`

</details>

<details>
<summary>💤 Files with no reviewable changes (2)</summary>

* src/garth/__init__.py
* docs/getting-started.md

</details>

<details>
<summary>✅ Files skipped from review due to trivial changes (4)</summary>

* src/garth/version.py
* pyproject.toml
* docs/telemetry.md
* docs/index.md

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

Comment on lines +112 to +113
enabled: bool = True
send_to_logfire: bool = True
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Breaking change: telemetry now enabled by default.

Changing defaults from False to True for both enabled and send_to_logfire is a significant behavioral change. Per the context snippet from http.py:67-68, this means:

  1. All users will see print(f"Garth session: {self.telemetry.session_id}") output at import time
  2. HTTP request/response data (sanitized) will be sent to Logfire by default

While the data is sanitized, this is an opt-out change that may surprise existing users. Consider:

  • Documenting this prominently in release notes
  • Keeping enabled=False as default and requiring explicit opt-in for telemetry collection
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/garth/telemetry.py` around lines 112 - 113, The change flips telemetry
defaults to opt-out-breaking behavior; revert the default booleans back to
disabled by setting enabled: bool = False and send_to_logfire: bool = False (or
make them driven by an explicit opt-in like an environment variable) so
telemetry.Session creation (which triggers print(f"Garth session:
{self.telemetry.session_id}") in http.py) and automatic Logfire sends do not
occur at import time; update the configuration initialization in telemetry.py
(the enabled and send_to_logfire symbols) to require explicit opt-in and ensure
any env/config flag (e.g., GARTH_TELEMETRY_ENABLED) is respected when
constructing the telemetry object.

@app4g
Copy link
Copy Markdown

app4g commented Apr 3, 2026

How can this work if old oauth endpoints are gone? Do you get oauth1/oauth2 tokens with this?

I'm actually still using the existing endpoints from way back when (garth from 1+ yrs ago) on my own iOS project. I've been waiting for it to not work, but it still does. I had 1 instance of 429 (I really did try a few times in succession) and it locked me out for a bit but then after 15+min or so it went back to working.

getCookies             - SUCCESS Headers: [xxxxx]
getCSRFToken           - SUCCESS CSRF: 989XXXXXXX
submitLogin.AuthTicket - SUCCESS Ticket:ST-XXXX-cas
URLRequest is created: https://connectapi.garmin.com/oauth-service/oauth/preauthorized?ticket=ST-XXXXX-cas&login-url=https://sso.garmin.com/sso/embed&accepts-mfa-tokens=true
getOAuth1Token         - SUCCESS
URLRequest is created: https://connectapi.garmin.com/oauth-service/oauth/exchange/user/2.0
exchOAuth1Token        - SUCCESS Expires:2026-04-05 07:25:21[24:31:47]

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

Successfully merging this pull request may close these issues.

3 participants