I am attempting to get access to a customer's Google Drive to download their files. When testing the code on my own google drive, I am able to successfully download files. However, when I get the oauth code from them, I get the error:
oauth2client.client.FlowExchangeError: invalid_grant
After looking at some of the other answers, it has been suggested that you ensure access_type='offline', which seems to be the default and I can see in the generated url that this parameter is set. It also sounds like the code they give back may only be valid for an hour, however I have tried to use it within the hour and still no luck. Any other suggestions for how to avoid this problem?
Here is the code I have been running:
from oauth2client import client
import webbrowser
flow = client.flow_from_clientsecrets(
'client_secrets.json',
scope='https://www.googleapis.com/auth/drive.readonly',
redirect_uri='urn:ietf:wg:oauth:2.0:oob')
auth_uri = flow.step1_get_authorize_url()
webbrowser.open(auth_uri)
print auth_uri
auth_code = raw_input('Enter the auth code: ')
credentials = flow.step2_exchange(auth_code)
http_auth = credentials.authorize(httplib2.Http())
It errors on the flow.step2_exchange line.
There are three standard causes for this error that I am aware of.
The time is off on your PC. Solution: check it.
You are trying to use an authentication code more then once.
You can only use the authentication code once to get the refresh token.
You are testing and authenticating the code more then once. Each time you authenticate the code you get a valid refresh token. You can get up to 25 refresh tokens and then they stop working. Solution: make sure that every time you refresh the access you are using that refresh token and not an older one.
Also google as a Python tutorial that shows you how to access drive using the Python Client library it may make things easer for you. Python QuickStart
Related
I need to use the ezsheets module which requires the use of both Google Drive and Google Spreadsheets APIs. I enabled them and have managed to gain the required credentials, which I passed in the python project folder.
According to Google Spreadsheets documentation, the next step should be gaining the two required token files ( one for each API ) in the same directory where the credentials is placed. Allegedly, you're supposed to do this by simply typing
import spreadsheets
However, when I do this, the thing that pops up instead of an authentication window, is an error message
In Pycharm console, the message that pops up is as follows :
Please visit this URL to authorize this application: https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=934755340326-1qlpikthrsdblrrnodqea6k4kjtiugfb.apps.googleusercontent.com&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2F&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fspreadsheets&state=yxr0mqsA7K0qxoJ2gaCtVrJyA8Cf87&access_type=offline
So I tried changing the OAuth 2.0. client authorized redirect URI to the link python gave out in the aforementioned message. However, nothing changed. Then I changed it to the http://localhost:8080 ( since the error message gave this one out ), but the problem persists.
Is there any way I can solve this problem, or acquire the token files in literally any other way ? I would be immensely thankful if anyone could help me out with this, as it prevents me to progress any further, which is detrimental for a beginner such as myself.
EDIT: I also added the JSON credentials file to system variables. It didn't change the result of the import ezsheets command.
You have run your code with a redirect uri of http://localhost:8080/ but you have not added http://localhost:8080/ as a valid redirect URI in Google Developer console.
You need to go to Google Developer console for your Web credentials and edit that and set the redirect uri properly
Here is an example of how to add the redirect uri How to add redirect URI. Remember it must match exactly, that means the / at the end is important.
I am trying to hit microsoft to do list api using python program.
Api : https://graph.microsoft.com/beta/me/todo/lists , which resulted in error : Access is denied due to invalid credentials. But when I tried the api : https://graph.microsoft.com/v1.0/users, I am getting the results properly. The documentation of the api (https://learn.microsoft.com/en-us/graph/api/resources/todo-overview?view=graph-rest-beta) says "Currently, the API supports only permissions delegated by the signed-in user". Currently I am trying to get auth code and then auth token and then hitting the API. To act as signed in user, what method should I follow in python? Please note I am not using a web frame work. When I tried using flask and then hitting the API , it works. Need to know how a browserless console python application can serve the purpose.
Thank youin advance for the help
You are getting an App only token using a client credential flow and it doesn't ask for user credentials. Please check these Authentication flows and according to your requirement you can choose one of these and implement it. In other ways you can test your HTTP call in Graph Explorer by adding permissions there itself. Your call works here because you will login as user.
I've created a simple Python program using Spotipy that shows some recommended tracks based on the tracks downloaded in the user device. But I'm having some trouble on making the program user-friendly.
First of all, is there any problem by sharing my Client ID and my Client Secret with the user by, for example, uploading my code in GitHub? Can I use Redirect URI as being http://localhost/ or should I create a website for my program for securing purposes? In Username field, it should be the username of the account to be analyzed or it can be anything, like "Brian Rogers"?
In the authentication part, it shows the user in Python console the following message:
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.
Opening https://... in your browser
Enter the URL you were redirected to:
My question is: since I'm managing to use Tkinter, how can I redirect the input from the Tkinter input box to the Python console?
Finally, how long does the authentication token take to expire? And if so, how to renew it (if possible, so that only the user enters when they run the program for the first time)?
Thanks in advance for the patient!
I'll address all your questions one by one.
is there any problem by sharing my Client ID and my Client Secret with the user by, for example, uploading my code in GitHub?
One should always avoid putting personal credentials in the source. If someone misuses your credentials, you'll be the one who will be held responsible because they are YOUR credentials. In any case, the only havoc I can imagine one could cause is to spam requests to Spotify's API which I believe Spotify's API already has protections and will drop further requests if it detects request spam. I've had and seen some projects put their Spotify and YouTube API credentials by creating special accounts for generating API credentials for their projects, in their source code and push to GitHub to make the tool easier to setup for use.
Can I use Redirect URI as being http://localhost/ or should I create a website for my program for securing purposes? In Username field, it should be the username of the account to be analyzed or it can be anything, like "Brian Rogers"?
As you're only searching for relevant tracks on Spotify, I believe you probably don't need to access the personal information of the Spotify user whose credentials you are using. If so, you can avoid both passing the username and verifying the redirect URI, by using oauth2.SpotifyClientCredentials to authorize yourself:
import spotipy
import spotipy.oauth2 as oauth2
credentials = oauth2.SpotifyClientCredentials(
client_id=client_id,
client_secret=client_secret)
token = credentials.get_access_token()
# This won't prompt for verification of Redirect URI
sp = spotipy.Spotify(auth=token)
My question is: since I'm managing to use Tkinter, how can I redirect the input from the Tkinter input box to the Python console?
You won't need to, if you use oauth2.SpotifyClientCredentials as mentioned above.
Finally, how long does the authentication token take to expire? And if so, how to renew it (if possible, so that only the user enters when they run the program for the first time)?
As of writing this, the token stays valid for exactly one hour. You can confirm by checking the value of credentials.token_info["expires_in"] which displays the time in seconds.
Also, spotipy raises spotipy.client.SpotifyException when a dependent method has been called but the token has already expired. So, you could catch this exception and overwrite your previous spotipy.client.Spotify instance with a new one. At the minimal you would do something similar to this:
import spotipy
import spotipy.oauth2 as oauth2
def authenticate_calls():
credentials = oauth2.SpotifyClientCredentials(
client_id=client_id,
client_secret=client_secret,
)
token = credentials.get_access_token()
sp = spotipy.Spotify(auth=token)
return sp
sp = authenticate_calls()
try:
do_something_that_needs_authentication(sp)
except spotipy.client.SpotifyException:
sp = authenticate_calls()
do_something_that_needs_authentication(sp)
You could also create a decorator function which would refresh the token if expired and decorate your functions with it!
I am currently working on some code that connects to our Google apps domain, makes some administrative changes and then impersonates different users in our domain and uploads data to their drive, email and calendar. What I'm trying to do is figure out the proper way to use SignedJwtAssertionCredentials and change the "sub" kwarg. Do I need to redo the whole oauth process for each user I want to impersonate, i.e...
http = httplib2.Http()
credentials = SignedJwtAssertionCredentials(service_account, key, scope=api_scopes, sub=current_user)
http = credentials.authorize(http)
service = build(api_service, api_version, http=http)
or is there a way to just update/modify the sub kwarg and then re-authorize the httplib2 object?
I tried doing it the first way I described and it doesn't seem to work, about half way through the programs execution, I start getting odd errors saying,
WARNING:oauth2client.util:new_request() takes at most 1 positional argument (2 given)
Does anyone have any ideas on why I'm getting this error and or the best way I can implement the oauth process to do what I need it to?
Thanks!
I'm working on converting a Python script using the Google gdata API client + user/pass authentication to something more suitable for production (an API key). I am pretty frustrated with the muddled state of their documentation on authentication. I admittedly don't have a great grasp of OAuth2, but it seems like it's way more complicated for my usage case, which is: Hit Google Analytics every 24 hours to get the X most popular articles on our site.
In this scenario, we're not dealing with modifying someone's personal data, and all activity is centered on one account. It doesn't seem like OAuth2 is worth the complexity for something so simple.
I see that on the Google API Console (https://code.google.com/apis/console/), I've registered there and notice that there's a "Simple API Access" section with one key beneath the "Client ID for web applications" (which appears to be OAuth2). There's also the Google domain update page, https://www.google.com/accounts/UpdateDomain, but that appears to be OAuth related.
Is there any way to use this Simple API Access key (not OAuth) for retrieving analytics data with the Python gdata client, and if so, does anyone have any authentication examples? I already have the data retrieval stuff working once authenticated, but I'm using the user/pass approach, which is not appropriate for production.
Greg,
If you are already using the library gdata-python-client, this is relatively easy to do if you are the only user that your application will be authorizing.
The general mechanisms were detailed in a blog post in September, 2011, but I'll describe them here for completeness.
Part 1: Go to the APIs console and start a new project.
Part 2: From the project, go to "Services" and enable "Analytics API"
Part 3: From the project, go to "API Access" and click "Create an OAuth 2.0 client ID..." (you'll need to provide a product name, though the value you provide won't matter). When asked for the application type, select "Installed Application" and then "Create client ID". Since you will be the only user, you will only need one refresh token, and you can get this by authorizing from a desktop application a single time.
Part 4: Get your client id and client secret from the APIs console and then create an empty token:
import gdata.gauth
CLIENT_ID = 'id-from-apis-console'
CLIENT_SECRET = 'secret-from-apis-console'
SCOPE = 'https://www.google.com/analytics/feeds/' # Default scope for analytics
token = gdata.gauth.OAuth2Token(
client_id=CLIENT_ID,
client_secret=CLIENT_SECRET,
scope=SCOPE,
user_agent='application-name-goes-here')
I got the scope from GData FAQ, though I'm not sure if it is correct.
Part 5: Use the token to create authorization URL for you to visit:
url = token.generate_authorize_url(redirect_uri='urn:ietf:wg:oauth:2.0:oob')
Since your application is an "Installed Application", your redirect URI is the default 'urn:ietf:wg:oauth:2.0:oob'. (Also note, the blog post had a typo and used the keyword argument redirect_url.)
Part 6: Visit the url and authorize your application to make requests on behalf of your account. After authorizing, you'll be redirected to a page with a code on it. This code will be used to exchange for an access token and a long-lived refresh token. The code has a life of 10 minutes and the access token has a life of an hour. The refresh token will allow you to get new access tokens for signing requests in perpetuity (or until you revoke the permission from your account).
Part 7: Use the code to get an access token:
code = 'random-string-from-redirected-page'
token.get_access_token(code) # This returns the token, but also changes the state
This again differs slightly from the blog post, because we are using an installed application.
Part 8: With the token you can now make all requests you want to make to the analytics client:
import gdata.analytics.client
client = gdata.analytics.client.AnalyticsClient()
token.authorize(client)
This is the big money right here. When an access token expires, the API requests signed with that token are rejected. However, by authorizing the client as above, when the said requests fail, the token attempts to use the refresh token to obtain a new access token. If it successfully obtains a new access token, the client resends the original API request, signed with the new access token.
I don't know anything about the Analytics API so I won't provide any more details there.
Future Use Note 1: Saving information for future use. You can re-use this from different places and after this use very easily. There are methods called token_to_blob and token_from_blob provided by the library that allow turning a token into a string and converting out of a string:
saved_blob_string = gdata.gauth.token_to_blob(token)
Once you have done this, you can store the string in a file and kill your running Python process. When you'd like to use it again:
saved_blob_string = retrieve_string_from_file() # You'll need to implement this
token = gdata.gauth.token_from_blob(saved_blob_string)
Future Use Note 2: This token will be able to be used to authorize a client and perform all your magic again and again, so long as you have the refresh token around. If for some reason you would like to get an access token again without calling token.generate_authorize_url, you'll need to manually set this on the object:
token.redirect_uri = 'urn:ietf:wg:oauth:2.0:oob'
Future Use Note 3: Also, if you lose your refresh token and would like to get another one without having to go to the browser to revoke the original, you can use the approval_prompt parameter to get a new refresh token by visiting the url generated by:
url = token.generate_authorize_url(
redirect_uri='urn:ietf:wg:oauth:2.0:oob',
approval_prompt='force')