I am trying to set up a django app which needs access to my own (not a user's) google calendar. I'd rather not have to go through the whole oauth process just to do this, so I set up my authentication in a file (called calendar.dat) in the same directory as the django view which uses my calendar. The code to authorize my account is as follows:
import os.path
import httplib2
from oauth2client.file import Storage
module_dir = os.path.dirname(__file__)
file_path = os.path.join(module_dir, 'calendar.dat')
storage = Storage(file_path)
credentials = storage.get()
http = hhtplib2.Http()
http = credentials.authorize(http)
When this code runs through a call from the browser I get the error that credentials = None. However, if I put this code in a normal python file in the same directory and just run it in the terminal it works. Is there something about django that is messing this up and is there a way I can fix this? Somewhat of a beginner, sorry if this is a novice question.
Related
I can't seem to get the EMBED-API Server-side Authorization demo to work:
https://ga-dev-tools.appspot.com/embed-api/server-side-authorization/
In the demo it says the following:
Once the library is installed you can add the following python module
to your project and invoke the get_access_token() method to get an
access token that you can use to authorize the Embed API.
# service-account.py
from oauth2client.service_account import ServiceAccountCredentials
# The scope for the OAuth2 request.
SCOPE = 'https://www.googleapis.com/auth/analytics.readonly'
# The location of the key file with the key data.
KEY_FILEPATH = 'path/to/json-key.json'
# Defines a method to get an access token from the ServiceAccount object.
def get_access_token():
return ServiceAccountCredentials.from_json_keyfile_name(
KEY_FILEPATH, SCOPE).get_access_token().access_token
I've succesfully done all the previous steps, but this one I just can't get my head around. Where do I put this code? It seems as if it should be put in a .py file.
Can someone please help?
It depends on your implementation, but basically you want to run your service account code on your server, and have the access token passed to your client application so it can make authorized requests from the browser.
The whole app is open sourced and you can see where the service account code is in the source code.
As in the demo, if you are using django or app engine it is easy to put python server code in your site which will return the token and replace the value in template code.
Add that code in service-account.py file and upload it on your server using FTP. I saved the code using dreamweaver, updated the path and added following line at the end of the service-account.py file:
print get_access_token()
Upload .JSON file in same directory and ran the command python service-account.py to get access_token.
I'm having issues with the Directory API + Service Accounts (Google APIs). This is my current setup:
A web page has an OAuth2 login link like this: https://accounts.google.com/o/oauth2/auth?access_type=offline&state=%2Fprofile&redirect_uri=##REDIR##&response_type=code&client_id=##CLIENTID##&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fadmin.directory.user.readonly
Users log in there, authorizing the app to access the Directory API in read-only mode on their behalf.
I then try to retrieve the users of the domain of a given user (by knowing its email address), using the Directory API.
Python code:
from apiclient.discovery import build
from oauth2client.client import SignedJwtAssertionCredentials
import httplib2
CLIENT_ID = "xzxzxzxzxzxz.apps.googleusercontent.com"
APP_EMAIL = "xzxzxzxzxzxz#developer.gserviceaccount.com"
SCOPES = ('https://www.googleapis.com/auth/admin.directory.user.readonly')
f = file('key.p12', 'rb')
key = f.read()
f.close()
credentials = SignedJwtAssertionCredentials(APP_EMAIL, key, SCOPES, sub="user#example.com")
http = httplib2.Http()
http = credentials.authorize(http)
directory_service = build('admin', 'directory_v1', http=http)
users = directory_service.users().list(domain="example.com").execute()
print users
I have also tried setting sub="user#example.com" to the app owner like this sub="appowner#company.com", to no avail.
Another thing I have tried is not using impersonation at all (ie. removing the sub=xx part), which leads me to this error:
apiclient.errors.HttpError: https://www.googleapis.com/admin/directory/v1/users?domain=example.com&alt=json returned "Not Authorized to access this resource/api">
Using impersonation always yields me this. I have verified it has to do with the scopes and the api which I try to call:
oauth2client.client.AccessTokenRefreshError: access_denied
Now, the actual questions:
Should I be using service accounts? For me, it is the most convenient way as I don't have to be storing tokens which can be outdated altogether.
If service accounts are the way to go, what am I doing wrong in the way I use them? Impersonation with either the Google Apps administrator account (which logs in via OAuth web) or the app owner account does not seem to work.
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)
This is a follow-up question for this question:
I have successfully created a private key and have read the various pages of Google documentation on the concepts of server to server authentication.
I need to create a JWT to authorize my App Engine application (Python) to access the Google calendar and post events in the calendar. From the source in oauth2client it looks like I need to use oauth2client.client.SignedJwtAssertionCredentials to create the JWT.
What I'm missing at the moment is a stylised bit of sample Python code of the various steps involved to create the JWT and use it to authenticate my App Engine application for Google Calendar. Also, from SignedJwtAssertionCredentials source it looks like I need some App Engine compatible library to perform the signing.
Can anybody shed some light on this?
After some digging I found a couple of samples based on the OAuth2 authentication. From this I cooked up the following simple sample that creates a JWT to access the calendar API:
import httplib2
import pprint
from apiclient.discovery import build
from oauth2client.client import SignedJwtAssertionCredentials
# Get the private key from the Google supplied private key file.
f = file("your_private_key_file.p12", "rb")
key = f.read()
f.close()
# Create the JWT
credentials = SignedJwtAssertionCredentials(
"xxxxxxxxxx#developer.gserviceaccount.com", key,
scope="https://www.googleapis.com/auth/calendar"
)
# Create an authorized http instance
http = httplib2.Http()
http = credentials.authorize(http)
# Create a service call to the calendar API
service = build("calendar", "v3", http=http)
# List all calendars.
lists = service.calendarList().list(pageToken=None).execute(http=http)
pprint.pprint(lists)
For this to work on Google App Engine you will need to enable PyCrypto for your app. This means adding the following to your app.yaml file:
libraries:
- name: pycrypto
version: "latest"
I am stuck with a problem.
#!/usr/bin/python
import httplib2
import pprint
from apiclient.discovery import build
from apiclient.http import MediaFileUpload
from oauth2client.client import OAuth2WebServerFlow
# Copy your credentials from the 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)
# Insert a file
media_body = MediaFileUpload(FILENAME, mimetype='text/plain', resumable=True)
body = {
'title': 'My document',
'description': 'A test document',
'mimeType': 'text/plain'
}
file = drive_service.files().insert(body=body, media_body=media_body).execute()
pprint.pprint(file)
The above code asks user to copy the url to the browser, and then authorize their account, and then again, copy-paste the code and paste it on the terminal. I know storing the credentials and using the refresh tokens, users will have to do this just for once.
But, I don't want so much of user-interactions. Is it possible that user authorizes by just logging in to their gmail account? As in, from my code itself, the authorization link should get open in a web browser without user doing it, and just signs in to his/her account, and that's it, authorization is done, and this login should also happen for just one time, as in, one time authorization, so that whatever is uploaded, gets uploaded on his Google Drive account and maintained. The authorization code should be directly retrieved, and these credentials should be stored as usual and be used and tokens should also be refreshed.
I came across Google Drive Service Account, good thing is that user-intervention is gone completely, but bad thing is that, it doesn't allow the account where the file is to be uploaded. It uploads the file on that drive who has created the app.
Can anyone pls help me out with this? If going with the above code, then what should I be doing to automate the task? If going with the Service Account, what should I be doing to make the app upload the data to the user's own drive account?
Any help would be appreciated.
Thanks!
I'm guessing that you have a local Python app (not web app) that you want to be able to access user's Drive. There is no reason why the authorisation needs to be done in your Python app. So for example you could write a small web app that walks the user through the authentication process, then emails you or the user the appropriate strings to paste into the python app.
Did the same for DropBox. You can integrate PyQt's or PySide QWebView (Webkit) where in you can put the auto open the URL. A mix of javascript and python can get the job done.