# Feature Specification: Garmin Login Improvements **Feature Branch**: `003-loginimprovements-use-the` **Created**: Friday, October 10, 2025 **Status**: Draft **Input**: User description: "Rework the garmin authentication for this app. I want the app to: allow providing a user/pass via the /login endpoint; the app should store the resulting auth tokens and user/pass in the centralDB; the api caller should not need a cookie - all state should be global for the Garmin Sync service" ## User Scenarios & Testing *(mandatory)* ### User Story 1 - Initial Garmin Account Setup (Priority: P1) A user wants to link their Garmin account to the FitTrack Garmin Sync service for the first time. They provide their Garmin credentials via the `/login` endpoint. The system successfully authenticates with Garmin, stores the credentials and tokens, and confirms the link. **Why this priority**: This is the core functionality enabling users to connect their Garmin accounts, which is fundamental to the service. **Independent Test**: Can be fully tested by calling the `/login` endpoint with valid Garmin credentials and verifying that the credentials and tokens are stored in the `centralDB` and subsequent Garmin Sync operations can proceed. **Acceptance Scenarios**: 1. **Given** the FitTrack Garmin Sync service is running, **When** a user sends a POST request to `/login` with valid Garmin username and password, **Then** the system successfully authenticates with Garmin, stores the Garmin username, plaintext password, and authentication tokens in the `centralDB`, and returns a success response. 2. **Given** the FitTrack Garmin Sync service is running, **When** a user sends a POST request to `/login` with invalid Garmin username or password, **Then** the system returns an error response indicating authentication failure and does not store any credentials or tokens. --- ### User Story 2 - Automatic Garmin Token Refresh (Priority: P1) After initial setup, the system automatically manages the Garmin authentication tokens, refreshing them as needed without user intervention, to ensure continuous synchronization with Garmin. **Why this priority**: Ensures the service remains operational and data synchronization is uninterrupted, providing a seamless user experience. **Independent Test**: Can be tested by simulating an expired token scenario and verifying that the system successfully refreshes the token during a subsequent Garmin API call. **Acceptance Scenarios**: 1. **Given** valid Garmin credentials and tokens are stored in the `centralDB`, and the current Garmin authentication token is nearing expiration or has expired, **When** the Garmin Sync service attempts to perform an operation requiring Garmin authentication, **Then** the system automatically refreshes the Garmin authentication token using the stored credentials, updates the `centralDB` with the new tokens, and successfully completes the Garmin operation. 2. **Given** valid Garmin credentials and tokens are stored in the `centralDB`, and the current Garmin authentication token is valid, **When** the Garmin Sync service attempts to perform an operation requiring Garmin authentication, **Then** the system uses the existing valid token without attempting a refresh. --- ### User Story 3 - Stateless Garmin Sync Operations (Priority: P1) The Garmin Sync service operates without relying on session cookies. For every operation requiring Garmin access, it retrieves the necessary authentication tokens from the `centralDB` based on the single-user context. **Why this priority**: This is a core architectural requirement for the service to be stateless and not rely on client-side cookies. **Independent Test**: Can be tested by performing multiple Garmin Sync operations (e.g., activity download, health metric sync) and verifying that each operation successfully retrieves credentials from the `centralDB` and completes without requiring a prior session. **Acceptance Scenarios**: 1. **Given** valid Garmin credentials and tokens are stored in the `centralDB`, **When** any Garmin Sync operation is initiated, **Then** the service retrieves the necessary Garmin authentication tokens from the `centralDB` for the single user and uses them to authenticate with Garmin. 2. **Given** no valid Garmin credentials or tokens are stored in the `centralDB`, **When** any Garmin Sync operation is initiated, **Then** the service returns an error indicating that Garmin authentication is required. ## Requirements *(mandatory)* ### Functional Requirements - **FR-001**: The system MUST expose a `/login` endpoint that accepts a Garmin username and password. - **FR-002**: The system MUST authenticate with Garmin using the provided username and password. - **FR-003**: Upon successful Garmin authentication, the system MUST store the Garmin username, plaintext password, and authentication tokens in the `centralDB`. - **FR-004**: The system MUST automatically refresh Garmin authentication tokens when they are expired or nearing expiration. - **FR-005**: The system MUST update the `centralDB` with newly refreshed Garmin authentication tokens. - **FR-006**: The system MUST retrieve Garmin authentication tokens from the `centralDB` for all Garmin Sync operations. **The client is not required to send any authentication header for these operations.** - **FR-007**: The system MUST return an error response to the API caller if Garmin authentication fails (initial login or token refresh). - **FR-008**: The system MUST operate as a single-user system, using the single set of stored Garmin credentials for all operations. - **FR-009**: The `/login` endpoint MUST be publicly accessible without prior authentication. ## Clarifications ### Session 2025-10-10 - Q: How should the client authenticate for subsequent sync operations (e.g., `/api/sync/garmin/activities`) given that the spec states "the api caller should not need a cookie" and "all state should be global for the Garmin Sync service", but the contract for `sync_garmin_activities` shows an `Authorization: Bearer ` header? → A: No authentication header is required; the backend implicitly uses the single stored Garmin credentials. ### Key Entities *(include if feature involves data)* - **GarminCredentials**: Represents the stored Garmin authentication information. * Attributes: `garmin_username` (string), `garmin_password_plaintext` (string), `access_token` (string), `access_token_secret` (string), `token_expiration_date` (datetime). * Relationship: Stored in `centralDB`. ## Success Criteria *(mandatory)* ### Measurable Outcomes - **SC-001**: Users can successfully link their Garmin account via the `/login` endpoint within 10 seconds. - **SC-002**: Garmin data synchronization operations (e.g., activity download) complete without interruption due to expired tokens for 99.9% of attempts. - **SC-003**: The `/login` endpoint correctly handles invalid Garmin credentials, returning an error response within 2 seconds. - **SC-004**: The system maintains continuous Garmin connectivity for 99% of the time without requiring manual re-authentication.