Facebook: Authenticate w/o the JavaScript SDK (Python)
If you're using the Facebook JavaScript SDK to implement Facebook connect, your site may be more fragile than you think. Last weekend, I ran into an issue where an unrelated JavaScript error (the dreaded comma of death) caused IE7 users to fail trying to connect to Facebook. To make the site more robust, I decided to implement a non-JavaScript fallback.
Normally with Facebook connect, the login links have event handlers attached to them via JavaScript, such as this jQuery code.
$("#facebook-login-button").click(function () { FB.login(function(response) { if (response.session) { window.location = "/facebook/authenticated"; } }, { perms: "email" }); return false; });
Normally that URL has a null href, like a pound symbol. We are still going to attach the Facebook handler, but we're also going to supply a fall back href.
connect to Facebook
Generating the correct Facebook URL to redirect the user to, and handling the "code" handed back by Facebook is done in Python/Django:
import urllib import json @register.filter() def facebook_oauth_url(request, perms=None, next=None): return get_oauth_url(request, perms, next) # generates the URL to put into the facebook connect login link as a non-js fallback def get_oauth_url(request, perms=None, next=None): client_id = settings.FACEBOOK_TOKEN # there are various kinds of users that needs to authenticate via Facebook # each needs to be taken back to a different page, and possibly use different perms request.session["facebook_next"] = next if perms == None: perms = "email,publish_stream" redirect_uri = reverse("facebook_login", prefix=settings.SITE_URL) return "https://graph.facebook.com/oauth/authorize?client_id=%(client_id)s&scope=%(perms)s&redirect_uri=%(redirect_uri)s" % locals() # handles the "facebook_login" request; back from Facebook's side def login(request): code = request.REQUEST.get("code") if code: access_token_url = "https://graph.facebook.com/oauth/access_token?" args = {} args["client_id"] = settings.FACEBOOK_TOKEN args["client_secret"] = settings.FACEBOOK_SECRET # facebook_login is THIS url, need to pass something in or the token will not be generated args["redirect_uri"] = reverse("facebook_login", prefix=settings.SITE_URL) args["code"] = code url = access_token_url + urlencode(args) file = urllib.urlopen(url) try: contents = file.read() if file.getcode() == 200: access_token = cgi.parse_qs(contents).get("access_token")[-1] return HttpResponse("Got OAuth token: " + access_token) else: response = _parse_json(contents) print "Facebook error code: " + response.get("error") except ValueError, e: print "Error connecting to Facebook. %s" % e finally: file.close()
That's it! Once you have the access token, you can make your API calls. I use the Facebook GraphAPI SDK for Python.