Skip to content

Commit 145294e

Browse files
cyberjunkydavidbsandorclaude
committed
Fix tokens not saved to disk after fresh credential login (#342)
On a fresh login, _tokenstore_path was never set on the client before calling client.login(), so auto-refresh dump() calls never fired and the token file was never written. Every run forced a full re-login with MFA regardless of tokenstore path provided. Fix: normalize tokenstore_path to str upfront, set client._tokenstore_path before credential login, and explicitly dump tokens after a successful fresh login. Reported and fixed by @davidbsandor — thanks! Co-Authored-By: davidbsandor <davidbsandor@users.noreply.github.com> Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent aac3498 commit 145294e

2 files changed

Lines changed: 11 additions & 4 deletions

File tree

garminconnect/__init__.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""Python 3 API wrapper for Garmin Connect."""
22

3+
import contextlib
34
import logging
45
import numbers
56
import os
@@ -420,6 +421,7 @@ def login(self, /, tokenstore: str | None = None) -> tuple[str | None, str | Non
420421

421422
# Try to load tokens from tokenstore if provided
422423
tokens_loaded = False
424+
tokenstore_path = None
423425
if tokenstore:
424426
try:
425427
if len(tokenstore) > 512:
@@ -429,9 +431,8 @@ def login(self, /, tokenstore: str | None = None) -> tuple[str | None, str | Non
429431
# Tokenstore is a path - normalize it for cross-platform compatibility
430432
# This fixes Windows path issues where ~ expansion or path separators
431433
# might cause token extraction to not find all token files correctly
432-
tokenstore_path = Path(tokenstore).expanduser().resolve()
433-
# Convert to string with normalized path separators
434-
normalized_path = str(tokenstore_path)
434+
tokenstore_path = str(Path(tokenstore).expanduser().resolve())
435+
normalized_path = tokenstore_path
435436
logger.debug(
436437
f"Loading tokens from normalized path: {normalized_path}"
437438
)
@@ -470,11 +471,17 @@ def login(self, /, tokenstore: str | None = None) -> tuple[str | None, str | Non
470471
)
471472
# In MFA early-return mode, profile/settings are not loaded yet
472473
return mfa_status, _legacy_token
474+
if tokenstore_path is not None:
475+
self.client._tokenstore_path = tokenstore_path
473476
mfa_status, _legacy_token = self.client.login(
474477
self.username,
475478
self.password,
476479
prompt_mfa=self.prompt_mfa,
477480
)
481+
# Persist tokens so next run restores without re-login/MFA
482+
if tokenstore_path is not None:
483+
with contextlib.suppress(Exception):
484+
self.client.dump(tokenstore_path)
478485
# Continue to load profile/settings below
479486

480487
# Ensure profile is loaded (tokenstore path may not populate it)

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "garminconnect"
3-
version = "0.3.0"
3+
version = "0.3.1"
44
description = "Python 3 API wrapper for Garmin Connect"
55
authors = [
66
{name = "Ron Klinkien", email = "ron@cyberjunky.nl"},

0 commit comments

Comments
 (0)