I work at a small company whose mail is hosted through Google. As one of the administrators responsible for managing employee accounts I'm attempting to automate some tasks using Google APIs and one or more dedicated service accounts. I wrote the short Python script below to request an access token according to the documentation Google provides but I continue to get an "invalid_grant" error.
I've done the following:
- Logged into the Google Developers Console as the service account and created a project
- Created a client ID of type service account
- Logged into the Google Admin Console and added client email address and scope URLs I wish the account to have access to
Searches online have yielded answers indicating that either the system time of the machine is off, the limit for refresh tokens has been exceeded or that the client ID instead of the client email has been used. I've synchronized the time on a Windows machine and a Linux machine prior to running the script and the same error appears. I'm not even getting an access token so I doubt the refresh limit has been exceeded. As can be seen below, the iss value is set to the client email address ending with "@developer.gserviceaccount.com".
I suspect that there is something else I am missing and, as I'm new to Python, I suspect it's something embarrassingly simple. Perhaps someone can assist?
import json
import time
import base64
import requests
from datetime import datetime
utc = datetime.utcnow()
iat = time.mktime(utc.timetuple())
exp = iat + 3600
jwt_header = {
"alg":"RS256",
"typ":"JWT"
}
jwt_claim_set = {
"iss":"pleasehelpme@developer.gserviceaccount.com",
"scope":"https://www.googleapis.com/auth/admin.directory.user",
"aud":"https://www.googleapis.com/oauth2/v3/token",
"iat":int(iat),
"exp":int(exp),
"sub":"someadminfrustrated@googleoauth.com"
}
jwt_jws = bytearray(str(jwt_header) + '.' + str(jwt_claim_set))
jwt_unencoded = str(jwt_header) + '.' + str(jwt_claim_set) + '.' + str(jwt_jws)
jwt_encoded = base64.urlsafe_b64encode(str(jwt_unencoded))
url = 'https://www.googleapis.com/oauth2/v3/token'
headers = {
'content-type': 'application/x-www-form-urlencoded'
}
payload = {
'grant_type': 'urn:ietf:params:oauth:grant-type:jwt-bearer',
'assertion': jwt_encoded
}
response = requests.post(url, headers=headers, params=payload)
print response
print response.json()
The output is the following:
<Response [400]>
{u'error_description': u'Bad Request', u'error': u'invalid_grant'}