Adding Facebook authentication to your Django Application
As the internet becomes more interconnected, data of all kinds is more readily passing between different domains and applications. As a result, several centralized data “hubs” are cropping up that allow web users to enter data in once, and then allow applications to access it from there. This is in contrast to the age-old practice of requiring users to create unique accounts, and enter the same information for every single web site or application they wanted to use.
Unique user authentication systems are dead, at least for most of us.
As the Oatmeal so eloquently put it (hint: scroll down to #4), there’s really no reason for the vast majority of web applications to have their own “vaults” of user data, forcing the user to jump through hoops every time they go to a new site. Rather, it’s better now to use the growing number of public APIs to let users log into our applications with the accounts they already have. As far as a mostly public repository of user data goes, it’s hard to get better than Facebook.
The plan.
I’ve been toying around with a new web app as of late, and I decided from the outset that I would allow users to log into my system with their Facebook accounts. Eventually, I’ll add OpenID as well. The goal for me is to ask users to jump through a unique registration system only if they can’t log in with a pre-existing account from somewhere else.
With that in mind, let’s get started.
My setup.
Here is some information about my setup:
- Ubuntu 10.4
- PostgreSQL 8.4
- Python 2.6
- Django 1.2
- Nginx
- FastCGI for serving up my Django app.
If you are running things differently, you might have to make some minor modifications to get things working.
The plan.
The goal of this tutorial is to inject your Django app with some Facebook love. We will be setting up and installing the following:
Assumptions and prerequisites.
I’m assuming you’ve already gone through the trouble of setting up your stack and have a Django project started. If not, my friend Brandon Konkle has an excellent tutorial that will get you up and running.
Install memcached.
django-facebookconnect requires caching, so the first thing we will do is set up and install memcached. If you’d rather use database caching, or something else, you should read up on other options for caching in Django.
sudo apt-get install memcached
Then, open your project’s settings.py file and add the following line:
CACHE_BACKEND = 'memcached://127.0.0.1:11211/'
This tells Django to access a memcached server at port 11211 of the local host.
Install PyFacebook.
The django-facebookconnect app requires PyFacebook to be installed, and that makes sense, given that you’ll need the goodies in the package to make your app talk to Facebook.
I find it easiest to create a “code” directory in my home directory, and then pull things into it. I’m using git here to pull the files down, but you can use whatever you need to.
mkdir code cd code git clone http://github.com/sciyoshi/pyfacebook.git cd pyfacebook sudo python setup.py install
Note: It’s important to note that Ubuntu, for some reason, places all of your python packages in /usr/local/lib/python2.6/dist-packages, as opposed to the conventional site-packages directory. You’ll need to remember this if you want to remove PyFacebook or django-facebookconnect at a later date.
Install django-facebookconnect.
Head back to your code directory, and go grab the django-facebookconnect package. You’ll have to unzip it with your decompressor of choice.
cd ~/username/code wget http://django-facebookconnect.googlecode.com/files/django-facebookconnect-0.1.zip unzip django-facebookconnect-0.1.zip cd django-facebookconnect-0.1
Once it’s unzipped, you’ll want to copy the “facebook” directory into your dist-packages directory.
sudo cp facebook /usr/local/lib/python2.6/dist-packages/
Configuring your application.
Let’s start by adding the facebook app to your installed apps. You’ll also need to add django-auth, if you don’t already have it. Move into your project directory and edit your settings.py file.
INSTALLED_APPS = (
#---
'django.contrib.auth',
'django.contrib.sessions',
'facebookconnect',
)
Next we need to add the middleware definitions in. Middleware can be very picky, so the order here is very important.
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'facebook.djangofb.FacebookMiddleware',
'django.middleware.common.CommonMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'facebookconnect.middleware.FacebookConnectMiddleware',
)
Note: You may have some other middleware that isn’t included in the previous list. Just try to set the order as best you can; you might need to play with it to get everything working.
Now it’s time to define the authenticate backends. If you don’t have an AUTHENTICATION_BACKENDS group in your settings file, just add one.
AUTHENTICATION_BACKENDS = (
'facebookconnect.models.FacebookBackend',
'django.contrib.auth.backends.ModelBackend',
)
The last step to configuring your app is getting the Facebook-specific information in. This will require you to get a Facebook API key. Head over to their developer site and create an application. You’ll need to fill in the “Connect” information for your app once you get it set up as well.
With Facebook info in-hand, we can finish the settings.py file.
DUMMY_FACEBOOK_INFO = {
'uid':0,
'name':'(Private)',
'first_name':'(Private)',
'pic_square_with_logo':'http://www.facebook.com/pics/t_silhouette.gif',
'affiliations':None,
'status':None,
'proxied_email':None,
}
FACEBOOK_API_KEY = '00000000000000000000000000000000'
FACEBOOK_SECRET_KEY = '00000000000000000000000000000000'
FACEBOOK_INTERNAL = True
#Cache facebook info for x seconds. Default is 30 minutes
FACEBOOK_CACHE_TIMEOUT = 1800
What we’ve done here is set up some dummy information for Facebook to display, in case something goes wrong with the connection. This happens from time to time, so Facebook attempts to break gracefully, rather than taking your site down with an ugly error message.
Underneath that is where you’ll put your API keys, and set the cache timeout limit. I don’t know what the FACEBOOK_INTERNAL call does, except that PyFacebook requires it. I’ve messaged the author of PyFacebook for some more information, and will update this post when I get it.
Configure URLs, and add the Facebook Connect button to your template.
Ok, we are almost ready to rock and roll. All that’s left is adding the new URLs, and putting the relevant tags into your templates. Open up your project’s urls.py file and make the following changes.
urlpatterns = patterns('',
...,
(r'^facebook/', include('facebookconnect.urls')),
)
Now, open up your registration/login.html template, and add these tags.
#Top of the page
{% load facebook_tags %}
#In the head tag
{% facebook_js %}
{% initialize_facebook_connect %}
#Wherever you want the button to appear
{% show_connect_button %}
Start your server up, and voila, you should have a Connect with Facebook button on your login page. Clicking on it should take you to a Facebook Login page, and when you successfully log in, you will be redirected to the accounts/profile page. Pretty cool, eh?
But wait, there’s more!
There are some very interesting options available to the django-facebookconnect app, and I suggest you take a look at the installation instructions to learn more. Changing the page that Facebook redirects to after login might be particularly useful.
Letting your users utilize a pre-existing account, especially one that is most likely central to their internet lives, will encourage casual browsers to become actual users. Adding additional options, such as OpenID, is also advisable so you can capitalize on the wealth of data that’s already out there. Not having to worry about account management also frees up time to for you to streamline your application.