Im trying to use the youtube analytics API. I already have the access token of the channel stored in some db. In Php, you can build the client and just add the access token, client_id, client_secret then use the client to call youtube analytics.
In the python example however, I saw something like this:
flow = flow_from_clientsecrets(
CLIENT_SECRETS_FILE,
scope=' '.join(YOUTUBE_SCOPES),
message=MISSING_CLIENT_SECRETS_MESSAGE)
storage = Storage('%s-oauth2.json' % sys.argv[0])
credentials = storage.get()
if credentials is None or credentials.invalid:
credentials = run_flow(flow, storage, data)
http = credentials.authorize(httplib2.Http())
yt.analytics = build(
YOUTUBE_ANALYTICS_API_SERVICE_NAME,
YOUTUBE_ANALYTICS_API_VERSION,
http=http)
It authenticates the user using the browser. I don't need to go by that step since I already have the access_token stored in the db. The question is how to use that access_token in the build() function call so that I can proceed with the query below.
analytics_query_response = yt_analytics.reports().query(
ids='channel==',
metrics=options.metrics,
dimensions=options.dimensions,
start_date=options.start_date,
end_date=options.end_date,
max_results=options.max_results,
sort=options.sort,
).execute()
Unfortunately, the build function doesn't have an access_token parameter. Here are the docs.
You can also create your credentials object like this, though (which may be what you are looking for):
from oauth2client.client import GoogleCredentials
from oauth2client import GOOGLE_TOKEN_URI
access_token = YOUR_TOKEN
token_expiry = None
token_uri = GOOGLE_TOKEN_URI
user_agent = 'Python client library'
revoke_uri = None
credentials = GoogleCredentials(
access_token,
client_id,
client_secret,
refresh_token,
token_expiry,
token_uri,
user_agent,
revoke_uri=revoke_uri
)
Related
I am having trouble sending an authenticated firestore REST API request from a cloud function. The request needs to have an oauth2 token in the header. I've followed the docs here https://cloud.google.com/functions/docs/securing/authenticating and tried the python function they provided, but that still does not give the right authentication. What has worked so far is copying the token from gcloud auth application-default print-access-token but that expires after an hour. Any ideas?
import urllib
import google.auth.transport.requests
import google.oauth2.id_token
def make_authorized_get_request(endpoint, audience):
"""
make_authorized_get_request makes a GET request to the specified HTTP endpoint
by authenticating with the ID token obtained from the google-auth client library
using the specified audience value.
"""
# Cloud Functions uses your function's URL as the `audience` value
# audience = https://project-region-projectid.cloudfunctions.net/myFunction
# For Cloud Functions, `endpoint` and `audience` should be equal
req = urllib.request.Request(endpoint)
auth_req = google.auth.transport.requests.Request()
id_token = google.oauth2.id_token.fetch_id_token(auth_req, audience)
req.add_header("Authorization", f"Bearer {id_token}")
response = urllib.request.urlopen(req)
return response.read()
The above function results in aurllib.error.HTTPError: HTTP Error 401: Unauthorized"
The solution in my case was to add datastore.importExportAdmin "Cloud Datastore Import Export Admin" role to the service account that would generate the token. And to use the code below to generate a token from credentials:
credentials = service_account.Credentials.from_service_account_file(
SERVICE_ACCOUNT_FILE, scopes=SCOPES)
request = google.auth.transport.requests.Request()
credentials.refresh(request)
https://cloud.google.com/firestore/docs/security/iam#roles
I am trying to use the following code to insert videos using youtube's API. I have generated my client secret file, however, could not understand how the oauth2.json file is generated.
import httplib2
import os
import sys
from apiclient.discovery import build
from apiclient.errors import HttpError
from oauth2client.client import flow_from_clientsecrets
from oauth2client.file import Storage
from oauth2client.tools import argparser
from oauth2client import tools
# The CLIENT_SECRETS_FILE variable specifies the name of a file that contains
# the OAuth 2.0 information for this application, including its client_id and
# client_secret. You can acquire an OAuth 2.0 client ID and client secret from
CLIENT_SECRETS_FILE = "my_client_secret.json"
# This variable defines a message to display if the CLIENT_SECRETS_FILE is
# missing.
MISSING_CLIENT_SECRETS_MESSAGE = """
WARNING: Please configure OAuth 2.0
To make this sample run you will need to populate the client_secrets.json
file
found at:
%s
with information from the Cloud Console
https://cloud.google.com/console
For more information about the client_secrets.json file format, please
visit:
https://developers.google.com/api-client-
library/python/guide/aaa_client_secrets
""" % os.path.abspath(os.path.join(os.path.dirname(__file__),
CLIENT_SECRETS_FILE))
# This OAuth 2.0 access scope allows for full read/write access to the
# authenticated user's account.
YOUTUBE_SCOPE = "https://www.googleapis.com/auth/youtube"
YOUTUBE_API_SERVICE_NAME = "youtube"
YOUTUBE_API_VERSION = "v3"
def get_authenticated_service():
flow = flow_from_clientsecrets(CLIENT_SECRETS_FILE, scope=YOUTUBE_SCOPE,
message=MISSING_CLIENT_SECRETS_MESSAGE)
storage = Storage("%s-oauth2.json" % sys.argv[0])
credentials = storage.get()
if credentials is None or credentials.invalid:
credentials = tools.run_flow(flow, storage)
return build(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION,
http=credentials.authorize(httplib2.Http()))
def add_video_to_playlist(youtube,videoID,playlistID):
add_video_request=youtube.playlistItem().insert(
part="snippet",
body={
'snippet': {
'playlistId': playlistID,
'resourceId': {
'kind': 'youtube#video',
'videoId': videoID
}
#'position': 0
}
}).execute()
if __name__ == '__main__':
youtube = get_authenticated_service()
add_video_to_playlist(youtube,"yszl2oxi8IY","PL2JW1S4IMwYubm06iDKfDsmWVB-J8funQ")
How do I generate the OATUH2.JSON file?
The file <yourscript>-oauth2.json is used to store credentials (access token, refresh token, id token, token expiration date etc...)
From google API client guide :
The oauth2client.file.Storage class stores and retrieves a single
Credentials object. The class supports locking such that multiple
processes and threads can operate on a single store.
If the file doesn't exist or the credentials in it are invalid the authentication flow is run :
if credentials is None or credentials.invalid:
credentials = tools.run_flow(flow, storage)
Thus, if this file already exists and contains valid credentials, it won't be necessary to request an authorization code (through user registration and user accepting scope) to get a first access token since it will use the existing access token/refresh token in this file to hit Google API.
You can read more about oauth2client.tools.run_flow here
Can anyone provide sample code that would be a working replacement for the code that used the now defunct gdata.docs.client API:
import gdata.docs, gdata.docs.client, gdata
pw = file('pw','r').read()
client = gdata.docs.client.DocsClient()
client.ClientLogin('username#domain.org',pw,None)
Until yesterday, that code worked, but google has finally axed the depreceated ClientLogin API (https://developers.google.com/identity/protocols/AuthForInstalledApps).
In reading over the documentation for the OAuth 2.0 library, it looks like the process is supposed to involve user interaction to finish the authentication process, but I need a script to run in a cronjob on a regular basis without user involvement (we update various parts of our google site using a script on a cronjob).
Current Answer:
Hard-coding authentication for the docs API was possible, but that API is also discontinued, so here's the way to do it for the new, preferred DRIVE API.
credentials = OAuth2WebServerFlow(
client_id = "CLIENT ID",
client_secret = "CLIENT SECRET",
scope = 'https://www.googleapis.com/auth/drive',
user_agent = "HTTP",
access_token = "ACCESS TOKEN",
refresh_token = "REFRESH TOKEN",
)
# Create an httplib2.Http object and authorize it with our credentials
http = httplib2.Http()
# Now it gets ugly
# The authorize method below changes the "request" method of http_client
# Not at all sure why I had to fake this to make it work, but I did --
# I believe this must get set somewhere in the normal gdrive flow which
# we're circumventing with this method. You can see the code that
# requires this fake client here:
# https://code.google.com/p/gdata-python client/source/browse/src/gdata/gauth.py
# at ~line 1324
Class FakeClient:
request = 'Fake'
http.http_client = FakeClient()
http = credentials.authorize(http)
# Create an httplib2.Http object and authorize it with our credentials
http = httplib2.Http()
Class FakeClient:
request = 'Fake'
http.http_client = FakeClient()
http = credentials.authorize(http)
In order to get those credentials, you can use the standard OAuth method described in the google documentation and then just dig into the variables to find all the right information. Here's some code I wrote myself to print it all out:
if NEED_NEW_CREDENTIALS:
CLIENT_ID = 'ID'
CLIENT_SECRET = 'SECRET'
OAUTH_SCOPE = 'https://www.googleapis.com/auth/drive'
REDIRECT_URI = 'urn:ietf:wg:oauth:2.0:oob'
flow = OAuth2WebServerFlow(CLIENT_ID, CLIENT_SECRET, OAUTH_SCOPE,
redirect_uri=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)
print 'Hey buddy -- you better hardcode these new credentials in.'
print 'client_id = "%s"'%credentials.client_id
print 'client_secret = "%s"'%credentials.client_secret
print 'scope = "%s"'%OAUTH_SCOPE
print 'user_agent = "%s"'%credentials.user_agent
print 'access_token = "%s"'%credentials.token_response['access_token']
print 'refresh_token = "%s"'%credentials.token_response['refresh_token']
Ok, I found a better solution in the PyDrive library, which already wraps all of this nicely up for you:
http://pythonhosted.org/PyDrive/
If you set PyDrive to store credentials, it will only make you go through the browser once, then remember the credentials automatically.
You'll need to set up a settings.yaml file that looks like this to work with it:
save_credentials: true
save_credentials_backend: file
save_credentials_file: credentials.txt
client_config_file: client_secrets.json
Once you've done that, and installed your secret in client_secrets.json, the login process is as simple as:
from pydrive.auth import GoogleAuth
gauth = GoogleAuth()
gauth.LocalWebserverAuth()
Then you're working with the PyDrive API, which is pretty friendly to use and well documented here: http://pythonhosted.org/PyDrive/oauth.html#customizing-authentication-with-settings-yaml
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.
I am trying to access the Google My Business API on a flask app, and having trouble. I have set up the O-Auth procedure with an authorize and oauth-callback functions. The oauth claims to have gone through fine, becuase it finishes the oauth-callback function and redirects to the locations method. I added a developer api key to the build function. When I try and build the connection to the api using the build function i get this: googleapiclient.errors.UnknownApiNameOrVersion: name: mybusiness version:
v4. Im pretty sure are the right api details, because in a command line version without oauth that api name and version number works. Im stuck and I think the error message could be a little misleading, maybe something is wrong with my oauth proccess. I am doing is incorrect?
I have tried the google drive api using the same procedure and it worked. I have also made sure the google my business api is enabled in the google developers console.
Here is the authorize function:
#bp.route('/authorize')
def authorize():
# Create flow instance to manage the OAuth 2.0 Authorization Grant Flow steps.
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
CLIENT_SECRETS_FILE, scopes=SCOPES)
# The URI created here must exactly match one of the authorized redirect URIs
# for the OAuth 2.0 client, which you configured in the API Console. If this
# value doesn't match an authorized URI, you will get a 'redirect_uri_mismatch'
# error.
flow.redirect_uri = url_for('google_questions.oauth2callback', _external=True)
code_verifier = generate_code_verifier()
flow.code_verifier = str(code_verifier)
flask.session['code_verifier'] = str(code_verifier)
authorization_url, state = flow.authorization_url(
# Enable offline access so that you can refresh an access token without
# re-prompting the user for permission. Recommended for web server apps.
access_type='offline',
# Enable incremental authorization. Recommended as a best practice.
include_granted_scopes='true')
# Store the state so the callback can verify the auth server response.
flask.session['state'] = state
apobj.notify(title='Auth url',
body=authorization_url)
return redirect(authorization_url)
Here is the oauth-callback function:
#bp.route('/oauth2callback')
def oauth2callback():
# Specify the state when creating the flow in the callback so that it can
# verified in the authorization server response.
state = flask.session['state']
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
CLIENT_SECRETS_FILE, scopes=SCOPES, state=state)
flow.redirect_uri = flask.url_for('google_questions.oauth2callback', _external=True)
flow.code_verifier = flask.session['code_verifier']
# Use the authorization server's response to fetch the OAuth 2.0 tokens.
authorization_response = flask.request.url
flow.fetch_token(authorization_response=authorization_response)
# Store credentials in the session.
# ACTION ITEM: In a production app, you likely want to save these
# credentials in a persistent database instead.
credentials = flow.credentials
flask.session['credentials'] = credentials_to_dict(credentials)
return flask.redirect(flask.url_for('google_questions.locations'))
Here is the creds_to_dict method:
def credentials_to_dict(credentials):
return {'token': credentials.token,
'refresh_token': credentials.refresh_token,
'token_uri': credentials.token_uri,
'client_id': credentials.client_id,
'client_secret': credentials.client_secret,
'scopes': credentials.scopes}
Here is where it chokes in the locations method:
#bp.route('/locations', methods=['GET','POST'])
#roles_required(['Admin'])
def locations():
# Use the discovery doc to build a service that we can use to make
# MyBusiness API calls, and authenticate the user so we can access their
# account
if 'credentials' not in flask.session:
return flask.redirect('authorize')
# Load credentials from the session.
credentials = google.oauth2.credentials.Credentials(
**flask.session['credentials'], developerKey={api-key})
business = googleapiclient.discovery.build(
API_SERVICE_NAME, API_VERSION, credentials=credentials)
These are the scopes and api details defined globally:
SCOPES = ['https://www.googleapis.com/auth/business.manage']
API_SERVICE_NAME = 'mybusiness'
API_VERSION = 'v4'
I expect the api to connect and allow for api requests.
The google-api-python-client looks for a discovery document thats default does not have the mybusiness v4 included. You can find the code here https://github.com/googleapis/google-api-python-client/blob/master/googleapiclient/discovery.py You can specify a discovery document with the discoveryServiceUrl parameter. set it to this:
discoveryServiceUrl='https://developers.google.com/my-business/samples/mybusiness_google_rest_v4p5.json'
your full build should look like this:
business = googleapiclient.discovery.build(
API_SERVICE_NAME, API_VERSION, credentials=credentials, discoveryServiceUrl='https://developers.google.com/my-business/samples/mybusiness_google_rest_v4p5.json')