1ap / google-api-python-client

Automatically exported from code.google.com/p/google-api-python-client
Other
0 stars 0 forks source link

Cannot get new access token on second start #160

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
[Use this form for both apiclient and oauth2client issues]

What steps will reproduce the problem?
1. Complete tasks.py with changes to Fusion API

   service = build("fusiontables", "v1", http=http)
   #help(service.query())
   print(service.query().sql(sql='SELECT Location FROM        1gvB3SedL89vG5r1128nUN5ICyyw7Wio5g1w1mbk').execute(http))

2. First start of app is ok. Everything works. 
3. The second start of app gets error: 

     oauth2client.client.AccessTokenRefreshError: invalid_grant

4. Wait for 5-6 hours and you'll get steps 2 and 3 again. 

What is the expected output? What do you see instead?
I expect working of application on every start, not only on the first one.

What version of the product are you using? On what operating system?
MacOS Lion

Please provide any additional information below.

Source code:

from apiclient.discovery import build
from oauth2client.client import SignedJwtAssertionCredentials

logging.getLogger().setLevel(logging.INFO)

f = file('key.p12', 'rb')
key = f.read()
f.close()

# Create an httplib2.Http object to handle our HTTP requests and authorize it
  # with the Credentials. Note that the first parameter, service_account_name,
  # is the Email address created for the Service account. It must be the email
  # address associated with the key that was created.
credentials = SignedJwtAssertionCredentials(
    '...@developer.gserviceaccount.com',
    key,
    scope='https://www.googleapis.com/auth/fusiontables')
http = httplib2.Http()
http = credentials.authorize(http)

service = build("fusiontables", "v1", http=http)
#help(service.query())
print(service.query().sql(sql='SELECT Location FROM 
1gvB3SedL89vG5r1128nUN5ICyyw7Wio5g1w1mbk').execute(http))

Original issue reported on code.google.com by legato...@gmail.com on 30 Jun 2012 at 8:38

GoogleCodeExporter commented 8 years ago
[deleted comment]
GoogleCodeExporter commented 8 years ago
[deleted comment]
GoogleCodeExporter commented 8 years ago
[deleted comment]
GoogleCodeExporter commented 8 years ago
I guess there is should be used some kind of storage, but I didn't find the 
setting of this storage in SignedJwtAssertionCredentials and 
AssertionCredentials. I found set_store() function in main OAuth2Credentials 
class, but seems like it is unused in SignedJwtAssertionCredentials, so the 
access token is not kept in it.

Original comment by legato...@gmail.com on 30 Jun 2012 at 9:23

GoogleCodeExporter commented 8 years ago
Alright, I figured out what was the problem.

First of all I've got "invalid_grant" error because system time on my mac was 
few seconds ahead. I've tuned the time and now everything works everytime.

Second, I found out that there is a code in SignedJwtAssertionCredentials 
resposible to store private_key in storage (to_json and from_json), but this 
code is not working.

My source code:

f = file('privatekey.p12', 'rb')
key = f.read()
f.close()

credentials = SignedJwtAssertionCredentials(
    '...@developer.gserviceaccount.com',
    key,
    scope='https://www.googleapis.com/auth/fusiontables')
storage = Storage('fusion.dat')
credentials.set_store(storage)

http = httplib2.Http()
http = credentials.authorize(http)

service = build("fusiontables", "v1", http=http)
print(service.query().sqlGet(sql='SELECT Location FROM 
1gvB3SedL89vG5r1128nUN5ICyyw7Wio5g1w1mbk').execute(http))

There is a problem storing private_key as JSON field. Running this code I get 
error like this:

UnicodeDecodeError: 'utf8' codec can't decode byte 0x82 in position 1: invalid 
start byte

I've tried several approaches to encode private_key, that it can be stored in 
Storage, but with no luck. I'll continue to try, but I need an advice.

Original comment by legato...@gmail.com on 1 Jul 2012 at 12:01

GoogleCodeExporter commented 8 years ago
hooray! 
So I found the main problem of SignedJwtAssertionCredentials is that it just 
does not keep access_token, it refreshing access token on every request, what 
takes some time. I solved that problem:

1. I store private_key in Storage object via encoding it in Base64.
2. I've managed to work SignedJwtAssertionCredentials with Storage object to 
keep access_token: I've added some fields in constructor of 
SignedJwtAssertionCredentials and its parent class – AssertionCredentials.

I've attached new "client.py" from "oauth2client" package. It has all the 
discribed changes and it works well.

Original comment by legato...@gmail.com on 1 Jul 2012 at 12:45

Attachments:

GoogleCodeExporter commented 8 years ago
Thanks for finding this, it does look like the issue is storing the private_key 
in JSON. I will probably solve it in a slightly different way, by keeping the 
base64 encoded value in self.private_key and decoding it when it is needed to 
be used, that avoids putting special code in OAuth2Credentials.to_json() that's 
only needed for a sub-sub-class.

Original comment by jcgregorio@google.com on 10 Jul 2012 at 3:26

GoogleCodeExporter commented 8 years ago
CL out for review: http://codereview.appspot.com/6346086/

Original comment by jcgregorio@google.com on 11 Jul 2012 at 2:31

GoogleCodeExporter commented 8 years ago

Original comment by jcgregorio@google.com on 11 Jul 2012 at 4:10

GoogleCodeExporter commented 8 years ago
This issue was closed by revision 59a3057af225.

Original comment by jcgregorio@google.com on 11 Jul 2012 at 7:36

GoogleCodeExporter commented 8 years ago
Great! Glad to be useful)

Original comment by legato...@gmail.com on 12 Jul 2012 at 5:23