How to authenticate with Google Spreadsheets API using Python client / discovery service? - python

I'm using Python 2.7 and the client library for Google API which I am trying to use to get authenticated access to Spreadsheets like so:
# sa == Service Account
scope = 'https://spreadsheets.google.com/feeds'
credentials = SignedJwtAssertionCredentials(sa_id, sa_key, scope)
http = httplib2.Http()
http = credentials.authorize(http)
build('spreadsheets', 'v2', http=http)
Note this is from a client script and not in Google App Engine. The output of the above is:
File "/Library/Python/2.7/site-packages/apiclient/discovery.py", line
196, in build
version)) apiclient.errors.UnknownApiNameOrVersion: name: spreadsheets version: v2
I know I'm doing this wrong, but I'm having trouble finding any examples of authenticating without using ClientLogin and/or the .NET/Java client libraries.
[UPDATE] The answer may be in the following source example, but I noticed on skimming it that it still uses email/password: https://code.google.com/p/gdata-python-client/source/browse/src/gdata/spreadsheet/service.py

The old Python gdata service libraries support ClientLogin, AuthSub and OAuth 1.0 authentication. All of which have been deprecated. If you wish to use the OAuth 2.0 Service Account credentials you'll need to hack something together like:
def buildSpreadsheetService():
scope = 'https://spreadsheets.google.com/feeds'
credentials = SignedJwtAssertionCredentials(sa_id, sa_key, scope)
http = httplib2.Http()
http = credentials.authorize(http)
build('drive', 'v2', http=http)
sheets = gdata.spreadsheet.service.SpreadsheetsService()
sheets.additional_headers = {'Authorization': 'Bearer %s' % http.request.credentials.access_token}
return sheets

Related

Gmail Api return Unauthorized client or scope in request

I have struggled to make this work but did half the job.
Actually I can only read messages from Gmail API, If I try to use the gmail.modify Scope I get an error:
HttpAccessTokenRefreshError: unauthorized_client: Unauthorized client or scope in request.
Here is my code:
# init gmail api
credentials_path = os.path.join(settings.PROJECT_DIR, 'settings/gmail_credential.json')
scopes = ['https://www.googleapis.com/auth/gmail.readonly',
'https://www.googleapis.com/auth/gmail.modify']
credentials = ServiceAccountCredentials.from_json_keyfile_name(credentials_path, scopes=scopes)
delegated_credentials = credentials.create_delegated('my_account#gmail.com')
http_auth = delegated_credentials.authorize(Http())
gmail = build('gmail', 'v1', http=http_auth)
In my service account:
I have set all possibles rĂ´les to my service account "......iam.gserviceaccount.com"
I activated DWD: DwD: Google Apps Domain-wide Delegation is enabled.
I have read somewhere that I need a google work account to give permission to my service account to use gmail.Modify on my my_account#gmail email account. Seems very hard way to just modify a message in an email.
I don't know what to do next.
Based from this documentation, you need to use the client ID from your "Developers Console" as the Client Name in the "Manage API client access" when you're setting your API scopes. Google API does not work as expected with your personal account #gmail.com. You should have organization domain account in Google in format you#your_organisation_domain.
Check these threads:
Google API Python unauthorized_client: Unauthorized client or scope in request
Google API OAuth2, Service Account, "error" : "invalid_grant"

Authenticate with Google Python SDK with only auth_token or the refresh_token

I have bunch of gmail.storage files containing a JSON blob with access info for users' accounts. I got these credential sets using PHP to prompt the user to authenticate/authorize my app. I'm able to call the Gmail API using these credentials. The JSON has the following fields:
{"access_token": xxxxxx,
"token_type":"Bearer",
"expires_in":3599,
"refresh_token":"xxxxxx",
"created":1421545394}
However, when I use the Python SDK for Gmail to authenticate a call using these credentials file like so:
credentials = storage.get()
It says that it needs the fields _module, _class and a few others. I'm able to get these when I use Python to fetch the information but not with PHP. Any idea how I can use the above code to get credentials without these extraneous fields?
Just call the refresh method before using the creds again.
storage = file.Storage("auth.dat")
credentials = storage.get()
http = httplib2.Http()
credentials.refresh(http) # <----------
http = credentials.authorize(http)
service = build('whatever_service', 'v2', http=http)

Make calls to Drive API inside of a Google App Engine Cloud Endpoints

I am trying to build my own endpoints inside of an App Engine Application.
There is an endpoint API that needs to ask user for
"https://www.googleapis.com/auth/drive.readonly" scope.
It performs a list of the Drive API and scan the drive file of that user.
The problem is that I don't know how to make call to Drive api inside of an endpoint API.
I think inside of the endpoint method, it has the credentials we got from the user. But I don't know how to receive that.
I am using python as the backend language.
#drivetosp_test_api.api_class(resource_name='report')
class Report(remote.Service):
#endpoints.method(EmptyMessage, EmptyMessage,
name='generate',
path='report/generate',
http_method='GET'
)
def report_generate(self, request):
logging.info(endpoints)
return EmptyMessage()
You can use os.environ to access the HTTP Authorization header, that includes the access token, that was granted all scopes you asked for on the client side, include drive.readonly in your sample.
if "HTTP_AUTHORIZATION" in os.environ:
(tokentype, token) = os.environ["HTTP_AUTHORIZATION"].split(" ")
You can then use this token to make calls to the API, either directly or by using the Google APIs Client Library for Python:
credentials = AccessTokenCredentials(token, 'my-user-agent/1.0')
http = httplib2.Http()
http = credentials.authorize(http)
service = build('drive', 'v2', http=http)
files = service.files().list().execute()
Note that this approach won't work if you are using an Android client, because that uses ID-Token authorization instead of access tokens.

Google Drive Service Account Access on Google App Engine to Impersonate Users

I am trying to gain service account access to to the Google Drive API. I followed the Google Drive SDK example when I was building my application. My code resembles the example almost exactly:
class MainPage(webapp2.RequestHandler):
def get(self):
build = createDriveService(user)
searchFile = build.files().get(fileId='FILEID').execute()
self.response.write(searchFile)
def createDriveService(userEmail):
API_KEY = 'APIKEY'
credentials = AppAssertionCredentials(
scope='https://www.googleapis.com/auth/drive',
sub=userEmail)
http = httplib2.Http()
http = credentials.authorize(http)
return build('drive', 'v2', http=http, developerKey=API_KEY)
When I call visit my GAE page the error in the logs that I am getting is:
<"File not found: FILEID">
I know the file ID exists as I copied it from the UI. I am using the simple Key access for the variable API_KEY. Should I be validating my application a different way?
EDIT1:
I've tried following various other StackOverflow. One of which involves using the SignedJwtAssertionCredentials and converting the .p12 key to a .pem key. After this change I am getting a
cannot import SignedJwtAsserionCredentials
error. From there I made sure to include the pycrypto library in my app.yaml. Any Idea?
EDIT2
I have successfully impersonated users on app engine. I followed this previously answered question and it worked.
I do not understand the user part of your code, bacause you use a Google App Engine project user account.
See this doc on how to use and find this account. You can also fnd this account using :
from google.appengine.api import app_identity
logging.info('service account : ' + app_identity.get_service_account_name())
Make sure you have given this project user account access to your drive file or folder!
My code looks like this :
def createDriveService():
SCOPE = 'https://www.googleapis.com/auth/drive'
API_KEY = 'AIzaSyB9UkK4OH5Z_E4v3Qp6bay6QEgGpzou3bc' # GAE
credentials = AppAssertionCredentials(scope=SCOPE)
logging.info('using service account : ' + app_identity.get_service_account_name())
http = credentials.authorize(httplib2.Http())
return build('drive', 'v2', http=http, developerKey=API_KEY)

Fulfilling Google Drive API OAuth2.0 Procedure w/o needing to find a verification code

The Google Drive API has the following OAuth2.0 procedure from their quickstart to receive the drive_service at the end:
# Copy your credentials from the APIs Console
CLIENT_ID = 'YOUR_CLIENT_ID'
CLIENT_SECRET = 'YOUR_CLIENT_SECRET'
# Check https://developers.google.com/drive/scopes for all available scopes
OAUTH_SCOPE = 'https://www.googleapis.com/auth/drive'
# Redirect URI for installed apps
REDIRECT_URI = 'urn:ietf:wg:oauth:2.0:oob'
# Path to the file to upload
FILENAME = 'document.txt'
# Run through the OAuth flow and retrieve credentials
flow = OAuth2WebServerFlow(CLIENT_ID, CLIENT_SECRET, OAUTH_SCOPE, REDIRECT_URI)
authorize_url = flow.step1_get_authorize_url()
print 'Go to the following link in your browser: ' + authorize_url
code = raw_input('Enter verification code: ').strip()
credentials = flow.step2_exchange(code)
# Create an httplib2.Http object and authorize it with our credentials
http = httplib2.Http()
http = credentials.authorize(http)
drive_service = build('drive', 'v2', http=http)
Notice that you will be given the variable authorize_url which is printed out. You are supposed to visit it using a browser and then confirm that you allow Google Drive to access your information, which then allows you get a "verification code." Is there any way that I can avoid the step of manual intervention and create a program that automates this step?
Yes, you can use web server to get OAuth callback which doesn't require any user interaction.
Basically, you set up your server to retrieve oauth code and add redirect uri to oauth flow so that oauth sends code to given uri instead of telling user to put code into the textbox.
Take a look at tools.run_flow() method at google-api-python-client.
It has pretty handy code of local webserver oauth flow.

Categories

Resources