Authenticating with Facebook on the Command Line Using Python
Ever since Facebook launched graph.facebook.com, I’ve been wanting to check it out and see just how superior it is to Facebook Connect. It turns out it was pretty easy to authenticate myself from python using OAuth 2. So I wrote a little script that spits out my feed on the command line.
If you’ve ever felt frustrated implementing an OAuth client before, rest assured that OAuth 2 is one million times easier to work with than OAuth 1. You don’t have to keep track of all these different tokens or worry about generating signatures in just the right way. The one gotcha here is that you need a web server for the user to be redirected to after they authorize your application with Facebook. Fortunately, python makes it really easy to start up a mini webserver for the purposes of OAuth.
Here is the script in 75 lines of python. If you want to try it out yourself, you’ll have to register an application with Facebook at http://developers.facebook.com/setup/.
#!/usr/bin/python2.6
import os.path
import json
import urllib2
import urllib
import urlparse
import BaseHTTPServer
import webbrowser
APP_ID = 'your-app-id-here'
APP_SECRET = 'your-app-secret-here'
ENDPOINT = 'graph.facebook.com'
REDIRECT_URI = 'http://127.0.0.1:8080/'
ACCESS_TOKEN = None
LOCAL_FILE = '.fb_access_token'
STATUS_TEMPLATE = u"{name}\033[0m: {message}"
def get_url(path, args=None):
args = args or {}
if ACCESS_TOKEN:
args['access_token'] = ACCESS_TOKEN
if 'access_token' in args or 'client_secret' in args:
endpoint = "https://"+ENDPOINT
else:
endpoint = "http://"+ENDPOINT
return endpoint+path+'?'+urllib.urlencode(args)
def get(path, args=None):
return urllib2.urlopen(get_url(path, args=args)).read()
class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_GET(self):
global ACCESS_TOKEN
self.send_response(200)
self.send_header("Content-type", "text/html")
self.end_headers()
code = urlparse.parse_qs(urlparse.urlparse(self.path).query).get('code')
code = code[0] if code else None
if code is None:
self.wfile.write("Sorry, authentication failed.")
sys.exit(1)
response = get('/oauth/access_token', {'client_id':APP_ID,
'redirect_uri':REDIRECT_URI,
'client_secret':APP_SECRET,
'code':code})
ACCESS_TOKEN = urlparse.parse_qs(response)['access_token'][0]
open(LOCAL_FILE,'w').write(ACCESS_TOKEN)
self.wfile.write("You have successfully logged in to facebook. "
"You can close this window now.")
def print_status(item, color=u'\033[1;35m'):
print color+STATUS_TEMPLATE.format(name=item['from']['name'],
message=item['message'].strip())
if __name__ == '__main__':
if not os.path.exists(LOCAL_FILE):
print "Logging you in to facebook..."
webbrowser.open(get_url('/oauth/authorize',
{'client_id':APP_ID,
'redirect_uri':REDIRECT_URI,
'scope':'read_stream'}))
httpd = BaseHTTPServer.HTTPServer(('127.0.0.1', 8080), RequestHandler)
while ACCESS_TOKEN is None:
httpd.handle_request()
else:
ACCESS_TOKEN = open(LOCAL_FILE).read()
for item in json.loads(get('/me/feed'))['data']:
if item['type'] == 'status':
print_status(item)
if 'comments' in item:
for comment in item['comments']['data']:
print_status(comment, color=u'\033[1;33m')
print '---'
Thanks. I’ll try this on my Nokia N900 and see. If I get stucked may be I’ll get back to you :-)
Great post.
Thanks but I got exception –
Exception happened during processing of request from (’127.0.0.1′, 56051)
Traceback (most recent call last):
File “/usr/lib/python2.6/SocketServer.py”, line 281, in _handle_request_noblock
self.process_request(request, client_address)
File “/usr/lib/python2.6/SocketServer.py”, line 307, in process_request
self.finish_request(request, client_address)
File “/usr/lib/python2.6/SocketServer.py”, line 320, in finish_request
self.RequestHandlerClass(request, client_address, self)
File “/usr/lib/python2.6/SocketServer.py”, line 615, in __init__
self.handle()
File “/usr/lib/python2.6/BaseHTTPServer.py”, line 329, in handle
self.handle_one_request()
File “/usr/lib/python2.6/BaseHTTPServer.py”, line 323, in handle_one_request
method()
File “./facebook_oauth.py”, line 48, in do_GET
‘code’:code})
File “./facebook_oauth.py”, line 29, in get
return urllib2.urlopen(get_url(path, args=args)).read()
File “/usr/lib/python2.6/urllib2.py”, line 126, in urlopen
return _opener.open(url, data, timeout)
File “/usr/lib/python2.6/urllib2.py”, line 397, in open
response = meth(req, response)
File “/usr/lib/python2.6/urllib2.py”, line 510, in http_response
‘http’, request, response, code, msg, hdrs)
File “/usr/lib/python2.6/urllib2.py”, line 435, in error
return self._call_chain(*args)
File “/usr/lib/python2.6/urllib2.py”, line 369, in _call_chain
result = func(*args)
File “/usr/lib/python2.6/urllib2.py”, line 518, in http_error_default
raise HTTPError(req.get_full_url(), code, msg, hdrs, fp)
HTTPError: HTTP Error 400: Bad Request
—————————————-
with the following trace –
> /usr/lib/python2.6/urllib2.py(126)urlopen()
-> return _opener.open(url, data, timeout)
(Pdb) url
‘http://graph.facebook.com/oauth/access_token?code=2.EHB5ky9EmSqEWvJtuTMqmA__.3600.1286092800-697227527%7CcddDcBN5M3fWrg2liCJcYmzpJvI&client_secret=dbd93892b77f800ae2cb2ab7365a3015&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2F&client_id=140335172679102′
(Pdb) data
(Pdb) n
–Return–
> /usr/lib/python2.6/urllib2.py(126)urlopen()->None
-> return _opener.open(url, data, timeout)
(Pdb) n
HTTPError: HTTPError()
Do you have an idea? Thanks.
-Jerry
Hi,
I am trying to run this code and everytime I am getting stuck at line 65. Not able to proceed and get the Access code. It invokes the facebook login page, and even success if user logs into and accept the app. But after that it hangs up. I tried changing the URL but no awail. Any suggestions will be of great help.
There was an error in the
get_urlfunction. You must use https when passing the client secret, which was not being done before. I’ve updated the above code with the fix:if 'access_token' in args or 'client_secret' in args:
endpoint = "https://"+ENDPOINT
Hi,
I am still not able to get any response back. Does Localhost have anything to do with it?
1. I am redirecting user to the Facebook provided dummy Success page. Do I need to change it here in this line :
httpd = BaseHTTPServer.HTTPServer((‘http://www.facebook.com/connect/login_success.html’,80), RequestHandler) ??
2. Also I behind a Public Network Router. Do I need to set port forwarding at router as My internal IP and the one which is actually contacting facebook authentication will be different (Just guessing).
The call to to
BaseHTTPServer.HTTPServerstarts a locally running http server so that facebook can pass back the access code via a web browser. The parameters to the constructor are the interface on which to run the server (localhost) and the port. It should match up with REDIRECT_URI at the top. If you want to redirect users to facebook’s success page (i’m not sure why you would want to do this), then you would need to modify the RequestHandler to return an HTTP 302 response.It’s ok if you are behind a public network router. Facebook never makes a request to your server, it only redirects the user back to your server.
Hi .. I’ve tried to run this script in my vps shell however It cant proceed with the fb auth using lynx browser. I think it would be cool if this script can login you in facebook using shell. BTW I ran this in my vps since fb is blocked in my workplace.
That would be cool indeed. Do you know what exactly the problem was with authenticating using lynx?
Hi
I can’t run this script
when I run, i can see ELinks which is a text browser.
and i try to login to facebook. but I meet message “Incompatible Browser” and I cant go on next step. It is holding.
what am i missing here?
I’m afraid Facebook does not support ELinks. I’ll see if I can find out if there are any text browsers that are explicitly supported for Facebook login. At the very least I suspect the browser would have to support SSL and cookies.
Hi~
Thanks to response.
It seems that my computer’s default browser is ELinks in python. I am sorry but I think that text browser is not support in facebook.
hi,
Is there any way to shut down the web Server we are starting to catch the Access Code? I am trying something like if it runs for 2 mins and still dint get access code then script should shut down web server and exit execution.
If you wanted to shut down the web server after 2 minutes, you would have to run it in a separate thread. It shouldn’t be too hard to do using python’s threading module.
Pingback: Ask From Octopus » Answers Archive » Facebook news feed, cant find server…
Pingback: Facebook news feed, cant find server… - Question Lounge
took me two days to figure this simple thing and this is exactly what I was looking for.Couple of things I don’t get though…I can’t seem to find the .fb_access_token (Local File).
Also is there a way to get facebook session ID from this?
how do u get on facebook if skools have blocked facebook.com
This is very helpful. Thank you!!
This is not a bad piece of work, but it’s totally misleading to call it “authenticating with the command-line”. It’s not auth with a command-line, it is using a browser. If that wasn’t obvious to you when you wrote it, it should have become obvious after you received several comments to that effect.
Pingback: It All Starts Here « Jason James Hoyle
What a great piece of code we have here. Really really nice std lib based Py authentication for Facebook. Congrats, dude!