gmusicapi icon indicating copy to clipboard operation
gmusicapi copied to clipboard

Webclient requires additional steps to log in from new ip

Open JakedUp opened this issue 8 years ago • 5 comments

The docs state "Users who don’t use two-factor auth will likely need to enable less secure login. If this is needed, a warning will be logged during login (which will print to stderr in the default logging configuration)."

However, I cannot get login to work. I've tried with 2-step & app-specific passwords, and I've tried without 2-step & less secure login enabled. Either way, when I login, it always returns false. When looking at the log file, I see the following entry: "gmusicapi.Webclient3 (webclient:61) [INFO]: failed to authenticate". Mobileclient and Musicmanager login just fine.

I know it's suggested to not use the Webclient, but as far as I can tell, it's the only way I can get my cover art uploaded correctly (Webclient.upload_album_art). When uploading music via Musicmanager, my cover art is removed from the MP3.

Is Webclient login no longer working?

JakedUp avatar Jul 19 '16 01:07 JakedUp

Got it! Started running session.py line-by-line over SSH, and found that after submitting the password, there was a third screen where it was asking me to do one of 4 things:

  • Get a text message with a verification code at (•••) •••-••99
  • Get a phone call with a verification code at (•••) •••-••99
  • Confirm the recovery phone you added to this account
  • Confirm the recovery email you added to this account

I simulated submitting one of these steps over SSH, and then Webclient.login worked perfectly.

        form_candidates = response.soup.select("form")
        form = form_candidates[3]
        response = browser.submit(form, 'https://accounts.google.com/ServiceLoginAuth')
        form_candidates = response.soup.select("form")
        form = form_candidates[0]
        form.select('[name=email]')[0]['value'] = '[email protected]'
        response = browser.submit(form, 'https://accounts.google.com/ServiceLoginAuth')

I suspect I needed to do this step since I'm running gmusicapi off of a remote webserver, and therefore Google was trying to block the login since it didn't appear to be a known IP address. This is just a theory, but it makes sense.

Wonder if this flow could somehow be integrated into the Webclient login?

JakedUp avatar Jul 19 '16 02:07 JakedUp

Ah. Yeah, we've had trouble with webclient auth on remote machines: I actually turned off webclient testing from travis because of it.

I don't think there's an easy solution. The webclient just wasn't built for programmatic auth.

simon-weber avatar Jul 19 '16 17:07 simon-weber

It's all good. Now that I've successfully logged in with the work-around above, that IP address is now known to Google, and I am longer having login issues. Hopefully this thread helps someone else who is having the same issue. You should probably also look into putting a notice in the docs about remote connections not working. I could not find a single thread of information about this anywhere.

JakedUp avatar Jul 19 '16 19:07 JakedUp

I had some problems with using a TFA account with WebClient - it won't accept an app-specific password, but it's not possible to use less-secure login with TFA. I added the following lines in session.py after submitting the password. I also had to change the login method in WebClient to accept kwargs so as to be able to pass the TFA token across; now I can log in using something like wc.login("email", "password", totp="TFATokenFromAuthenticator")

        if 'totp' in kwargs:  # Using 2FA
            form_candidates = response.soup.select("form")

            #commented out as there is another form to try a different option
            # if len(form_candidates) > 1:
            #     log.error("Google login form dom has changed; there are %s candidate forms:\n%s",
            #               len(form_candidates), form_candidates)
            #     return False

            form = form_candidates[0]
            form.select("#totpPin")[0]['value'] = kwargs["totp"]

            response = browser.submit(form, 'https://accounts.google.com/signin/challenge/totp/2')

            try:
                response.raise_for_status()
            except requests.HTTPError:
                log.exception("submitting OTP form failed")
                return False

askvictor avatar Aug 23 '16 04:08 askvictor

Had the same issue. Just False login status, same messages in logs. Added application password in google and used it instead of mine. worked.

sashgorokhov avatar May 17 '17 18:05 sashgorokhov