kiwiz/gkeepapi

gkeepapi.LoginException: NeedsBrowser

EcmaXp opened this issue ยท 21 comments

Python 3.6.3 (v3.6.3:2c5fed8, Oct  3 2017, 18:11:49) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import gkeepapi
>>> import getpass
>>> gkeepapi.Keep()
<gkeepapi.Keep object at 0x000001B86923C438>
>>> keep = _
>>> keep.login("********@********", getpass.getpass())
Password:
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Users\EcmaXp\AppData\Roaming\Python\Python36\site-packages\gkeepapi\__init__.py", line 363, in login
    ret = auth.login(username, password, get_mac())
  File "C:\Users\EcmaXp\AppData\Roaming\Python\Python36\site-packages\gkeepapi\__init__.py", line 67, in login
    raise LoginException(res.get('Error'), res.get('ErrorDetail'))
gkeepapi.LoginException: ('NeedsBrowser', 'To access your account, you must sign in on the web. Touch Next to start browser sign-in.')```

Note. I setup the OTP for secure.

Password:
{'Error': 'NeedsBrowser',
 'ErrorDetail': 'To access your account, you must sign in on the web. Touch '
                'Next to start browser sign-in.',
 'Url': 'https://accounts.google.com/signin/continue?sarp=1&scc=1&continue=https://accounts.google.com/o/android/auth?hl%3Den_us%26xoauth_display_name%3DAndroid%2BLogin%2BService%26source%3DAndroid%2BLogin&plt=...'}

After finish the OAuth login, redirect to https://accounts.google.com/o/oauth2/programmatic_auth?hl=en_us&xoauth_display_name=Android+Login+Service&source=Android+Login&client_id=SOME_NUMBER_HERE-SOME_TOKEN_HERE.apps.googleusercontent.com&scope=https://www.google.com/accounts/OAuthLogin&access_type=offline&set_oauth_token_cookie=true

SOME_NUMBER_HERE, and SOME_TOKEN_HERE is private string.
oauth_code, oauth_token, SIDCC cookie also provided from redirected page.

can you use an app pass if getpass() isn't already?

success. thanks!

if Error value are equal as "NeedBrowser" then fireing customized warning also help.

  1. warning "Warning: you need setup app password if you using OTP.")
  2. raise the original error?
kiwiz commented

Added a note to the readme for now.

I don't have 2-factor enabled. This means also there is no option for me to create an app password.
I still get the error.

Here they suggest 2 options:

Using a fresh install with Python 3.6 gives me this error:

In [11]: keep.login('myemail@gmail.com', getpass.getpass(), 'android_mac')
Password:
Using android_id: 0123456789abcdef
{'name': 'Privat', 'mainId': 'SAMPLE_LABEL_15579203-66cd-48ee-87e3-65a7ff283206', 'timestamps': {'created': '2015-03-03T09:46:30.480Z', 'updated': '2018-05-10T22:02:43.861Z'}}
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-11-b6639a94b661> in <module>()
----> 1 api.login('myemail@gmail.com', getpass.getpass(), '0123456789abcdef')

D:\Hannes\dev\gkeepapi\gkeepapi\__init__.py in login(self, username, password, android_id)
    351         ret = auth.login(username, password, android_id)
    352         if ret:
--> 353             self.load(auth)
    354
    355         return ret

D:\Hannes\dev\gkeepapi\gkeepapi\__init__.py in load(self, auth)
    365         self._keep_api.setAuth(auth)
    366         self._reminders_api.setAuth(auth)
--> 367         self.sync()
    368
    369     def get(self, node_id):

D:\Hannes\dev\gkeepapi\gkeepapi\__init__.py in sync(self)
    568
    569             if 'userInfo' in changes:
--> 570                 self._parseUserInfo(changes['userInfo'])
    571
    572             if 'nodes' in changes:

D:\Hannes\dev\gkeepapi\gkeepapi\__init__.py in _parseUserInfo(self, raw)
    631                     node = _node.Label()
    632                     logger.debug('Created label: %s', label['mainId'])
--> 633                 node.load(label)
    634                 labels[label['mainId']] = node
    635

D:\Hannes\dev\gkeepapi\gkeepapi\node.py in load(self, raw)
   1352         self._name = raw['name']
   1353         self.timestamps.load(raw['timestamps'])
-> 1354         self._revision = raw['revision']
   1355         self._merged = NodeTimestamps.str_to_dt(raw['lastMerged']) if 'lastMerged' in raw else NodeTimestamps.int_to_dt(0)
   1356

KeyError: 'revision'

#24 should address this.


What worked for me

  • Comment line 1354 in node.py (see #24).
  • Let Keep.login accept a third parameter android_id and pass in one of your Android devices.
  • Go to https://accounts.google.com/b/0/DisplayUnlockCaptcha and click continue.
  • Run keep = keep.login('youremail@gmail.com', getpass.getpass(), 'your_android_mac')
kiwiz commented

@hannesfrank Could you submit a PR with this changes? I'm (finally) seeing this behaviour. The server doesn't seem to expose any version info, so detecting this sort of thing is difficult. :/

Bad news, the unlock captcha setting appears to be a one thim thing: It works only for the next login attempt. Today I get the same NeedsBrowser error again.

Could be that setting up 2-factor and using an app password is the only reliable solution, but I don't want to use that.

Another possibility would be to try parsing the Website. gmusicapi implements a Webclient which uses mechanicalsoup. I haven't testet that though.

But if someone figures out a reliable solution, I'd be happy to make a PR. ๐Ÿ˜ƒ

Facing the same NeedsBrowser issue. Was so excited to try this. ๐Ÿ˜ข

@hannesfrank That gmusicapi approach looks decent to me. I'll test it out, and report. If it works, we would be okay with adding this here, right?

A bit unrelated question, but are the keep notes stored on disk somewhere? or are they only in memory?

I experienced this issue myself when i was trying to test out gkeepapi. Funny thing is, I had disabled two-step authentication and the issue still occurred. So I thought what would happen if I enable two step authentication for my google account to be able to generate app password for my script. It turns out that it worked that way :) Hope this helps someone.

Hey guys, I'm getting this LoginException: NeedsBrowser error even though I'm using an app password. This seems to have started happening within the last week. Here's my code:

print('importing modules')
import gkeepapi
import os

print('setting environment variables')
user = os.environ['GKEEP_USERNAME']
pw = os.environ['GKEEP_APP_PASSWORD']

print('logging into Keep')
keep = gkeepapi.Keep()
keep.login(user, pw)

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Library/Python/2.7/site-packages/gkeepapi/__init__.py", line 470, in login
    ret = auth.login(username, password, get_mac())
  File "/Library/Python/2.7/site-packages/gkeepapi/__init__.py", line 48, in login
    raise exception.LoginException(res.get('Error'), res.get('ErrorDetail'))
gkeepapi.exception.LoginException: (u'NeedsBrowser', u'To access your account, you must sign in on the web. Touch Next to start browser sign-in.')

screen shot 2018-10-16 at 1 17 20 pm

I'm only getting 'NeedsBrowser' when requesting from heroku/aws. I am able to use app password on home or work isp (att). Exact same code. Maybe this is required when google doesn't recognize the device?

kiwiz commented

Can someone test the following code snippet with the information generated from the browser flow?

import google_auth_oauthlib.flow

auth = google_auth_oauthlib.flow.Flow.from_client_config(
	{'installed': {
		'auth_uri': None,
		'token_uri': None,
		'client_id': CLIENT_ID,
	}},
	['https://www.google.com/accounts/OAuthLogin']
)

auth.fetch_token(code=OAUTH_CODE)
# Hopefully no exception was thrown

Hi @kiwiz ,

It looks like a couple more pieces are needed, and the scope URL you have there looks invalid. Here's what worked for me:

from google_auth_oauthlib.flow import Flow     
                                                                                                                                                                                                                                                                                                     
client_cfg = {'installed': {                                                                                                                                             
               'auth_uri' : 'https://accounts.google.com/o/oauth2/auth',                                                                                                  
               'token_uri' : 'https://oauth2.googleapis.com/token',                                                                                                       
               'client_id' : MY_CLIENT_ID,                                                                                 
               'client_secret' : MY_CLIENT_SECRET,                                                                                                                             
}}               
                                                                                                                                          
scopes = ['https://www.googleapis.com/auth/userinfo.email', 'https://www.googleapis.com/auth/userinfo.profile']                                                           
redir_uri = 'urn:ietf:wg:oauth:2.0:oob'                                                                                                                                   
                                                                                                                                                                          
auth = Flow.from_client_config(client_cfg, scopes, redirect_uri=redir_uri)                                                                                                 
print(auth.authorization_url(prompt='consent'))

# Here, I went to the printed URL and consented to obtain OAUTH_CODE
                                                                                                                    
auth.fetch_token(code=OAUTH_CODE)
#Token data successfully returned with access_token, refresh_token, and id_token, along with expires_in (presumably seconds) and expires_at (Unix timestamp)

I'm not clear on what scopes you would actually need to make all of this work, though.

I haven't read through any of your code yet, but I would really like to help get this working if I can, since it's not working for me! Even with an App Password, I'm always getting the NeedsBrowser error.

I get the NeedsBrowser error when I try and login from my server, where annoyingly I have no browser. But on my laptop everything runs fine. In fact Google logged something along the way as a critical security error and I had to reset my passwords. I don't have two-factor authentication on and back in the day I ticked the 'allow less secure apps' option.

kiwiz commented

@MortimerMcMire315 Thanks for looking into this. I've been unable to repro, but I believe those parameters are correct. We're trying to replicate the parameters described in the second post.

Same problem just started happening to me. It was working yesterday.

My guess is that it may have something to do with changing internet connections?

The only code I am using is:

import gkeepapi
keepAPI = gkeepapi.Keep()
succ = keepAPI.login('####', '###')

Throws error:

Traceback (most recent call last):
  File "test.py", line 7, in <module>
    succ = keepAPI.login('#####@gmail.com', '#######')
  File "/home/######/.local/lib/python3.5/site-packages/gkeepapi/__init__.py", line 470, in login
    ret = auth.login(username, password, get_mac())
  File "/home/#####/.local/lib/python3.5/site-packages/gkeepapi/__init__.py", line 48, in login
    raise exception.LoginException(res.get('Error'), res.get('ErrorDetail'))
gkeepapi.exception.LoginException: ('NeedsBrowser', 'To access your account, you must sign in on the web. Touch Next to start browser sign-in.')

You need to allow an application to be added via this URL, it will simulate the recaptcha check:

gkeepapi and the packaged used for the Android Application settings don't support recaptcha, and that's how google blocks you initially.

Is there any resolution or update on this? I'm experiencing the same problem. DisplayUnlockCaptcha works partially. The error appears again after a while. 2-Step verification saddly isn't an option for me right now. Is there something else I should try or test?

kiwiz commented

Nothing concrete, unfortunately. The last few comments here might be useful: #69

You need to allow an application to be added via this URL, it will simulate the recaptcha check:

gkeepapi and the packaged used for the Android Application settings don't support recaptcha, and that's how google blocks you initially.

This was what worked for me. I'm using my own test (Google) account with no 2FA mechanism enabled, in case anyone was wondering.

kiwiz commented

Consolidated debugging tips here. Closing this for now, but feel free to comment if you continue to have issues.