seached and found that /me/accounts/ is no more available, in the past i used it, so i posted on a page's application without any problem, using that Gist,
But i deleted that application and tried to add another new one, when changed the code to:
class MainHandler(BaseHandler, tornado.auth.FacebookGraphMixin):
#tornado.web.authenticated
#tornado.web.asynchronous
def get(self):
self.facebook_request("/me/applications/developer/", self._on_accounts, access_token=self.current_user["access_token"])
def _on_accounts(self, account):
if account is None:
# Session may have expired
print "on accounts failed"
sys.exit()
print "here we go!"
print account # this will return me a json
for acc in account["data"]:
if acc["id"] == "157547381099830":
self.facebook_request("/157547381099830/feed", post_args={"message":"hi there!", "link": "http://www.example.com"}, access_token=self.current_user["access_token"], callback=self.async_callback(self._on_page_post))
what i can to do, is only post on my wall (changing self.facebook_request("/157547381099830/feed"... by self.facebook_request("/me/feed"...
)
I entered to the page, and Facebook knows that am the admin, but if i use the python code, it will publish the stream a normal user!
Edit: It seems that the problem is kind of new Facebook rules? when switch to my name, i cant publish on the wall, even if i'm the admin?
In the management setting, it is written:
Manager
Abdelouahab can manage admin roles, send messages and create posts as the Page, create ads, and view insights.
But, it seems it is not the case, because when i choose:
You are posting, commenting, and liking as Abdelouahab Abdenour Aliane — Change to Essog Community then i can post, only if i switch to Essog Community (because i blocked external users from posting on the wall).
Update: added manage_pages to the scope, and even this did not work
Sorry, found the answer:
Dident use manage_pages in the first time, so i used the page token!
i must get the page access token and not the user token!
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.
(deleted and begin a new page)
this will work:
for acc in account["data"]:
if acc["id"] == "345632575539519":
print acc["access_token"]
self.facebook_request("/345632575539519/feed", post_args={"message":"hello", "link": "http://www.example.com"}, access_token=acc["access_token"], callback=self.async_callback(self._on_page_post))
Related
I'm trying to create a sign-in card so that the person interacting with the card is redirected to a sign-in page and the token is then used for other purposes (like fetching information etc).
class SignInGeneratorService:
def __init__(self, APP_ID, APP_PASSWORD):
SETTINGS = BotFrameworkAdapterSettings(APP_ID, APP_PASSWORD)
self.ADAPTER = BotFrameworkAdapter(SETTINGS)
activity = Activity()
self.turn_context = TurnContext(self.ADAPTER, activity)
async def generate_raw_link(self):
return await self.ADAPTER.get_oauth_sign_in_link(self.turn_context, "ADAuth")
This is what I initially tried to get the sign in link, but it doesn't seem to work (probably because we are using a dummy turn context object). Any ideas on how to do the same without having to use dialogs?
Unless I'm misunderstanding your question, I think you can achieve this using the "signin" card. The 06.using-cards sample demonstrates how to set up the card. And, visiting the BotFramework-WebChat repo, you can test this using the 01.getting-started/a.full-bundle demo. Just type in the word "signin" and the card will be presented. Clicking the button brings you to a page to log into Microsoft's live.com site.
You would only need to update the URL so it points to the service of your choice or design allowing you to acquire whatever information necessary.
Hope of help!
Sharing what worked for me. I had to pass MicrosoftAppCredentials and set the bot identity using the bearer token I had created earlier using the Microsoft login API (needs the client id and secret for generating this). After this I was able to create a sign-in URL which could be passed on for further use.
identity = await self.ADAPTER._authenticate_request(self.activity,
"Bearer *bearerToken*")
self.app_credentials = MicrosoftAppCredentials(APP_ID, APP_PASSWORD)
self.turn_context.turn_state[BotAdapter.BOT_IDENTITY_KEY] = identity
sign_in_resource = await self.ADAPTER.get_oauth_sign_in_link(self.turn_context, "ADAuth", None, self.app_credentials)
I'm working on an app using the Spotify API but I'm a bit new to all of this. I'm trying to get the Authorization Code with Proof Key for Code Exchange (PKCE) (https://developer.spotify.com/documentation/general/guides/authorization-guide/#authorization-code-flow-with-proof-key-for-code-exchange-pkce)
My problem is how do I redirect the user to the query where he has to ACCEPT the authorization and make my app to wait until the user clicks on ACCEPT. When he does this, the user will be redirected and that new URL (as the docs said) will contain the authorization code that I need to then exchange it for an authorization token.
This is my function so far to get that authorization code:
def get_auth_code(self):
code_challenge = self.get_code_challenge_PKCE()
scopes_needed = "user-read-email%20user-read-private%20playlist-read-collaborative%20playlist-modify-public%20playlist-read-private%20playlist-modify-private%20user-library-modify%20user-library-read"
endpoint = "https://accounts.spotify.com/authorize"
query = f"{endpoint}?client_id={self.client_ID}&response_type=code&redirect_uri={self.redirect_uri}&scope={scopes_needed}&code_challenge_method=S256&code_challenge={code_challenge}"
webbrowser.open(query)
Set up a web server.
To programmatially extract the access tokens you need a web server to handle the redirection after the user logs in on Spotify (which you redirected them to). Now this server can be the user pasting the URI to an input field on a terminal, but obviously this isn't ideal for user experience. It leaves room for lots of mistakes.
I've authored a Spotify Web API client, whose internals might be useful for you to examine. For example, you can use Flask to construct the server. The main principle is using one endpoint (i.e. /login) to redirect (code 307 worked for me browsers won't remember it) the user to a callback (i.e. /callback) which recieves the code parameter with which you can request an access token.
OAuth2 can be a bit of a pain to implement locally, I know. In my library I also made a similar function that you are constructing using webbrowser, but it does have the manual copy-pasting quirk. To use functions you can define yourself for brevity, the gist of it is:
verifier = secrets.token_urlsafe(32) # for PKCE, not in my library yet
url = user_authorisation_url(scope, state, verifier)
# Communicate with the user
print('Opening browser for Spotify login...')
webbrowser.open(url)
redirected = input('Please paste redirect URL: ').strip()
code = parse_code_from_url(redirected)
state_back = parse_state_from_url(redirected)
assert state == state_back # For that added security juice
token = request_user_token(code, verifier)
I am working on a python AppEngine application with Facebook login. I want to be able to access a logged-in user's friends' bios (their "about me" information).
Having requested/saved changes for all of the permissions I need on the Facebook developer's dashboard, I can successfully make calls like this:
friends = graph.get_connections("me", "friends", fields="name")
for friend in friends["data"]:
print friend["name"]
But trying to access the about me, as specified by the "bio" field in the docs, results in a key error:
friends = graph.get_connections("me", "friends", fields="name,bio")
for friend in friends["data"]:
print friend["bio"]
AppEngine log when running on local host:
File "/Users/nicole/aggie-harmony/main.py", line 154, in get
user = self.current_user
File "/Users/nicole/aggie-harmony/main.py", line 108, in current_user
bio = friend["bio"]
KeyError: 'bio'
INFO 2013-11-16 02:59:27,243 module.py:608] default: "GET / HTTP/1.1" 500 -
I have experimented with other fields, and it seems like anything that requires an access token will generate a key error (although the docs actually seem to have been updated mere HOURS before this question was posted...and they now suggest that "Other fields that have been explicitly set to public visibility can also be retrieved without an access token"...in my test user, the bio is indeed public!)
Unless I am just missing something syntax-wise, is this indeed a token issue? My app is based on the example here and basically obtains/uses the access token like this (auth stuff was generated previously and stored in its own file):
...
cookie = facebook.get_user_from_cookie(self.request.cookies, auth.FACEBOOK_APP_ID,
auth.FACEBOOK_APP_SECRET)
...
graph = facebook.GraphAPI(cookie["access_token"])
...
Interestingly enough, the app doesn't pop up a permission box for the user after the log-in area, which might support my hunch...
SOLVED: It was indeed an issue of permissions. In my adapted example html file, I just needed to change this:
function doLogin() {
FB.login(function(response) {} , {perms:''});
}
...to this:
function doLogin() {
FB.login(function(response) {} , {perms:'user_about_me,friends_about_me,user_likes,friends_likes,user_relationship_details,friends _relationship_details,user_relationships,friends_relationships, user_education_history, friends_education_history'});
}
Facebook takes care of the rest with the proper oauth dialog, etc.
this is my first web-programming experience so I hope my questions doesn't sound very dumb. I have been stucked on this for many days.
I am trying to understand a sample code:
https://github.com/facebook/runwithfriends
However I am not understanding very well how the information flow works and how can I modify that sample (i.e. how the code works).
For example, in the following section of the code:
class RecentRunsHandler(BaseHandler):
"""Show recent runs for the user and friends"""
def get(self):
if self.user:
friends = {}
for friend in select_random(
User.get_by_key_name(self.user.friends), 30):
friends[friend.user_id] = friend
self.render(u'runs',
friends=friends,
user_recent_runs=Run.find_by_user_ids(
[self.user.user_id], limit=5),
friends_runs=Run.find_by_user_ids(friends.keys()),
)
else:
self.render(u'welcome')
As I understand (along with HTML) is useful for showing friends that are using the same app, and if I understand correctly, here is the essential part:
*friends_runs=Run.find_by_user_ids(friends.keys())*
But what if I want to show any given friend. How can I do it?
Summarizing, I would like to know:
1- How the flow of the code works? (I don't fully understand the explanation here)
2- How can I manipulate the code so to get, for example, to show a list of friends of the user (not necessary that use the same app)?
Moreover, Can I show friends filtered by some characteristic (for example, gender)?
Thanks a lot!
The python "SDK" for facebook I use I took from https://gist.github.com/1190267
and combined it with the code from the example app to achieve the functionality I wanted both for a canvas app and for website usage.
It depends whether you're using facebook with websites or a canvas application. For a canvas application you probably could do well with the javascript SDK but for a "login with facebook" I required serverside logic that should work with javascript turned off so I've completed that solution with details you might have help to know. You can try make small changes of that specific app 'runwithfriends' to get an understanding which code does what. The project you're looking at contains some outdated practice though:
getting and setting cookies is likely preferable now doing with webapp2's builtin functions for this instead of the code that comes with the FB example app
logging in and out is now done with OAuth 2.0 so it's likely that the login system you're looking at is outdated and you need to use OAuth 2.0 which is described here. I much rather do login/logout serverside so I did an OAuth 2.0 pure python solution to login / logout following the authentication steps mentioned in the tutorial from FB. I had to clear the cookie to log a user out which was not documented.
To upgrade to python 2.7 I had to also modify so that HTTP header did not cast to unicode. I don't know why but otherwise it complained that headers were "not strings"
To more elaborately answer your specific questions:
1) The requesthandler class you posted is a subclass of a BaseHandler so to fully understand what it does you can look at the BaseHandler class since what you are posting is a BAseHandler. The BaseHandler uses django templates for rendering and if you want to can switch the template engine to jinja2 which is remmended. Further the code accesses the user object inherited from the BaseHandler and does some operations on it and renders it to a template. You can try make a requesthandler of your own, subclass BaseHandler and do what you want.
2) I could manipulate the code and I'm not an expert so you should be able to do it too. I wanted a simple FB app to display random images and I could manipulate it to select random images via blobs and render to to a template while keeping the facebook base functions. A function to use for getting the user using the Graph API I do this:
def parse_signed_request(signed_request, secret):
"""
Parse signed_request given by Facebook (usually via POST),
decrypt with app secret.
Arguments:
signed_request -- Facebook's signed request given through POST
secret -- Application's app_secret required to decrpyt signed_request
"""
if '.' in signed_request:
(esig, payload) = signed_request.split('.')
else:
return {}
sig = urlsafe_b64decode(str(esig))
data = _parse_json(urlsafe_b64decode(str(payload)))
if not isinstance(data, dict):
raise SignedRequestError('Pyload is not a json string!')
return {}
if data['algorithm'].upper() == 'HMAC-SHA256':
if hmac.new(secret, payload, hashlib.sha256).digest() == sig:
return data
else:
raise SignedRequestError('Not HMAC-SHA256 encrypted!')
return {}
def get_user_from_cookie(cookies, app_id, app_secret):
"""Parses the cookie set by the official Facebook JavaScript SDK.
cookies should be a dictionary-like object mapping cookie names to
cookie values.
If the user is logged in via Facebook, we return a dictionary with the
keys "uid" and "access_token". The former is the user's Facebook ID,
and the latter can be used to make authenticated requests to the Graph API.
If the user is not logged in, we return None.
Download the official Facebook JavaScript SDK at
http://github.com/facebook/connect-js/. Read more about Facebook
authentication at http://developers.facebook.com/docs/authentication/.
"""
cookie = cookies.get('fbsr_' + app_id, '')
if not cookie:
return None
response = parse_signed_request(cookie, app_secret)
if not response:
return None
args = dict(code=response['code'], client_id=app_id,
client_secret=app_secret, redirect_uri='')
file = \
urllib.urlopen('https://graph.facebook.com/oauth/access_token?'
+ urllib.urlencode(args))
try:
token_response = file.read()
finally:
file.close()
access_token = cgi.parse_qs(token_response)['access_token'][-1]
logging.debug('returning cookie')
return dict(uid=response['user_id'], access_token=access_token)
See http://developers.facebook.com/docs/api for complete documentation for the API. And you can get the the official Facebook JavaScript SDK at http://github.com/facebook/connect-js/
I'm now writing code to sync a webapp2_extras.auth account with facebook so that custom accounts and facebook accounts can co-exist and we're discussing solutions for this in the webapp2 groups and categories. The current way I do it is adding the recommended current_user to a basehandler and using that as the FB identity while working on "merging" my class FBUser that is a custom class for facebook users that autheorized my website and/or canvas application to sync with webapp2_extras.auth.models.User which is an expando model so it can just add the properties it doesn't have such as facebookid, firstname, lastname, etc.
#property
def current_user(self):
if not hasattr(self, '_current_user'):
self._current_user = None
cookie = get_user_from_cookie(self.request.cookies,
facebookconf.FACEBOOK_APP_ID,
facebookconf.FACEBOOK_APP_SECRET)
if cookie:
# Store a local instance of the user data so we don't need
# a round-trip to Facebook on every request
user = FBUser.get_by_key_name(cookie['uid'])
if not user:
graph = GraphAPI(cookie['access_token'])
profile = graph.get_object('me')
user = FBUser(key_name=str(profile['id']),
id=str(profile['id']),
name=profile['name'],
profile_url=profile['link'],
access_token=cookie['access_token'])
user.put()
elif user.access_token != cookie['access_token']:
user.access_token = cookie['access_token']
user.put()
self._current_user = user
return self._current_user
You can also solve your authentication with session objects and build your authentication system around that. That is what I do when using both custom accounts and facebook accounts and you're welcome to have a lok at my repository for more code examples how to intregrate facebook with google app engine using python 2.7.
im using FriendlyFormPlugin, but would like to retrieve the username that was input as part of the request.params, but its no longer there when i check. this way i can set the default for username if the password is incorrect. thanks
I think what you need to do is to setup a post login handler action when you setup the middleware. In that action you can then check params, set a session var, etc. I had to hook into here in order to create a message to the user that their login had failed. I check for a 'login_failed' param on the login form.
def post_login(self):
""" Handle logic post a user's login
I want to create a login_handler that's redirected to after login. This would
check
- if user was logged in, if not then send back to login
- if user is admin, go to job list
- adjust the max age on the existing cookie to XX remember me timeframe
"""
if auth.check(not_anonymous()):
log.debug('checked auth')
else:
# login failed, redirect back to login
log.debug('failed auth')
redirect_to(controller="root", action="login", login_failed=True)
# expire this cookie into the future
ck = request.cookies['authtkt']
response.set_cookie('authtkt', ck,
max_age=60*60*24*7,
path='/'
)
redirect_to(controller="job", action="list")
In response for more details, too big to add as another comment:
So I've got a few things you can look at. First, this is my docs I'm writing as a repoze 'summary' to help explain to other devs how this stuff works/terminology used:
http://72.14.191.199/docs/morpylons/auth_overview.html
I started out using the repoze sql quickstart plugin:
http://code.gustavonarea.net/repoze.what-quickstart/
I then ripped out their setup_sql_auth and modified it for our own needs since we do both SQL and LDAP auth in our apps. Go make sure to look at the plugin source for setup_sql_auth and go through it until you really understand what it's doing.
and since you asked on middleware config...
app = setup_morpace_auth(app, User, Group, Permission, meta.Session,
post_login_url='/root/post_login',
post_logout_url='/login',
log_level='debug',
log_file='stdout'
)