Service Account, python, cannot get sample to work ("invalid grant"?)

2,942 views
Skip to first unread message

Mike Bria

unread,
Apr 1, 2012, 2:46:13 PM4/1/12
to oauth...@googlegroups.com
Hi, I'm trying to get the given OAUTH / "Service Account" in Python working locally.


I've got my Service Account activated on the Console, and have the private key file locally, and am using the sample as is (with the exception of using my key file name and dev email during the SignedJwtAssertionCredentials creation).

I can't get past the "build" line though, fails with:

ERROR:oauth2client.client:Failed to retrieve access token: {

  "error" : "invalid_grant"

}


Stepping into the discovery.py build function, I can see it get to the resp, content = http.request(requested_urlline, but no further. The full trace info in the console is:
ERROR:oauth2client.client:Failed to retrieve access token: {
  "error" : "invalid_grant"
}
Traceback (most recent call last):
  File "C:\Users\Mike Bria\Documents\Visual Studio 2010\Projects\PyServiceAccoun
tSample\PyServiceAccountSample\PyServiceAccountSample.py", line 68, in <module>
    main(sys.argv)
  File "C:\Users\Mike Bria\Documents\Visual Studio 2010\Projects\PyServiceAccoun
tSample\PyServiceAccountSample\PyServiceAccountSample.py", line 60, in main
    service = build("tasks", "v1", http=http)
  File "C:\Python27\lib\site-packages\google_api_python_client-1.0beta8-py2.7.eg
g\apiclient\discovery.py", line 180, in build
    resp, content = http.request(requested_url)
  File "C:\Python27\lib\site-packages\google_api_python_client-1.0beta8-py2.7.eg
g\oauth2client\client.py", line 386, in new_request
    self._refresh(request_orig)
  File "C:\Python27\lib\site-packages\google_api_python_client-1.0beta8-py2.7.eg
g\oauth2client\client.py", line 553, in _refresh
    self._do_refresh_request(http_request)
  File "C:\Python27\lib\site-packages\google_api_python_client-1.0beta8-py2.7.eg
g\oauth2client\client.py", line 609, in _do_refresh_request
    raise AccessTokenRefreshError(error_msg)
AccessTokenRefreshError: invalid_grant


I'm pretty new to this, so maybe (hopefully?) I'm doing something stupid and easily fixed.  Can anyone help?

Thanks,
Mike
 

Eric Haskins

unread,
Apr 1, 2012, 3:14:41 PM4/1/12
to oauth...@googlegroups.com

Check the iss field to make sure your using client email and not client id. I did that on mine and was getting invalid grant

Eric Haskins
Voodoo.com
sent from my Samsung Galaxy S2

Mike Bria

unread,
Apr 1, 2012, 4:38:36 PM4/1/12
to oauth...@googlegroups.com
Thanks for the response Eric. Unfortunately, I am in fact passing the email (7......@ developer.gserviceaccount.com) and not the client id (7......@ apps.googleusercontent.com).

Hm, wonder what's up.

One thing to note that may be factor (?) is that I also have a "Client ID for installed applications" generated for the API Access too.  Could that be affecting or causing this in any way?  I'd like to try removing that (I don't need it, only created it by accident first), but I don't see any way on the Console to delete it.

Mike

Eric Haskins

unread,
Apr 1, 2012, 5:00:55 PM4/1/12
to oauth...@googlegroups.com

No cause you generate the jwt with the private key and email of the service account. Make sure you haven't crossed any info.

Eric


sent from my Samsung Galaxy S2

Mike Bria

unread,
Apr 1, 2012, 7:13:04 PM4/1/12
to oauth...@googlegroups.com
Bummer.  My info is definitely not crossed - its surely the service account info.

FWIW, what I'm really trying to do is create a C#/.NET based dailyish job that will go our to the GAN (Google Affiliate Network) Events API and get my publisher "events".  This really should be a simple thing, but I'm finding it certainly ain't.  All the .NET client samples are using "Installed app" approach, which maybe I can live with - but the damn sample code is next to nightmarish.  I figured I'd give Service Account a try and with Python - cuz the the python client api looks clean, and I can integrated Python into my .NET app.

The whole thing is quite frustrating.  I just want to make a simple headless REST GET to a single Uri, why does it have to be so darn complicated?!?  (Sorry for venting here).

Eric Haskins

unread,
Apr 1, 2012, 7:39:27 PM4/1/12
to oauth...@googlegroups.com
Mike,

I am familiar with python but only using for NLP most of our stuff is PHP so here is how we got the access token in PHP. Of course we cant use it since we are after AdSense Stats which are tied to a user and wont work with a service account

<?php
$now = time();
$jwt_header = base64_encode(json_encode(array(
'alg' => 'RS256',
'typ' => 'JWT'
)));

$jwt_claim = base64_encode(json_encode(array(
'exp' => $now+3600,
'iat' => $now
)));

require_once '/www/phpinclude/google_client_api/src/auth/apiSigner.php';
require_once '/www/phpinclude/google_client_api/src/auth/apiP12Signer.php';
$p12 = new apiP12Signer('private.pem', 'notasecret');
$jwt_signature = base64_encode($p12->sign($jwt_header . '.' . $jwt_claim));

$ch = curl_init();
curl_setopt_array($ch, array(
CURLOPT_HEADER => false,
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POSTFIELDS => array(
'grant_type' => 'assertion',
'assertion' => implode('.', array($jwt_header,$jwt_claim,$jwt_signature))
),
));
$x = curl_exec($ch); 

$token = json_decode($x, true); 

if($token['access_token']){
echo "Holy $%&# it Works!!!";
echo '<pre>';
print_r($token);
$query = 'access_token=' . $token['access_token'];
$query .= '&accountId=dp-XXXXXXX_XXX_XXXX';
$query .= '&startDate=2012-03-01';
$query .= '&endDate=' . date('Y-m-d');
$query .=
'&metric=PAGE_VIEWS&metric=AD_REQUESTS&metric=MATCHED_AD_REQUESTS&metric=CLICKS&metric=EARNINGS';
$query .= '&dimension=DATE';

curl_setopt_array($ch, array(
CURLOPT_HTTPGET => true,
));
$x = curl_exec($ch); 
curl_close($ch);
print_r(json_decode($x,true));
} else {
echo "Google API's Are A Thorn In my Side!";
}

--
Eric Haskins
Voodoo.com

Mike Bria

unread,
Apr 1, 2012, 7:54:55 PM4/1/12
to oauth...@googlegroups.com
Thanks for the reference Eric, appreciate that (and the shared sentiment imbedded in the strings!).  I'll see what I can gather from it.

Thing is, I'm realizing Service Accounts won't help me anyway - GAN won't support it.

Nonetheless, I still have the fun task of figuring out how the heck to get this data using the "installed app" (yet no user) route.

Fun fun fun.  Side thorns!


On Sunday, April 1, 2012 7:39:27 PM UTC-4, Eric Haskins wrote:
Mike,

I am familiar with python but only using for NLP most of our stuff is PHP so here is how we got the access token in PHP. Of course we cant use it since we are after AdSense Stats which are tied to a user and wont work with a service account

<?php
$now = time();
$jwt_header = base64_encode(json_encode(array(
'alg' => 'RS256',
'typ' => 'JWT'
)));

$jwt_claim = base64_encode(json_encode(array(

Justin Smith

unread,
Apr 1, 2012, 7:54:51 PM4/1/12
to oauth...@googlegroups.com
I'm sorry you guys are having problems. I'd like to help.

Mike - what happens if you add the following line right after the call to "authorize"?

    print credentials._generate_refresh_request_body()

You should see something like:

grant_type=assertion&assertion_type=http%3A%2F%2Foauth.net%2Fgrant_type%2Fjwt%2F1.0%2Fbearer&assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.{the part after this '.' is unique to your service account}

Justin Smith

unread,
Apr 1, 2012, 9:28:32 PM4/1/12
to oauth...@googlegroups.com
The python client library should just work "out of the box" for getting an access token.

The access token is available in the client after you make the API calls - the client obtains an access token only when they are needed. In this sample: http://code.google.com/p/google-api-python-client/source/browse/samples/service_account/tasks.py, the access token is available after the call to "execute".

9 times out of 10, when you get an error with "invalid_grant", it's because the email address was copied incorrectly, or there's an old private key in the directory.

As you point out, GAN doesn't really support Service Accounts yet. Only a few APIs do at this point (http://googledevelopers.blogspot.com/2012/03/service-accounts-have-arrived.html).


On Sunday, April 1, 2012 4:54:51 PM UTC-7, Justin Smith wrote:
I'm sorry you guys are having problems. I'd like to help.

Mike - what happens if you add the following line right after the call to "authorize"?

    print credentials._generate_refresh_request_body()

You should see something like:

grant_type=assertion&assertion_type=http%3A%2F%2Foauth.net%2Fgrant_type%2Fjwt%2F1.0%2Fbearer&assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.{the part after this '.' is unique to your service account}
On Sun, Apr 1, 2012 at 4:39 PM, Eric Haskins <eha...@gmail.com> wrote:
Mike,

I am familiar with python but only using for NLP most of our stuff is PHP so here is how we got the access token in PHP. Of course we cant use it since we are after AdSense Stats which are tied to a user and wont work with a service account

<?php
$now = time();
$jwt_header = base64_encode(json_encode(array(
'alg' => 'RS256',
'typ' => 'JWT'
)));

$jwt_claim = base64_encode(json_encode(array(

Mike Bria

unread,
Apr 1, 2012, 10:28:13 PM4/1/12
to oauth...@googlegroups.com
Hi Juston, thanks for the input.

To your first question/suggestion - adding the print on the creeds.  Yes, I get just what you said I should:

grant_type=assertion&assertion_type=http%3A%2F%2Foauth.net%2Fgrant_type%2Fjwt%2F
1.0%2Fbearer&assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.[..and a bunch of other encoded chars...]

I'm pretty sure I've got all the info (email, key file name) defined in the script correctly, I've checked it (and "checked it twice" like Santa).

I've even tried a whole nuther account I have access to with the same "invalid grant" result.  I should note at this point:  doing this with IronPython (Pyth9on 2.7.2) in Visual Studio '10 on Win7 via VMWare on a MacBook.  Neat, huh?  Could any of that be playing in somehow I wonder?

At this point its just my inner demon determined to see this work, not as much a true-true need, since we've confirmed I can't use the Service Account for this week's desired biz need (GAN) anyway.  Nonetheless, I really want to see this work.

Thanks much, if there's any other info I can give, please let me know.

Mike

jcgregorio

unread,
Apr 2, 2012, 9:01:00 AM4/2/12
to oauth...@googlegroups.com


On Sunday, April 1, 2012 7:13:04 PM UTC-4, Mike Bria wrote:
Bummer.  My info is definitely not crossed - its surely the service account info.

Are you sure you have the Tasks API turned on for that Project?
 

FWIW, what I'm really trying to do is create a C#/.NET based dailyish job that will go our to the GAN (Google Affiliate Network) Events API and get my publisher "events".  This really should be a simple thing, but I'm finding it certainly ain't.  All the .NET client samples are using "Installed app" approach, which maybe I can live with - but the damn sample code is next to nightmarish.  I figured I'd give Service Account a try and with Python - cuz the the python client api looks clean, and I can integrated Python into my .NET app.

Since you can't use service accounts with GAN it might be easier to use
an installed client, and then run this script as the user you want to access
the data under:


It's a command-line application that goes through the OAuth 2.0 flow and
gets you a refresh token and stores it. You can then use that file 'cmd-line.dat'
on your server to get access tokens.
 
storage = Storage('cmd-line.dat')
credentials = storage.get() http = httplib2.Http() credentials.authorize(http)

   -joe

 

Mike Bria

unread,
Apr 2, 2012, 9:30:51 AM4/2/12
to oauth...@googlegroups.com
Great Joe, thanks very much.  I don't have the time to check this out now, but I will soon.

Cheers,
Mike

Dimitry

unread,
Jun 20, 2012, 1:27:12 PM6/20/12
to oauth...@googlegroups.com
Hello!

Did you solved "invalid_grant" problem? I have the same.

понедельник, 2 апреля 2012 г., 17:30:51 UTC+4 пользователь Mike Bria написал:

Robert Cauble

unread,
Jun 25, 2012, 10:32:08 PM6/25/12
to oauth...@googlegroups.com
I ran into something similar. It turned out that the clock on my machine was just a few seconds ahead. Setting it back fixed the problem.

Dimitry

unread,
Jul 1, 2012, 6:27:31 AM7/1/12
to oauth...@googlegroups.com
Thank you! Tuning time on my mac solved the problem!)

вторник, 26 июня 2012 г., 6:32:08 UTC+4 пользователь Robert Cauble написал:

Mike Klem

unread,
Oct 3, 2012, 11:00:11 AM10/3/12
to oauth...@googlegroups.com
Thanks Robert!  I was having the same issue using using service accounts.  Time tweak fixed it.

Richard Gillette

unread,
Jan 7, 2013, 11:38:34 AM1/7/13
to oauth...@googlegroups.com
How have you turned back your clocks to fixed this? I have this cert signing working in PERL and am getting the same Invalid Grant error, but I dont know what you mean by resetting your clocks. Can someone explain it to me for an ubuntu 12 system?

Dimitry

unread,
Jan 10, 2013, 6:33:41 AM1/10/13
to oauth...@googlegroups.com
On MacOS by "resetting clock" I meant syncing system's clock with time server.

понедельник, 7 января 2013 г., 20:38:34 UTC+4 пользователь Richard Gillette написал:
Reply all
Reply to author
Forward
0 new messages