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.