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 '---'
About these ads
35 comments
  1. Manado said:

    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.

  2. Jerry said:

    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

  3. Tara Singh said:

    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.

  4. pcardune said:

    There was an error in the get_url function. 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

  5. Tara Singh said:

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

  6. pcardune said:

    The call to to BaseHTTPServer.HTTPServer starts 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.

  7. Ron said:

    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.

  8. pcardune said:

    That would be cool indeed. Do you know what exactly the problem was with authenticating using lynx?

  9. kaon said:

    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?

  10. pcardune said:

    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.

  11. kaon said:

    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.

  12. Ronnie said:

    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.

  13. pcardune said:

    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.

  14. Alok said:

    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?

  15. how do u get on facebook if skools have blocked facebook.com

  16. Ed said:

    This is very helpful. Thank you!!

  17. jeff said:

    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.

  18. Eduardo said:

    What a great piece of code we have here. Really really nice std lib based Py authentication for Facebook. Congrats, dude!

  19. frog23 said:

    Hmmm, great idea, but I I get the following error:

    {
    “error”: {
    “message”: “Invalid redirect_uri: Given URL is not allowed by the Application configuration.”,
    “type”: “OAuthException”,
    “code”: 191
    }
    }

  20. alam said:

    im too
    {
    “error”: {
    “message”: “Invalid redirect_uri: Given URL is not allowed by the Application configuration.”,
    “type”: “OAuthException”,
    “code”: 191
    }
    }

  21. SPV said:

    Even I get the same error
    {“error”:{“message”:”Invalid redirect_uri: Given URL is not allowed by the Application configuration.”,”type”:”OAuthException”,”code”:191}}

  22. gthandavam said:

    Even I am getting the same error. In the script I see that we are starting the httpd request handler after sending a http request to graph.facebook.com. I thought it was the problem and tried sending a request after the httpd is up. But, still the same exception. Not sure if I am missing anything obvious here.

  23. gthandavam said:

    I got a app-domain for my app from heroku (recognized by facebook) and got a canvas URL from them. Once I changed the redirect URL and httpd request handler URL in the python script to the canvas URL, the script worked like magic.

  24. #!/usr/bin/python2.6
    import os.path
    import json
    import urllib2
    import urllib
    import urlparse
    import BaseHTTPServer
    import webbrowser
    # https://github.com/pythonforfacebook/facebook-sdk
    from facebook import auth_url, get_access_token_from_code, GraphAPI

    APP_ID = ‘app_id’
    APP_SECRET = ‘app_secret’
    ENDPOINT = ‘graph.facebook.com’
    REDIRECT_URI = ‘http://localhost:8080/’
    ACCESS_TOKEN = None
    LOCAL_FILE = ‘.fb_access_token’
    STATUS_TEMPLATE = u”{name}33[0m: {message}”

    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_access_token_from_code(code, REDIRECT_URI, APP_ID, APP_SECRET)

    ACCESS_TOKEN = response['access_token']
    open(LOCAL_FILE,’w’).write(ACCESS_TOKEN)
    self.wfile.write(“You have successfully logged in to facebook. ”
    “You can close this window now.”)

    if __name__ == ‘__main__':
    if not os.path.exists(LOCAL_FILE):
    print “Logging you in to facebook…”
    webbrowser.open(auth_url(APP_ID, REDIRECT_URI, perms=['read_stream']))

    listen_on = urlparse.urlsplit(REDIRECT_URI)
    httpd = BaseHTTPServer.HTTPServer((listen_on.host, listen_on.port or 80), RequestHandler)
    while ACCESS_TOKEN is None:
    httpd.handle_request()
    else:
    ACCESS_TOKEN = open(LOCAL_FILE).read()
    client = GraphAPI(ACCESS_TOKEN)
    print client.request(‘me/feed’)

  25. Hi, I’m very new to python.
    In Line :httpd = BaseHTTPServer.HTTPServer((listen_on.host, listen_on.port or 80), RequestHandler), We know that
    If RequestHandler is a inherited class from BaseHTTPServer.HTTPServer, then We are supposed to create a object for RequestHandler class initially and then we should have used it here right?
    And if at all if we can call some class directly without creating a object, Then RequestHandler should be RequestHandler() isn’t?
    I’m totally down in understand this particular concept. Please help me with some Examples..

  26. Over the last year Desiree has been setting up a “classroom” where she can share the things she has learned in
    her adventures. Her passion was her work and she had little energy at the
    end of the day to focus on preparing good food. Permaculture
    is planting natural foods in land that is maintained without chemicals and machines, animals grazing that land naturally and cycling natural resources back into earth to create sustainable environments.

  27. It is however not always possible to modify certain conditions and restrictions that come with the property.
    One of the largest permaculture communities in the US, Earthhaven Ecovillage, is located in the nearby
    town of Black Mountain. Offering a variety of specialty produce alongside strong selling products establishes
    a foundation of success with any business and this includes a fruit-stand or Farmer’s Market enterprise.

  28. There’s certainly a great deal to know about this subject.
    I really like all the points you have made.

  29. I’m a developer and I have just thought of
    a breakthrough internet dating website page. I am only looking for beta test candidates to
    browse and try it out. Do you desire to opt-in? We
    shall compensate you.

  30. Google said:

    I was suggested this web site by my cousin. I’m not sure whether this
    post is written by him as no one else know such detailed about my difficulty.
    You are amazing! Thanks!

  31. When the first can of 10W-40 oil appeared on the
    market in 1972, it signaled the birth of an entire industry.
    VOC or Volatile Organic Compounds are organic solvents that easily evaporate
    into the air. As a possible example, if you’re using stiff card stock
    or a stiff business card (which you really should be) simply set the card across the top of
    a cup or mug of some sort.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 76 other followers

%d bloggers like this: