So I am attempting to crawl a user's activity stream for a research project using python and am currently running into issues making calls to the API.
Per the API documentation I have my scope set to https://www.googleapis.com/auth/plus.stream.read
and https://www.googleapis.com/auth/plus.me however whenever I try to make a call I get an error kicked back that reports a scope issue.
Has anybody experienced this issue and/or have a hot tip on how to go about getting around it?
from oauth2client.client import flow_from_clientsecrets
import webbrowser
import httplib2
from apiclient.discovery import build
service = build('plus', 'v1')
if __name__ == '__main__':
print 'Running oauth script'
flow = flow_from_clientsecrets('client_secret.json',
scope='https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/plus.stream.read',
redirect_uri='urn:ietf:wg:oauth:2.0:oob')
auth_uri = flow.step1_get_authorize_url()
webbrowser.get().open_new(auth_uri)
auth_code = raw_input('Enter the auth code: ')
credentials = flow.step2_exchange(auth_code)
http_auth = credentials.authorize(httplib2.Http())
http = httplib2.Http()
http = credentials.authorize(http)
activities_resource = service.activities()
request = activities_resource.list(userId = id_list.readline().split('\n'), collection = 'user', maxResults = '20' )
(Note: Obviously there's more to my code but this is what I think is the relevant bits. I think its also worth stating that I know this is python and indentation matters but please assume any obvious errors in indentation are a result of me copying and pasting as I have not mastered the art of formatting code on this site.)
Related
first time using OAuth here and I am stuck. I am building a web app that needs to make authorized calls to the YouTube Data API. I am testing the OAuth flow from my local computer.
I am stuck receiving Error 400: redirect_uri_mismatch when I try to run my Google OAuth flow in Python. The error occurs when I access the link generated by flow.run_console()
Here is my code:
os.environ["OAUTHLIB_INSECURE_TRANSPORT"] = "1"
client_secrets_file="./client_secret.json"
scopes = ["https://www.googleapis.com/auth/youtube.readonly"]
flow = google_auth_oauthlib.flow.InstalledAppFlow.from_client_secrets_file(
client_secrets_file, scopes)
flow.redirect_uri = "http://127.0.0.1:8080" # Authorized in my client ID
credentials = flow.run_console()
This code returns the message:
Please visit this URL to authorize this application: ***google oauth url ***
Enter the authorization code:
Visiting the link results in the following error:
I tried setting the Authorized Redirect URI in my OAuth Client ID to http://127.0.0.1:8080 since I am testing from my local machine. I also set flow.redirect_uri to http://127.0.0.1:8080 in Python. Using http://127.0.0.1:8080 is currently my only option since the front end has not been set up yet.
I expected the code to authorize my request, since the Authorized URI matches the redirect_uri. But I am still receiving the error.
I have had no issues running the flow from Google's OAuth Playground, if that means anything.
Any help is appreciated, thank you.
Thanks for your help everyone. I was able to find a working solution for my issue from referencing this documentation: https://googleapis.github.io/google-api-python-client/docs/oauth.html
Here is my solution:
def get_subscribers(channel_id="Channel_id",
client_secrets_file="Client_secret_file", n=50):
os.environ["OAUTHLIB_INSECURE_TRANSPORT"] = "1"
flow = Flow.from_client_secrets_file(
client_secrets_file,
scopes=["https://www.googleapis.com/auth/youtube.readonly"])
flow.redirect_uri = "http://localhost"
auth_url, __ = flow.authorization_url(prompt="consent")
print('Please go to this URL: {}'.format(auth_url))
code = input('Enter the authorization code: ')
flow.fetch_token(code=code)
youtube = googleapiclient.discovery.build(
"youtube", "v3", credentials=flow.credentials
)
request = youtube.subscriptions().list(
part="subscriberSnippet",
forChannelId=channel_id,
maxResults=n,
mySubscribers=True
)
return request.execute()
Change redirect_uri to http://127.0.0.1/ or http://localhost/. I have faced a similar issue before with Google Drive API, and removing the port number worked for me.
The library seems to have a bug.
I know it is not so good but in this case the hack is
flow._OOB_REDIRECT_URI = = "http://127.0.0.1:8080"
are you sure this is definitely your redirect uri? go to your client_secrets.json you downloaded when generating your credentials from the API centre and your redirect uris are in there, http://localhost (NOTE - without the trailing slash!) was specified in mine by default - if it isnt in yours then use the one specified in the json.
I'm attempting to use Youtube's Reporting API to access my company's Youtube data and analyze it. However, when I run an example script that Google has supplied, I receive the follow error:
HttpError: <HttpError 403 when requesting https://youtubereporting.googleapis.com/v1/media/%20?alt=json returned "The caller does not have permission">
I've created an Oauth 2.0 client ID, downloaded the client secrets file, and pointed the script to that. I am also being redirected to Google's authorization page, where I log in to the Youtube account that I'm trying get data from and authorize the script. For reference, the scope I'm using is:
https://www.googleapis.com/auth/yt-analytics-monetary.readonly
This is my first time trying to use Google's API so I'm sure I'm missing something, but I can't seem to figure it out. If anyone could offer some guidance I'd really appreciate it.
Edit: I've included the code that I'm using from Google's sample script below.
import urllib
import json
import os
from io import FileIO
import google.oauth2.credentials
import google_auth_oauthlib.flow
from oauth2client import client
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.http import MediaIoBaseDownload
def get_service():
flow = InstalledAppFlow.from_client_secrets_file(client_secrets_file=client_secrets, scopes=scope)
credentials = flow.run_console()
return build(api_service_name, api_version, credentials = credentials)
def execute_api_request(client_library_function, **kwargs):
response = client_library_function(**kwargs).execute()
print(response)
scope = ['https://www.googleapis.com/auth/yt-analytics-monetary.readonly']
api_service_name = 'youtubereporting'
api_version = 'v1'
client_secrets = 'client_secret_397754690264-ba1rtbpi731qkveqb11361q4ggui2bmd.apps.googleusercontent.com.json'
youtube_analytics = get_service()
youtube_analytics.jobs().create(body={'reportTypeId':'channel_combined_a2', 'name':'test_job'}).execute()
# this lists all the reports that are generated after you've created a job
# so it might take a while before you're able to get list a report
youtube_analytics.jobs().reports().list(jobId = job_id).execute()
# this uses a reportId from one of the reports that are listed above
report_url = youtube_analytics.jobs().reports().get(jobId = job_id, reportId = 'REPORTIDGOESHERE').execute()['downloadUrl']
request = youtube_analytics.media().download(resourceName = " ")
request.uri = report_url
fh = FileIO('yt_test.txt', mode='wb')
downloader = MediaIoBaseDownload(fh, request, chunksize=-1)
done = False
while done is False:
status, done = downloader.next_chunk()
if status:
print('Download %d%%.' % int(status.progress() * 100))
print('Download Complete!')
Edit #2: Just wanted to update this with a solution that I found for anyone that might stumble upon it.
The problem was that I wasn't setting the request's uri with a report url that's created when you create a job that in turn generates a report. I was under the assumption that this was its own report, but actually this is just the method in which you download said reports. So, I went ahead and created a job which generated a report. Then, I grabbed the "downloadUrl" from the reports metadata, set the request's uri as the url, and ran the downloader as usual. I've updated the code above to reflect this.
Adding this so I can mark it as answered. My solution is below:
The problem was that I wasn't setting the request's uri with a report url that's created when you create a job that in turn generates a report. I was under the assumption that this was its own report, but actually this is just the method in which you download said reports. So, I went ahead and created a job which generated a report. Then, I grabbed the "downloadUrl" from the reports metadata, set the request's uri as the url, and ran the downloader as usual. I've updated the code above to reflect this.
I built a Python 3.4 Web Application calling Google Analytics API.
class GA:
def __init__(self):
self.scope = ['https://www.googleapis.com/auth/analytics.readonly']
self.service_account_email = 'my_account_email'
self.key_file_location = 'my_key_location'
self.ga_id = 'my_ga_id'
def get_service(self, api_name = 'analytics', api_version = 'v3'):
f = open(self.key_file_location, 'rb')
key = f.read()
f.close()
credentials = SignedJwtAssertionCredentials(self.service_account_email, key,scope=self.scope)
http = credentials.authorize(httplib2.Http())
service = build(api_name, api_version, http=http)
self.service = service
return (service)
ga = GA()
ga.get_service()
It works perfectly without proxy
but I need to set it up on a windows server running behind a corporate proxy. So I tried to replace the http object by :
p = httplib2.proxy_info_from_url("http://username:pwd#myproxyname:80")
http = credentials.authorize(httplib2.Http(proxy_info=p))
But it doesn't work. So I also tried with :
os.environ['HTTP_PROXY']="http://username:pwd#myproxyname:80"
p = httplib2.proxy_info_from_environment(method='http')
http = credentials.authorize(httplib2.Http(proxy_info=p))
But it is not working either. I checked all the related questions without success. I always get a TimeoutError: [WinError 10060]
For those who are interesting, I decided to recode my web app in Python 2 ; still using httplib2 package;
The same code works (proxy info are taken into account contrary to Python 3)
I've just come across this question and it's relevant to a solution I've implemented in Python 3.6.
I tried a number of different methods but the only one that httplib2 seems to recognize the proxy is through modifying the http_proxy environment variable
I've also had to remove SSL validation since that was the only way I could get this working. I wouldn't recommend this approach, unless you trust the domain you're requesting from won't be compromised.
os.environ["https_proxy"] = "https://PROXY_URL:PROXY_PORT"
http = credentials.authorize(http=httplib2.Http(disable_ssl_certificate_validation=True))
This approach also works for the initial request to the authorization/discovery URL's, but fails later on if you need to request information from the API. I was above to dig into the google analytics api source code before I found a much simpler solution (above)
# http = credentials.authorize(http=httplib2.Http(proxy_info=httplib2.ProxyInfo(httplib2.socks.PROXY_TYPE_HTTP, "PROXY_URL", PROXY_PORT), disable_ssl_certificate_validation=True))
huberu, your code worked fine, you helped me a lot!
Blessings for you and your family!
If someone needs to test, you can use the code bellow to simulate a proxy connection:
import httplib2
import os
os.environ['https_proxy'] = '127.0.0.1:80'
http = httplib2.Http(disable_ssl_certificate_validation=True)
resp, content = http.request('http://google.com', 'GET')
print(resp)
print(content)
I'm attempting to write a Python script to create a Spotify playlist via the Spotipy application. I've successfully created an application in Spotify's Dev center and input the necessary variables into Spotipy's example (see below). However, the script is not authorizing properly. I've tried with and without a server running, but to no avail. There are similar questions on Stack but they do not offer complete solutions. Any suggestions would be very helpful.
Here is the message I am receiving via command prompt:
User authentication requires interaction with your
web browser. Once you enter your credentials and
give authorization, you will be redirected to
a url. Paste that url you were directed to to
complete the authorization.
Please navigate here:
https://accounts.spotify.com/authorize?scope=user-library-read&redirect_uri=None&response_type=code&client_id=xxxxx
Enter the URL you were redirected to:
And here is the script that's running. It's nearly identical to that example provided by Spotipy, with a change made for setting os variables for my Windows machine.
import pprint
import sys
import os
import subprocess
import spotipy
import spotipy.util as util
import requests
clientId = 'client id here'
clientSecret = 'client secret here'
clientRedirect = 'http://localhost:8888/callback'
username = 'username here'
scope='user-library-read'
os.environ["SPOTIPY_CLIENT_ID"] = clientId
os.environ["SPOTIPY_CLIENT_SECRET"] = clientSecret
os.environ["POTIPY_REDIRECT_URI"] = clientRedirect
token = util.prompt_for_user_token(username, scope)
if token:
sp = spotipy.Spotify(auth=token)
results = sp.current_user_saved_tracks()
for item in results['items']:
track = item['track']
print track['name'] + ' - ' + track['artists'][0]['name']
else:
print "Can't get token for", username
The application is asking a URL that should contain a "code" which will then be used to exchange with access_token as mentioned in Step.3 in https://developer.spotify.com/web-api/authorization-guide/ and the URL should look like this https://example.com/callback?code=NApCCg..BkWtQ&state=profile%2Factivity. I hope you are entering your credentials properly otherwise you will never get the code to proceed further.
I've been having trouble over the past few days using the Google Directory API in the Admin SDK for Google Apps. The documentation leaves a lot to be desired and when I contacted Google Apps Enterprise support they indicated they do not support the API. I am using the most recent Python API client library provided by Google as they suggest this is the best way to go. I've logged in to the Google API Console and created a Service Account and downloaded the OAuth2 key. I've also turned on the Admin SDK in the console. Here is my code:
f = file("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-privatekey.p12", "rb")
key = f.read()
f.close()
credentials = SignedJwtAssertionCredentials(
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx#developer.gserviceaccount.com",
key,
scope = "https://www.googleapis.com/auth/admin.directory.orgunit"
)
http = httplib2.Http()
http = credentials.authorize(http)
directoryservice = build("admin", "directory_v1", http=http)
orgunits = directoryservice.orgunits().list(customerId='XXXXXXX').execute(http=http)
pprint.pprint(orgunits)
Note that customerId is our Google Apps customer ID. I tried it with "my_customer" as Google seems to indicate should work when using an account that is super admin, but I receive the return "invalid customerId" when I try it that way. So I hardcoded our actual customerId.
When harcoded always receive the return "Login Required" but it seems as if the authentication process is working as the directory object gets created via the build command. Am I doing something wrong?
Note, I also read somewhere that sometimes the request needs to come from a domain account rather than the Service Account and to do this you need to add:
sub = "domain_account_superadmin#example.com"
In the SignedJwtAssertionCredentials call... which I tried, but then receive the message "access_denied"
Thanks in advance for suggestions.
See the google drive example here: https://developers.google.com/drive/delegation
Don't forget to delegate domain wide authority for the service account and scopes.
Here is an example for listing organization units via service account:
import sys
import apiclient.discovery
import oauth2client.client
import httplib2
import pprint
# see example for using service account here:
# https://developers.google.com/drive/delegation
def main (argv):
scopes = ('https://www.googleapis.com/auth/admin.directory.orgunit')
service_account_email = 'xxx#developer.gserviceaccount.com'
acting_as_user = 'yyy#zzz' # must have the privileges to view the org units
f = file('key.p12', 'rb')
key = f.read()
f.close()
credentials = oauth2client.client.SignedJwtAssertionCredentials(
service_account_email,
key,
scope=scopes,
sub=acting_as_user
)
http = httplib2.Http()
http = credentials.authorize(http)
directoryservice = apiclient.discovery.build('admin', 'directory_v1', http=http)
response = directoryservice.orgunits().list(customerId='my_customer').execute(http=http)
pprint.pprint(response)
if __name__ == '__main__':
main(sys.argv)