I'm trying to make authorized requests to the google spreadsheets API and all the examples I found requests email and password from the user.
http://www.payne.org/index.php/Reading_Google_Spreadsheets_in_Python
http://www.mattcutts.com/blog/write-google-spreadsheet-from-python/
http://mrwoof.tumblr.com/post/1004514567/using-google-python-api-to-get-rows-from-a-google
Well this problem was solved with OAuth2 protocol which Google implements. I've gone through the OAuth2 process and I have a valid access_token, which I use to interact with Google Drive smoothly:
access_token = get_access_token() # external function
user_agent = request.META['HTTP_USER_AGENT']
credentials = AccessTokenCredentials(access_token, user_agent)
http = httplib2.Http()
http = credentials.authorize(http)
service = build('drive', 'v2', http)
service.files().copy(fileId=k, body=dict(title="Copia")).execute() # this works!
But I can't figure out a way to use the access_token to interact with the spreadsheets API. Does it still uses email and password login?
Thanks!
PS: BTW, I'm using the python gdata package, and please let me know if you have a good reference for it! :)
So, if you already have an access token (maybe you got it by your own via Oauth2 protocol, like me). You can interact with google spreadsheet api passing an instance of AuthSubToken to methods of SpreadsheetsClient.
from gdata.gauth import AuthSubToken
from gdata.spreadsheets.client import SpreadsheetsClient
atok = AuthSubToken(token_string=get_access_token()) # acess token via protocol
data = SpreadsheetsClient().get_worksheets(key, auth_token=atok)
Related
I created an python application that is using the Youtube api (so examples are in python, but doesn't really matter, the concepts should be the same). I managed to get it working where I can connect and make api calls. However, when I connect to the api, I have to define a flow that checks if a the credentials storage file exists. If it doesn't, then I have to manually sign in using the flow. After sign in the file (main.py-oauth2.json), is created with the token. I would like to be able to download the credentials without having to sign manually sign in. I was hoping there was a way to make a POST request for that token, like I have seen here, but I have been able to do this with Youtube api. Does anyone know how to implement the desired feature ?
main.py
flow = flow_from_clientsecrets(CLIENT_SECRETS_FILE,
scope=YOUTUBE_UPLOAD_SCOPE,
message=MISSING_CLIENT_SECRETS_MESSAGE)
storage = Storage(OAUTH_CREDENTIALS)
credentials = storage.get()
if credentials is None or credentials.invalid:
# manual / UI login
credentials = run_flow(flow, storage, args)
Trying to use a google service account throws 401 errors on upload.
credentials = Credentials.from_service_account_file(
SERVICE_ACCOUNT_FILE, scopes=YOUTUBE_UPLOAD_SCOPES)
if credentials is None or credentials.expired:
raise ValueError('Invalid credentials')
return build(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION,
credentials=credentials)
...
status, response = insert_request.next_chunk()
# <HttpError 401 "Unauthorized">
Evidence this can be done
The oauth2client.service_account.ServiceAccountCredentials class is
only used with OAuth 2.0 Service Accounts. No end-user is involved
for these server-to-server API calls, so you can create this object
directly without using a Flow object.
youtube api
Oauth flow docs
https://developers.google.com/identity/protocols/OAuth2#serviceaccount
The problem is that most YouTube data is private user data. Being that it is private user data you must be authenticated as a user who has access to the data in question in order to access it. To do that we use Oauth2 and login to our account and get an access token and a refresh token returned.
The access token can be used to request data from the Youtube Api, the refresh token can be used to request a new access token when ever the access token expires (After an hour)
Normally i would say that you should consider using a service account. Services accounts are dummy users who can be preconfigured with access to user data. Unfortunately the Youtube api does not support service accounts.
What you should be doing and what i have done a number of times in the past is to authenticate your code once. Get the refresh token and save it. In the future whenever you wish to run your application you simply use the refresh token to request a new access token and you will be able to access the api. You wont have to manually type your login and password and consent to the access anymore everything can be done in the background using the refesh token.
Note: You will need to watch it there are some cases that can cause a refresh token to expire but you shouldn't worry for the most part they are good for as long as you continue to use them regularly.
I am not a python dev but found this
from oauth2client import client, GOOGLE_TOKEN_URI
CLIENT_ID = "client_id"
CLIENT_SECRET = "client_secret"
REFRESH_TOKEN = "refresh_token"
credentials = client.OAuth2Credentials(
access_token = None,
client_id = CLIENT_ID,
client_secret = CLIENT_SECRET,
refresh_token = REFRESH_TOKEN,
token_expiry = None,
token_uri = GOOGLE_TOKEN_URI,
token_ id = None,
revoke_uri= None)
http = credentials.authorize(httplib2.Http())
I'm using the Python API that google provides. What I want to do is just make sure that the access token doesn't expire. I have the refresh_token stored in the credentials file. I'm just not sure how to 'check' that the token is still good before making the call to the API and if need be refreshing it and re-storing it in the credentials file.
I did a test that even if I delete the access tokens from the credentials file that it rewrites them into it using the refresh token. I'm hoping that will work for expired access tokens as well.
Thanks
storage = Storage('cred_storage.txt')
credentials = storage.get()
if not 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)
storage.put(credentials)
http = httplib2.Http()
http = credentials.authorize(http)
print http
service = build('admin', 'reports_v1', http=http)
print service
data_query = service.customerUsageReports().get(**{'date':'2015-01-07'})
feed = data_query.execute()
print feed
Simply check the case of expired access token and refresh your expired access token like this:
if credentials.access_token_expired:
credentials.refresh(httplib2.Http())
Tip: While developing this, you can test by editing the access token expiry date in the credentials text file and forcing it to be older than an hour
Also, in your code on the line where you are checking if not credentials:, you can better handle that case with:
if credentials is None or credentials.invalid:
I came across this question while trying to find a way to refresh an access token when construction a credentials object when using from_authorized_user_info. Unfortunately, the following code did not work for me:
credentials.refresh(httplib2.Http())
But I found this documentation from the Oauth library that works wonder. Shared below:
import google.auth.transport.requests
import requests
request = google.auth.transport.requests.Request()
credentials.refresh(request)
I am trying to find a way to authenticate and authorize a client to access APIGEE. I can't seem to get it to function. I am using Python Requests-OAuthlib. Here is my code:
from requests_oauthlib import OAuth2Session
client_id = r'my_client_id'
client_secret = r'my_client_secret'
redirect_uri = 'https://api.usergrid.com/org/app'
oauth = OAuth2Session(client_id, redirect_uri=redirect_uri)
authorization_url, state = oauth.authorization_url('https://api.usergrid.com/org/app/token', grant_type='client_credentials')
redirect_response = raw_input(authorization_url)
token = oauth.fetch_token('https://api.usergrid.com/org/app/token', client_secret=client_secret, authorization_response=redirect_response)
url = "https://api.usergrid.com/org/app/my_collection"
r = oauth.get(url)
I get an error: "Please supply either code or authorization_code parameters."
Any ideas on what I am doing wrong? I am using the APIGEE docs found here: http://apigee.com/docs/app-services/content/authenticating-users-and-application-clients
Thank you in advance.
Your client is sending response_type=code in the authorization request. That is why the server is not performing client credential Oauth.
This could be a default behavior of your python client. In that case you might want to use a simple http client to keep things under control.
I know the title is a big wonky and I apologize for that. The dilemma I have is that gspread uses Session and the Google APIs client library for Python uses HTTPLib2. I have a service account that I have working with the Google API client and want to take the authenticated httplib2.Http() instance and wrap it so that gspread can use it like a Session object.
UPDATE: Fixed with update 103 to gspread. Based on Jay Lee's awesome answer below, here's how to initialize the gspread Client with a service account in Python 2.7 (you will need to replace /path/to/service-account.p12 and set sa_id):
import gspread
from oauth2client.client import SignedJwtAssertionCredentials
from apiclient.discovery import build
# ...
with open('/path/to/service-account.p12') as f: sa_key = f.read()
credentials = SignedJwtAssertionCredentials(
sa_id, sa_key, 'https://spreadsheets.google.com/feeds')
http = httplib2.Http()
http = credentials.authorize(http)
build('drive', 'v2', http = http)
access_token = http.request.credentials.access_token
gspread_auth_headers = {'Authorization' : 'Bearer %s' % access_token}
gspread_session = gspread.httpsession.HTTPSession(headers=gspread_auth_headers)
fakeauth = ('notmyusername#gmail.com', 'notmypassword')
client = gspread.Client(fakeauth, http_session=gspread_session)
# https://github.com/burnash/gspread/issues/103
if False == hasattr(client, "session"):
client = gspread.Client(fakeauth)
client.session = gspread_session
Now you can use client as you normally would. Whew!
A quick look at gspread indicates it's using the old ClientLogin authentication protocol which is deprecated. But you should be able to grab the access token from the httplib2.Http() instance and apply the same header to the gspread session (effectively getting gspread to use OAuth 2.0 also):
http = <<<Your existing, authenticated httplib2.Http() object)>>>
access_token = http.request.credentials.access_token
gspread_auth_headers = {'Authorization': 'Bearer %s' % access_token}
gspread_session = gspread.httpsession.HTTPSession(headers=gspread_auth_headers)
my_gspread = gspread.Client(auth=('notmyusername#gmail.com', 'notmypassword'), http_session=gspread_session)
notmyusername#gmail.com and notmypassword are random strings here, they're only needed because gspread.Client expects auth to be a tuple passed to it and they won't be passed to Google unless you call my_gspread.login() (which you won't).
You will need to watch out for and catch expired access_tokens. If gspread throws an error about invalid tokens, you should catch it, call http.request.credentials.refresh() to get a new access token and then recreate the gspread session with the fresh token.
I am trying to use python to consume some adwords soap API, I am able to get the auth token but when I try to make a get request I got the authenticationerror.login_cookie_required error. Any ideas?
from suds.client import Client
auth_data = {'accountType':'GOOGLE', 'Email':'xxx#xxx.com', 'Passwd':'xxxxxxxx', 'service':'adwords', 'source':'xxxxxxxxxx'}
auth_data = urllib.urlencode(auth_data)
auth_request = urllib2.Request('https://www.google.com/accounts/ClientLogin', auth_data)
auth_response = urllib2.urlopen(auth_request)
auth_response = auth_response.read()
split = auth_response.split('=')
auth_token = split[len(split)-1]
url = 'https://adwords-sandbox.google.com/api/adwords/cm/v201109/CampaignService?wsdl'
client = Client(url)
authToken = auth_token
developerToken = 'xxx#xxx.com++NZD'
userAgent = 'jameslin-python'
client.set_options(soapheaders=(authToken,developerToken,userAgent))
client.service.get()
Have you tried using the Python client library for the AdWords API?
http://code.google.com/p/google-api-ads-python/
authToken isn't a SOAP header. RequestHeader is the soap header and authToken is a member of that header. See http://code.google.com/apis/adwords/docs/headers.html and http://code.google.com/apis/adwords/docs/#soap for more details.
I also wish to point out that AdWords API official forum is http://groups.google.com/group/adwords-api, where we regularly answer questions on AdWords API. If you have any followup questions, feel free to ask on the official forum.
Cheers,
Anash