What's Changed
This release includes a security fix (please upgrade), major login
resilience improvements, two new activity-editing methods, and bug fixes.
๐ Security
- Token store hardening (GHSA-wjhr-76vg-2hvc, CWE-732, High).
Client.dump()
previously wrotegarmin_tokens.jsonunder the process umask, leaving it
world-readable (0o644) on the default Linux umask. The file holds the DI
refresh token, so any local user on a shared host could read it and gain
persistent access to the account. Tokens are now written0o600inside a
0o700directory (withO_NOFOLLOWand a defensivechmod), regardless of
umask. Affected: โค 0.3.4. Patched: 0.3.5. Upgrading is strongly advised
for anyone storing tokens on a multi-user system.
โจ Login resilience (fixes #369)
- In-chain token validation. Each login strategy's token is now verified
against the API before the chain accepts it. A token the API rejects
(401/403 โ an account/region-specific condition) is discarded and the next
strategy is tried automatically. Only definitive auth rejections fall
through; transient 5xx/network errors never block a working login. - Self-healing from poisoned cached tokens. If cached tokens load but the
API rejects them, they're discarded and a fresh credential login runs
automatically โ fixing the long-standing footgun where a stale token cache
silently short-circuited the login chain on every run. logout()is now functional (was a deprecated no-op): clears in-memory
auth state and removes cached tokens on disk. Callable asg.logout()or
g.logout(tokenstore).- New
verify_loginoption (Garmin(..., verify_login=False)) to restore
the legacy "first token wins" behavior. - New
skip_strategieson the client to force or skip specific login
strategies โ useful for diagnosing which auth path works on your account. - Cleaner failure handling: explicit Cloudflare 403 / CAPTCHA detection,
child/family-account detection,429errors preserved through the login
wrapper, and no more stack-trace dumps for expected login failures.
๐ New API methods
set_activity_description(activity_id, description)(#367)set_activity_exercise_sets(activity_id, payload)(#368)- CN accounts: domain-aware service URLs for authentication (#366)
Both new methods are available in the interactive demo under the new
โ๏ธ Activity Editing menu.
๐ Fixes
get_training_readinessnow correctly annotatedlist[dict[str, Any]]โ the
endpoint returns a list of snapshots, not a single dict (#361). Downstream
tooling that validates against the return type (e.g. pydantic-based MCP
servers) no longer breaks.get_morning_training_readinesskeeps defensive handling for a single-dict
response.- Typed wrapper:
typed.get_training_readiness()normalizes an empty response
to[].
๐งช Internal / tooling
- New mocked test suites for login recovery and token-store permissions; no
network required. test_strategy.pyโ interactive diagnostic to run each login strategy in
isolation and tee output to a log.
Upgrade
pip install --upgrade garminconnectFull Changelog: 0.3.4...0.3.5