Skip to content

Widget MFA detects email MFA but no OTP is delivered by email or SMS #386

Description

@rt-techlab

Summary

The widget+cffi login strategy correctly detects the Garmin email MFA page and calls the configured prompt_mfa callback, but no OTP is delivered for that Widget SSO session.

OTP delivery works immediately when logging in through a normal web browser. However, an OTP generated by the browser session is rejected when entered into the python-garminconnect Widget MFA session, which appears to confirm that the OTP is session-specific.

Environment

  • garminconnect: 0.3.6
  • Python: 3.12.13
  • Runtime: Docker, based on python:3.12-slim
  • Docker host: Debian 13
  • Garmin domain: garmin.com
  • Account MFA methods enabled:
    • Email
    • SMS

Authentication code

from garminconnect import Garmin

api = Garmin(
    email,
    password,
    prompt_mfa=lambda: input("Garmin MFA code: "),
)

api.login(tokenstore="/data/tokens")

I also reproduced the issue while explicitly skipping the rate-limited mobile strategies:

api.client.skip_strategies.update({
    "mobile+cffi",
    "mobile+requests",
})

This causes authentication to start directly with the Widget SSO strategy, but an OTP is still not delivered.

Steps to reproduce

  1. Use an account with email MFA enabled.
  2. SMS MFA was also enabled in the Garmin Account Security Center during troubleshooting.
  3. Call Garmin.login() with a prompt_mfa callback.
  4. The Widget SSO strategy reaches the MFA page.
  5. The callback prompts for a code:
Garmin MFA code:
  1. No new OTP is received by email or SMS.
  2. Log in through a normal web browser using the same account.
  3. The browser login OTP is delivered immediately.
  4. Entering that browser-generated OTP into the pending Widget MFA session fails with:
garminconnect.exceptions.GarminConnectAuthenticationError:
Widget MFA failed: GARMIN Authentication Application

Initial log with mobile strategies enabled

mobile+cffi returned 429: Mobile login returned 429 — IP rate limited by Garmin
mobile+requests returned 429: Mobile login returned 429 — IP rate limited by Garmin
Garmin MFA code:

The mobile 429 condition persisted for more than 32 hours.
The Widget strategy still reached the MFA prompt, so the mobile rate limit may be a separate issue.

Behavior after skipping mobile strategies

After setting:

api.client.skip_strategies.update({
    "mobile+cffi",
    "mobile+requests",
})

the Widget strategy was entered directly without the two mobile 429 responses, but no OTP was delivered.

Expected behavior

When the Widget SSO page is detected as email/SMS MFA, Garmin should deliver a new OTP associated with that Widget authentication session. Entering that OTP should complete authentication and allow the DI tokens to be persisted.

Actual behavior

The MFA page is detected and the callback is invoked, but no OTP is delivered for that session.
A code issued by a separate browser session is rejected by the Widget session.

Related issues / changes

Security / redaction

No email address, phone number, password, OTP, service ticket, Cookie, or OAuth token is included in this report.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions