I'm attempting to utilize the google content api for shopping to add/update products in my google merchant account.
It appears that I'm having some problems with OAuth.
Thanks in advance for the help!
Example Code
f = file("key.p12", 'rb')
CLIENT_SECRET = f.read()
f.close()
ACCOUNT_ID = 'xxxxxxx'
CLIENT_ID = 'xxxxxxxxx.apps.googleusercontent.com'
SERVICE_ACCOUNT_EMAIL = 'xxxxxxxx#developer.gserviceaccount.com'
SCOPE = 'https://www.googleapis.com/auth/structuredcontent'
USER_AGENT = 'content-api-example'
credentials = SignedJwtAssertionCredentials(
SERVICE_ACCOUNT_EMAIL,
CLIENT_SECRET,
scope=SCOPE)
http = httplib2.Http()
http = credentials.authorize(http)
auth_token = gdata.gauth.OAuth2TokenFromCredentials(credentials)
entry = gdata.contentforshopping.data.ProductEntry()
...
shopping_client.InsertProduct(entry)
Output
auth2client.client.AccessTokenRefreshError: invalid_grant
It looks like you are using a Service Account to access the API. Make sure you login to the respective Google Merchant Center account you are trying to access and add the Service account email generated from the Google Developer Console (in your code, this is the value within SERVICE_ACCOUNT_EMAIL") to the "Settings > Users" section and grant this email address "standard" or "administrative" access depending on the scope you are requesting.
This is an often missed step and not called out specifically in Google's documentation.
Hope this helps
Related
Libs: dj-rest-auth + allauth
I. I'm trying to interact with google API with credentials that I use to obtain internal access token. I managed to obtain both code and token but can't find how to use them with google API. The last page I found inapplicable is https://github.com/googleapis/google-api-python-client/blob/main/docs/oauth.md but probably I'm missing some things.
Here's the view I'm trying to use google API in:
class CreateGoogleDoc(GenericAPIView):
...
def get(self, request):
token = request.query_params['token']
module_dir = os.path.dirname(__file__) # get current directory
file_path = os.path.join(module_dir, 'client_secret.json')
flow = Flow.from_client_secrets_file(
file_path,
scopes=SCOPES,
redirect_uri='https://example.com'
)
credentials = service_account.Credentials.from_service_account_file(file_path, scopes=SCOPES)
service = build('docs', 'v1', credentials=credentials)
document = service.documents().create().execute()
return Response([document['documentId']])
II. While I tried to swap code to internal access token class I got another error:
Error retrieving access token: `{ "error": "invalid_request", "error_description": "You can't sign in to this app because it doesn't comply with Google's OAuth 2.0 policy for keeping apps secure. You can let the app developer know that this app doesn't comply with one or more Google validation rules."}`
Here's a view that I'm using for swapping:
GoogleLogin(SocialLoginView):
adapter_class = GoogleOAuth2Adapter
callback_url = 'http://localhist:8000/dj-rest-auth/google/'
client_class = OAuth2Client
Thanks!
Offering a workaround
If you already have a token from the GET response, why are you trying to get credentials from a service account file? Probably there is some wrong configuration there, but if you already have the access token, you can just use it like below and avoid the whole service account token fetching.
from google.oauth2.credentials import Credentials
# ...
def get(self, request):
token = request.query_params['token']
credentials = Credentials(token)
service = build('docs', 'v1', credentials=credentials)
document = service.documents().create().execute()
return Response([document['documentId']])
I am trying to fetch the calendar events from my personal premium outlook account. It is not a work account.
I have a office 365 subscription. Using the same, I have setup Azure actuve directory where I have added my python web application, granted all the required permissions to the app. While accessing the API via web app I am able to fetch profile details, users and all, but unable to get data related to events, calendar etc.
I am getting this error - "message": "The tenant for tenant guid \u00*******b5d-*9-4b-b1-c5c***2ec8\u0027 does not exist."
I looked at many solutions on msdn and also on stackoverflow, but everyone told to get a premium account which I did but still the issue is not resolved.
Please help resolving the same. Thankyou in advance :)
I am attaching the copy of my app.config file for your reference.
import os
CLIENT_SECRET = "client secret key"
AUTHORITY = "https://login.microsoftonline.com/tenant id"
CLIENT_ID = "client id"
REDIRECT_PATH = "/getAToken"
ENDPOINT =ENDPOINT = 'https://graph.microsoft.com/v1.0/users/{my id}/events
# I also tried 'ENDPOINT = ' 'https://graph.microsoft.com/v1.0/users/{my id}/calendar/events''
SCOPE = ["User.ReadBasic.All"]
SESSION_TYPE = "filesystem" # So token cache will be stored in server-side session
use 'Oauth' class of python to pass all your token and ADD details like client id, client secret etc.
Something like this -
(Note config files contains all my details mentioned above.)
OAUTH = OAuth(APP)
MSGRAPH = OAUTH.remote_app(
'microsoft',
consumer_key=config.CLIENT_ID,
consumer_secret=config.CLIENT_SECRET,
request_token_params={'scope': config.SCOPES},
base_url=config.RESOURCE + config.API_VERSION + '/',
request_token_url=None,
access_token_method='POST',
access_token_url=config.AUTHORITY_URL + config.TOKEN_ENDPOINT,
authorize_url=config.AUTHORITY_URL + config.AUTH_ENDPOINT)
my config file :
CLIENT_ID = 'put here'
CLIENT_SECRET = 'put here'
REDIRECT_URI = 'http://localhost:5000/login/authorized'
AUTHORITY_URL = 'https://login.microsoftonline.com/common'
AUTH_ENDPOINT = '/oauth2/v2.0/authorize'
TOKEN_ENDPOINT = '/oauth2/v2.0/token'
RESOURCE = 'https://graph.microsoft.com/'
API_VERSION = 'v1.0'
SCOPES = ['User.Read', 'Mail.Send', 'Files.ReadWrite','Calendars.Read', 'Calendars.ReadWrite']
now you can call the get events like this :
eventResponse = MSGRAPH.get('me/events',headers=request_headers()) #request_headers() return all the requeried headers
print(eventResponce.data)
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'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)