I am using web server flow for oAuth and simple-salesforce REST api to login the user using the access token and instance url. I have gone through the http://www.salesforce.com/us/developer/docs/api_rest/index.htm documentation and coudn't find anything on it.
Based on your comment saying you're using https://github.com/neworganizing/salesforce-oauth2 : you can do something like :
import urllib
# After you get the code
response = salesforce_oauth_2.get_token(code)
print urllib.urlopen(response['id'])
The json object response returned by get_token should contain an id attribute which is an url that you can query for more information about the current user. See here for more details (paragraph 5).
Get your salesforce dev to write a simple method that when pinged returns the context user details that you're after. See here for an example.
Related
I am trying to access particular gerrit details based on it's change-id. But unable to get the details.
I have used python-gerrit-api. code snippet as follows
from gerrit import GerritClient
gerrit = GerritClient(base_url="base-url-gerrit", username='xxxxx', password='xxxxxx', ssl_verify=False, cert=None)
change = gerrit.changes.get('123456')
but response getting as "404 Client Error: Not Found for url"
when I try to access same url "https://base-gerrit.com/changes/123456", directly json data is downloading.
Please let me know where did I do wrong, is there any otherway to get the change details based on change-id.
I am retrieving a ChromeOS device MAC address via the Google Admin Directory API using the device's Serial Number as reference, and am making my calls through
apiclient.
service = discovery.build('admin', 'directory_v1', developerKey=settings.API_KEY)
Here are the calls available for ChromeOS devices; my issue is that I require a Device ID in order to execute the following:
service.chromeosdevices().get(customerId=settings.CID, deviceId=obtained_id, projection=None).execute()
I can send a GET query via the following format:
https://www.googleapis.com/admin/directory/v1/customer/my_customer/devices/chromeos?projection=full&query=id:" + serial + "&orderBy=status&sortOrder=ascending&maxResults=10", "GET")
... but I'm trying to avoid using OAuth2 and just use my API key. Passing the key in a GET request doesn't work either, as it still returns a "Login Required" notice.
How do I squeeze the above query into an apiclient-friendly format? The only option I found via the above calls was to request every device we have (via list), then sift through the mountain of data for the matching Serial number, which seems silly and excessive.
I did notice I could call apiclient.http.HttpRequests, but I couldn't find a way to pass the API key through it either. There's new_batch_http_request, but I can't discern from the docs how to simply pass a URL to it.
Thank you!
Got it!
You can't use just a key for Directory API queries, you need a Service account.
I'm using google-auth (see here) since oauth2client is deprecated.
You also need to:
Delegate the necessary permissions for your service account (mine has the role of Viewer and has scope access to https://www.googleapis.com/auth/admin.directory.device.chromeos.readonly)
Delegate API access to it separately in the Admin Console (Security -> Advanced Settings -> Authentication)
Get your json client secret key and place it with your app (don't include it in your VCS)
Obtain your credentials like this:
credentials = service_account.Credentials.from_service_account_file(
settings.CLIENT_KEY,
scopes=settings.SCOPES,
subject=settings.ADMIN_USER)
where ADMIN_USER is the email address of an authorized Domain admin.
Then you send a GET request like so:
authed_session = AuthorizedSession(credentials)
response = authed_session.get(request_id_url)
This returns a Requests object you can read via response.content.
Hope it helps someone else!
I'm trying to setup endpoints api (with google app engine, python), but I'm having some trouble getting user profile info. API is working, I can create entities through API Explorer on my localhost.
My goal is to allow user to register for my app by providing just an email, and authorizing the app to get the reset of the info from their profile. I have this endpoints method:
#User.method(http_method="POST",
auth_level=endpoints.AUTH_LEVEL.REQUIRED,
allowed_client_ids=[
endpoints.API_EXPLORER_CLIENT_ID
],
scopes=[
'https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/userinfo.profile',
'https://www.googleapis.com/auth/plus.me',
],
user_required=True,
request_fields=('email',),
response_fields=('id',),
name="register",
path="users")
def UserRegister(self, instance):
logging.info(os.getenv( 'HTTP_AUTHORIZATION' ))
# 'Beared __TOKEN__'
logging.info(endpoints.users_id_token._get_token(None))
# '__TOKEN__'
instance.put()
return instance
This works fine, I receive authorization token and user is created in datastore, but I can't figure out how to get the profile info. If I enter the token in OAuth2 API (through API Explorer):
POST https://www.googleapis.com/oauth2/v2/tokeninfo?access_token=__TOKEN__
I get token info with some data I need { "user_id": "__ID__", "verified_email": true, ...}, and if I use user_id in +API:
GET https://www.googleapis.com/plus/v1/people/__ID__
I can get the rest of the data I need (name, image, etc).
What do I need to do to achieve this in my UserRegister() method? I'd prefer to return just entity ID and do the rest of registration asynchronously, but that's another issue, I'll figure it out (; Just need some guidance how to call other endpoints from my code...
EDIT:
I've managed to figure out how to call other APIs (code on Gist), now only have one issue with Plus API:
I did some queries and eventually got anonymous quota error. Then I added key parameter and set it to WEB_CLIENT_ID or SERVICE_ACCOUNT:
WEB_CLIENT_ID is OAuth2 Client ID (type: Web Application) from console.developers.google.com/apis/credentials,
SERVICE_ACCOUNT is default App Engine service account - MY_APP#appspot.gserviceaccount.com...
and now I'm getting following error:
HttpError: <HttpError 400 when requesting https://www.googleapis.com/plus/v1/people/__VALID_USER_ID__?key=__WEB_CLIENT_ID__or__SERVICE_ACCOUNT__&alt=json returned "Bad Request">
When I use +API explorer I get results as expected:
REQUEST:
https://www.googleapis.com/plus/v1/people/__VALID_USER_ID__?key={YOUR_API_KEY}
RESPONSE:
200 OK + json data for user...
Anyone knows why is this happening?
Why am I getting BadRequest response?
Problem with BadRequest was that I didn't send authorization token... I did try to send it as access_token, but seams like +api docs are outdated - it should be oauth_token. When I included this parameter issue was resolved:
build('plus', 'v1').people().get(userId=user_id, key=SERVICE_ACCOUNT, oauth_token=token).execute()
HINT: Use http://localhost:8001/_ah/api/discovery/v1/apis/, and discoveryRestUrl property it has to see real properties of your API - this is where I found the answer.
oauth_token can be obtained like this:
token = os.getenv('HTTP_AUTHORIZATION').split(" ")[1]
# or like in my question:
token = endpoints.users_id_token._get_token(None)
I'd suggest HTTP_AUTHORIZATION variable, because users_id_token docs state that it's a:
Utility library for reading user information from an id_token.
This is an experimental library that can temporarily be used to extract
a user from an id_token. The functionality provided by this library
will be provided elsewhere in the future.
How to call other API Endpoints?
This is also an answer to my first question:
from googleapiclient.discovery import build
service = build('plus', 'v1')
request = service.people().get(userId=user_id, key=SERVICE_ACCOUNT, oauth_token=token)
response = request.execute()
data = dict(self.response.POST)
Code that worked for me is here.
NOTE: WEB_CLIENT_ID obtained from https://console.developers.google.com/apis/credentials (OAuth2 Client ID of type Web Application) will NOT work in this case. I had to use SERVICE_ACCOUNT - I didn't try to generate one through console, default service account I got from App Engine worked fine.
...things are much clearer now that I got this working. Hope it will help someone else (;
I am trying make a post on my apps page wall as if it is coming from the app page (not another user) After researching I seem to find no solution that actually works!
I have tried to follow the documentation here:
I then get my 'access_token_page' by getting it from:
https://graph.facebook.com/oauth/access_token?client_id=APP_ID&client_secret=CLIENT_SECRET&grant_type=client_credentials
Then using the facebook python api I try:
graph1 = facebook.GraphAPI(access_token_page)
graph1.put_wall_post(fbmessage, attachment, profile_id=APP_PAGE_ID)
However this just returns the following facebook error:
*** GraphAPIError: (#200) The user hasn't authorized the application to perform this action
Any ideas on what I am missing? Remember, I am looking to have the App Page make a post to itself, not have a post be generated from another username.
Thank you!
What you had done is using App Access Token to publish to page.
You should using Page Access Token to post on page admin behalf instead. User Access Token is works too but it's a bug as reported at https://developers.facebook.com/bugs/647340981958249, so it's not recommended to use User Access Token by this time of writing.
As documented at https://developers.facebook.com/docs/reference/api/page/#page_access_tokens:
Page Access Tokens
To perform the following operations as a Page, and not the current
user, you must use the Page's access token, not the user access token
commonly used for reading Graph API objects. This access token can be
retrieved by issuing an HTTP GET to /USER_ID/accounts with the
manage_pages permission.
More info about different type of access token please visit https://developers.facebook.com/docs/facebook-login/access-tokens/
Try Django Facebook:
https://github.com/tschellenbach/Django-facebook
This will deal with many of your API problems.
You need the page access token, see here:
https://developers.facebook.com/docs/facebook-login/access-tokens/
Ask for manage_pages as an extra permission
After getting that setup, simply do:
user_graph = OpenFacebook(user_access_token)
response = user_graph.get('me/accounts')
# turn the response to a dict, and be sure to get the page you want
page_access_token = response['data'][0]['access_token']
graph = OpenFacebook(page_access_token)
graph.set('me/feed', message='helloworld')
You can find more docs here:
http://django-facebook.readthedocs.org/en/latest/open_facebook/api.html
I am using facepy facebook graph API to access my mailbox/messages and I followed the following two approaches:
1st Approach:
I used the access token I got from Graph Explorer facebook page and use the below code:
from facepy import GraphAPI
graph = GraphAPI(token)
print graph.get('/me')
#Rest of the code
The above code worked fine and I was able to retrieve all my messages using an FQL Query. The problem arised when my auth_token expired after sometime.
So, after some googling I shifted to approach two:
Now, what I did was created a facebook app gave it read_mailbox permission and got it's id and key and then used get_application_access_token method of facepy to get the token.
After retrieving the token I used:
token = facepy.utils.get_application_access_token(app_id, key)
graph.get('/me')
## OUT: OAuthError: [2500] An active access token must be used to query information about the current user.
facepy.utils.get_extended_access_token(token, app_id, key)
# OUT: OAuthError: [1] No user access token specified
Now, you can see the error(commented #) generated on using the application token.
I believe the error I am getting is because facebook needs the user_token and I am supplying it with app_token.
So, is it possible to access user data using the app_token and if not how can one issue a extended token which can access user data.
Update:
So, I followed #Johannes suggestion and tried this but ran into error:
from facepy.utils import get_extended_access_token
from facepy import GraphAPI
token = "My user access token got from https://developers.facebook.com/tools/explorer"
long_lived_access_token = get_extended_access_token(token)
graph = GraphAPI(long_lived_access_token)
graph.get('/me')
Now, when I ran the above code I got
TypeError: get_extended_access_token() takes exactly 3 arguments (1 given)
So, I changed it to long_lived_access_token = get_extended_access_token(token, None, None) and got
facepy.exceptions.OAuthError
So, I again I changed it to long_lived_access_token = get_extended_access_token(token, app_id, key) and I got the same exception/error as above.
So, is this a bug or am I doing something wrong.
PS: I installed the latest version from git.
You're right in your assumption that you cannot use application access tokens to read a user's mailbox, but the error you're getting stems from the fact that you haven't initialized graph with an access token at all.
Be that as it may, you're on the right track in asking for how you can extend the user's access token. As you have already discovered, Facepy HEAD (soon to be version 0.9) has a function get_extended_access_token which accepts an existing short-lived user access token and extends it. Extended user access tokens last for 2 months, and you can read more about them in Facebook's documentation on the removal of offline_access permission.
If you want to use get_extended_access_token right now, you will have to install facepy from git:
$ pip install git+git://github.com/jgorset/facepy.git#b5153f460f2f52cef9a5e49a3b48b3fb8742356c
Once you've installed the right version of Facepy, you can extend an existing short-lived user access token and initialize a new instance of GraphAPI with it:
from facepy.utils import get_extended_access_token
from facepy import GraphAPI
long_lived_access_token, expires_at = get_extended_access_token(short_lived_access_token, application_id, application_secret_key)
graph = GraphAPI(long_lived_access_token)
graph.get('/me')
There is nothing wrong with the API you are just not interpreting the result in a right way.
If you try to print the result of long_lived_access_token = get_extended_access_token(token) it will not directly give you a long_lived_access_token instead it will provide you a tuple with contents:
long_lived_access_token = ('your token', datetime_object).
You can verify this by looking at the source code of utils.py. If you look at get_extended_access_token method it returns token, expires_at.
According to the facebook docs to get the extended access token one has to make request at the below endpoint
https://graph.facebook.com/oauth/access_token?
client_id=APP_ID&
client_secret=APP_SECRET&
grant_type=fb_exchange_token&
fb_exchange_token=EXISTING_ACCESS_TOKEN
and the response is something like token=mytoken&expire=5184000 where 5184000 means 60 days.
So, your final code will look something like:
from facepy.utils import get_extended_access_token
from facepy import GraphAPI
app_id = 'id'
key = 'key'
short_lived_access_token = 'short_token'
long_token = get_extended_access_token(short_token, id, key)
graph = GraphAPI(long_token[0])
print graph.get('/me')