I am getting error when I am retrieving data from firebase - python

I am posting this question because I haven't found any proper solution related to my problem.
I am trying to retrieve my user's data from Firebase but I am unable to do it. Please explain to me what I am doing wrong.
For this project, I am using Flask API. I also included all required indexes in my rules for the database. My error message accrues on line 106.
Error message:
Code
Json for data

This is a default code required for getting data:
from firebase import firebase
firebase = firebase.FirebaseApplication('Your url of the Real Time Database')
obj = firebase.get('/', None) #NOTE: '/' should be followed by the path in case you have child attributes
print(obj) #You will get a dictionary in return

Related

Blob.generate_signed_url() failing to AttributeError

So I'm trying to produce temporary globally readable URLs for my Google Cloud Storage objects using the google-cloud-storage Python library (https://googlecloudplatform.github.io/google-cloud-python/latest/storage/blobs.html) - more specifically the Blob.generate_signed_url() method. I doing this from within a Compute Engine instance in a command line Python script. And I keep getting the following error:
AttributeError: you need a private key to sign credentials.the credentials you are currently using <class 'oauth2cl
ient.service_account.ServiceAccountCredentials'> just contains a token. see https://google-cloud-python.readthedocs
.io/en/latest/core/auth.html?highlight=authentication#setting-up-a-service-account for more details.
I am aware that there are issues with doing this from within GCE (https://github.com/GoogleCloudPlatform/google-auth-library-python/issues/50) but I have created a new Service Account credentials following the instructions here: https://cloud.google.com/storage/docs/access-control/create-signed-urls-program and my key.json file most certainly includes a private key. Still I am seeing that error.
This is my code:
keyfile = "/path/to/my/key.json"
credentials = ServiceAccountCredentials.from_json_keyfile_name(keyfile)
expiration = timedelta(3) # valid for 3 days
url = blob.generate_signed_url(expiration, method="GET",
credentials=credentials)
I've read through the issue tracker here https://github.com/GoogleCloudPlatform/google-cloud-python/issues?page=2&q=is%3Aissue+is%3Aopen and nothing related jumps out so I am assuming this should work. Cannot see what's going wrong here.
I was having the same issue. Ended up fixing it by starting the storage client directly from the service account json.
storage_client = storage.Client.from_service_account_json('path_to_service_account_key.json')
I know I'm late to the party but hopefully this helps!
Currently, it's not possible to use blob.generate_signed_url without explicitly referencing credentials. (Source: Google-Cloud-Python documentation) However, you can do a workaround, as seen here, which consists of:
signing_credentials = compute_engine.IDTokenCredentials(
auth_request,
"",
service_account_email=credentials.service_account_email
)
signed_url = signed_blob_path.generate_signed_url(
expires_at_ms,
credentials=signing_credentials,
version="v4"
)
A much complete snippet for those asking where other elements come from. cc #AlbertoVitoriano
from google.auth.transport import requests
from google.auth import default, compute_engine
credentials, _ = default()
# then within your abstraction
auth_request = requests.Request()
credentials.refresh(auth_request)
signing_credentials = compute_engine.IDTokenCredentials(
auth_request,
"",
service_account_email=credentials.service_account_email
)
signed_url = signed_blob_path.generate_signed_url(
expires_at_ms,
credentials=signing_credentials,
version="v4"
)

Getting user info with Cloud Endpoints (using other API Endpoints)

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 (;

How to get Salesforce username using REST api?

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.

Posting to Facebook App page wall as the App Page in python

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

Python: Facebook API showing invalid token

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')

Categories