Open cyberjunky opened 8 months ago
I use the Mi Scale Exporter application on Android, the author Łukasz Świderski also had a problem with 2FA, but he managed to solve it, a window appears where we enter the received code, maybe he could tell us how to solve it in your application, he is a very kind man
Unfortunately Garmin now refuses to disable 2FA even via support request for any ECG-enabled watches. This might become more of a problem over time
According to Garmin, by law they are required to permanently enable 2FA on watches that have the ECG feature. Until this integration has 2FA capability those of us with newer Garmin watches sporting the ECG feature will not be able to integrate them in Home Assistant. Bummer.
It's the same Garmin who keep their API closed sourced and thus didn't help when I asked them for access to their developers program, that's a Bummer too... But all kidding aside adding this functionality to the integration is still on the top of my list.
Also just hit this issue. But it seems like the package used in the backgroud Garth already supports 2FA. But looks like it tries to read the code from the pipe/std
Exception when login is tried with enabled 2FA:
File "/config/custom_components/garmin_connect/config_flow.py", line 47, in async_step_user
await self.hass.async_add_executor_job(api.login)
File "/usr/local/lib/python3.11/concurrent/futures/thread.py", line 58, in run
result = self.fn(*self.args, **self.kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/garminconnect/__init__.py", line 179, in login
self.garth.login(self.username, self.password)
File "/usr/local/lib/python3.11/site-packages/garth/http.py", line 160, in login
self.oauth1_token, self.oauth2_token = sso.login(*args, client=self)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/garth/sso.py", line 95, in login
handle_mfa(client, SIGNIN_PARAMS)
File "/usr/local/lib/python3.11/site-packages/garth/sso.py", line 147, in handle_mfa
mfa_code = input("Enter MFA code: ")
^^^^^^^^^^^^^^^^^^^^^^^^^
EOFError: EOF when reading a line```
So all we are missing is an interface to enter the 2fa code? Looks like garth is already requesting it. I tried to hack my way around it but so far no luck.
First we need to make sure we gather and store the oauth tokens in HA after login to account/reauth, and use that for future logins, so ditch the password storage. (there are two ways, store in a file, or in a string in HA storage, the last one is preferred) Then fiddle with new version of Garth (separate branch) where we can set the callback routine to handle MFA (if user has it enabled) See here https://github.com/matin/garth/issues/41 Then look into things like reauth flow when token has expired. I'm looking into how the standard way of HA handling with oauth works (and handling a few of the above items) And trying to free up some time to work on it
there are two ways, store in a file, or in a string in HA storage, the last one is preferred
I recommend using Client.dumps()
and Client.loads()
if you're looking for a way to dump and load the tokens as a base64 encoded string. There are a few projects that use this method vs storing the tokens in files in environment variables.
Then look into things like reauth flow when token has expired.
fwiw, the tokens generated after MFA are valid for one year 😁
You really need to fix this asap. Garmin is getting more and more aggressive to ‘demand’ 2FA these days. I just bought a dashcam that CANNOT be used without 2FA, rendering my watch integration in HA useless 🤷🏼♂️ And all newer watch models with ECG is having the same limitation - meaning that more and more HA users will drop out…
@obhammer this integration is kindly developed by @cyberjunky in his spare time. Contributions are welcome from anyone willing to help. Please be a little more considerate with your language - nobody "needs" to fix it, but if someone does take the time, then we will all be grateful.
@obhammer this integration is kindly developed by @cyberjunky in his spare time. Contributions are welcome from anyone willing to help. Please be a little more considerate with your language - nobody "needs" to fix it, but if someone does take the time, then we will all be grateful.
Well, the fact is that Garmin seem to force ‘all’ users to use 2FA pretty soon - and in that regard, this integration will be rendered useless for ‘all’ users. The word ‘need’ is of course very harsh to use - what I meant was ‘’maybe, if integration should stay relevant, you should evaluate if you maybe need to do something about it - soon….maybe’’ 😉
@obhammer this integration is kindly developed by @cyberjunky in his spare time. Contributions are welcome from anyone willing to help. Please be a little more considerate with your language - nobody "needs" to fix it, but if someone does take the time, then we will all be grateful.
Well, the fact is that Garmin seem to force ‘all’ users to use 2FA pretty soon - and in that regard, this integration will be rendered useless for ‘all’ users. The word ‘need’ is of course very harsh to use - what I meant was ‘’maybe, if integration should stay relevant, you should evaluate if you maybe need to do something about it - soon….maybe’’ 😉
Any updates with 2FA?
There was a delay due to waiting on a change in garth, an underlying library. I just published the change that should allow this to move forward.
I wrote earlier about the Mi Scale Exporter application for Android, author Łukasz Świderski, the author has already managed to do it so well that you don't even have to enter the code every time, maybe it would help with our problem
@Gawronnek the Garmin integration for mi-scale-exporter is based on Garth 😉
I left an earlier comment on how to avoid repeatedly entering the MFA code. The token generated during the login is valid for one year. It just needs to be stored and reused (instead of using username/password + MFA code).
@matin Good news.
Does this mean the feature is coming soon? 😀
I'm currently on a 1476 day step streak and use an input boolean to manually track whether I hit my 10k step goal for the day, otherwise, HA bombards me with reminder messages every hour past 8pm to finish my steps for the day. It would be nice if HA knew how many steps I had without me manually setting the input boolean every day.
Cheers!
Everybody, there is quite an easy workaround available and working.
If you take a look at underlying login function here you'll notice that it already uses garth library. This is great not only because garth allows saving tokens, but also this integration already tries to load them! So, in summary to use this integration if you have 2FA enabled on your Garmin Connect account you need to:
pip install garth
:
import garth
from getpass import getpass
email = input("Enter email address: ") password = getpass("Enter password: ")
garth.login(email, password) garth.save("~/.garth")
this will generate and save your session tokens to `~/.garth` (a hidden directory directly in your home dir, tokens are valid for 1 year)
2. you need to make those tokens accessible by Home Assistant.
2.1 if you're running Home Assistant in docker:
* copy content of `~/.garth` to any place you desire
* mount that directory in the container, eg `/srv/docks/hass/.garth:/config/.garth`
* add an environment variable `GARMINTOKENS` to equal to the path inside container
2.2 if you're running HASS anyhow else - add env variable `GARMINTOKENS` that points at the directory tokens are in
4. configure the integration as you would if you didn't have 2FA enabled - tokens will be used
5. PROFIT! it works
[Full explaination](https://blog.tyborek.pl/home-assistant-and-garmin-connect-2fa-workaround/)
awesome! Got it working 😀
FYI I used this custom integration to add the environment variable to homeassistant in step 2.2
I took a look at it and tried to add the MFA request to the config flow, but since the call from inside garth for the prompt_mfa
is not async, this is getting tricky with the HA config flow.
I have no real experience with the HA config flow, but there seems to be no easy way to show a new form over a "step" that is not yet finished. If anybody knows how, let me know and I put what I have into a PR.
My current approch is to start another async call that is waiting for input to the MFA field (with timeout), if given, the login continues.
I took a look at it and tried to add the MFA request to the config flow, but since the call from inside garth for the
prompt_mfa
is not async, this is getting tricky with the HA config flow.I have no real experience with the HA config flow, but there seems to be no easy way to show a new form over a "step" that is not yet finished. If anybody knows how, let me know and I put what I have into a PR.
My current approch is to start another async call that is waiting for input to the MFA field (with timeout), if given, the login continues.
I also implemented this, and was stuck on same issue, I then asked Matin from garth to make the function async, and he did, but I didn't have time yet to proceed/test it, make sure you are on last version of garth (in manifest) I believe he implemented it in production version
I'm not 100% sure, it is in main branch or a seperate one, he mentioned it in a closed issue on garths gh, with an unrelated subject, cant find it that quick
Awesome found it in 0.4.46, I will try to implement it and give it another try now.
Yeehh, nah, this is still going into a direction it should not. I asked matin if it would be possible to split the mfa request into a different method, as this would make our life way easier and would go hand in hand with the HA config flow.
https://github.com/matin/garth/issues/41#issuecomment-2346596817
Following the ha rules for config flow is always good yes, but I don't think we ever get it through to be official integration though. Done that with FireServiceRota once and kind of promised myself not to attempt it with another integration, it costed me 5 years of my life. When you made one part follow the strict rules and lint, another part got deprecated...Almost impossible...
But keep in mind you somehow need to know when to ask for MFA and when not, not everyone will enable it.
Following the ha rules for config flow is always good yes, but I don't think we ever get it through to be official integration though. Done that with FireServiceRota once and kind of promised myself not to attempt it with another integration, it costed me 5 years of my life. When you made one part follow the strict rules and lint, another part got deprecated...Almost impossible...
I understand, but the idea I had to get this working with the promt_mfa()
Callback would be super dirty and if interrupted could then force a restart of the HA instance to get it working again, and it would also depend on a timer function.
I think we should implement a clean solution or otherwise use the workaround with the GARMINTOKENS as mentioned by Bretos.
I would love to have this implemented in a proper and stable way, even if this never makes it officially into HA, since it uses a closed API and is against the guidelines.
Yeah. I agree. And yes more stable and following latest code structure is also what my aim is... And there are many many more sensors available then implemented in HA integration, I would love to implement categories of sensors to be enable/disabled by user, or autodetected
Workaround by Bretos definitely works. I just set it up, also used the custom integration mentioned by nelbs to add the ENV variable.
awesome! Got it working 😀
FYI I used this custom integration to add the environment variable to homeassistant in step 2.2
You can make a guide step to step? Now I have install Environment Variable, and garminconnect Start garmin connect and make login> login error with mail from garmin with passcode. in configuration mail insert this:
default_config:
environment_variable:
GARMINTOKENS: 123456 #(123456 is the passcode number received via mail)
restart the home assistant
re-loging garminconnect, but with error.
Thanks
The value for GARMINTOKENS should be the path to the folder where the tokens are stored, not the passkey you received.
The value for GARMINTOKENS should be the path to the folder where the tokens are stored, not the passkey you received.
Ok thanks, Then, for example, in the configuration.yaml insert:
`default_config: environment_variable: GARMINTOKENS: /config/.passcode
And in config folder create a file ".passcode" with inside:
123456
In this case the code received from garmin?
Thanks
@kirkoff71 nope, inside directory .passcode
put the tokens (two files) which were created by the python script I pasted in my comment
@kirkoff71 nope, inside directory
.passcode
put the tokens (two files) which were created by the python script I pasted in my comment
Solve thanks at all... Write for another.
Solve thanks at all... Write for another peaple if have problem.
1) Enter in home assistant with terminal, if heven't, install through add component " I have install "Advanced SSH & Web Terminal", I have virtual machine on Qnap NAS
2) Install through HACS the 2Environment Variable"
3) Edit "config.yaml" ed insert this code:
default_config:
environment_variable:
GARMINTOKENS: /config/.passcode/.garth
4) Restart home assistent
5) Create in in /config/.passcode the file "garmin.py" and copy this in the file and copy the file in the "/config/.passcode" (script create from @Bretos, thanks)
import garth
from getpass import getpass
email = input("Enter email address: ")
password = getpass("Enter password: ")
# If there's MFA, you'll be prompted during the login
garth.login(email, password)
garth.save("~/.garth")
6) open the terminal and install "garth" with this command pip install garth
7) In terminal change directory with this command: cd /config/.passcode
8) Lunch the script: python garmin.py
and insert, the mail, the password and the passcode send via mail from Garmin
9) Change directory with this command: cd ~
(the ~ create press alt key and digit 126 code on number key)
10) Check if file is present with ls -a
11) If is present now move the ".garth" direcory with this command mv .garth/ /config/.passcode/
12) Install the garmin add on via hacs and make the login with mail and password.
13) Enjoy :)
6. open the terminal and install "garth" with this command `pip install garth` 7. In terminal change directory with this command: `cd /config/.passcode` 8. Lunch the script: `python garmin.py` and insert, the mail, the password and the passcode send via mail from Garmin
Hello! In my terminal, I don't have the pip command, nor python. How would I get that installed? I'm using HAOS..
Placeholder for multiple related tickets