Facebook Authentication for Flask Apps

Ok, it looks like you want to add Facebook login to your Flask app.

If you followed my first tutorial on Flask apps, you might have something like this in your app.py:

import os
from flask import Flask, render_template, send_from_directory

#----------------------------------------
# initialization
#----------------------------------------

app = Flask(__name__)

app.config.update(
    DEBUG = True,
)

#----------------------------------------
# controllers
#----------------------------------------

@app.route('/favicon.ico')
def favicon():
    return send_from_directory(os.path.join(app.root_path, 'static'), 'ico/favicon.ico')

@app.errorhandler(404)
def page_not_found(e):
    return render_template('404.html'), 404

@app.route("/")
def index():
    return render_template('index.html')

#----------------------------------------
# launch
#----------------------------------------

if __name__ == "__main__":
    port = int(os.environ.get("PORT", 5000))
    app.run(host='0.0.0.0', port=port)

It is likely that your Flask app will look different, as you may have added a few things. Just make sure it is working before you continue.

register your app on Facebook

Go to https://developers.facebook.com/apps/ and create a new app.

Make sure the "App Domains" section and the "Website with Facebook Login" section have the domain you will be deploying to. If you are using Heroku, it may look like this: "some-crazy-name.herokuapp.com".

configure your hosts file

Open your hosts file (if you're not sure where this file is, check this guide and add the following line:

127.0.0.1 some-crazy-name.herokuapp.com

This will allow you to develop locally without Facebook complaining.

install OAuth

sudo pip install Flask-OAuth

pip freeze > requirements.txt

add in the code

Add the section below into your app.py, and make sure to replace the FACEBOOK_APP_ID and FACEBOOK_APP_SECRET with the ones that correspond to your newly registered app on Facebook. Also make sure that your secret key is set (e.g. app.config["SECRET_KEY"] = '\x01...').

#----------------------------------------
# facebook authentication
#----------------------------------------

from flask import url_for, request, session, redirect
from flask_oauth import OAuth

FACEBOOK_APP_ID = '000000000000000'
FACEBOOK_APP_SECRET = '0a0b0c00000000000000000000x0y0z0'

oauth = OAuth()

facebook = oauth.remote_app('facebook',
    base_url='https://graph.facebook.com/',
    request_token_url=None,
    access_token_url='/oauth/access_token',
    authorize_url='https://www.facebook.com/dialog/oauth',
    consumer_key=FACEBOOK_APP_ID,
    consumer_secret=FACEBOOK_APP_SECRET,
    request_token_params={'scope': ('email, ')}
)

@facebook.tokengetter
def get_facebook_token():
    return session.get('facebook_token')

def pop_login_session():
    session.pop('logged_in', None)
    session.pop('facebook_token', None)

@app.route("/facebook_login")
def facebook_login():
    return facebook.authorize(callback=url_for('facebook_authorized',
        next=request.args.get('next'), _external=True))

@app.route("/facebook_authorized")
@facebook.authorized_handler
def facebook_authorized(resp):
    next_url = request.args.get('next') or url_for('index')
    if resp is None or 'access_token' not in resp:
        return redirect(next_url)

    session['logged_in'] = True
    session['facebook_token'] = (resp['access_token'], '')

    return redirect(next_url)

@app.route("/logout")
def logout():
    pop_login_session()
    return redirect(url_for('index'))

Go to /facebook_login to test it out.

update your views

If you have a section that looks like this,

<ul class="nav pull-right">
    {% if not session.logged_in %}
    <li><a href="#">Login or Signup</a></li>
    {% else %}
    <li><a href="#">Logout</a></li>
    {% endif %}
</ul>

Update it to look like this:

<ul class="nav pull-right">
    {% if not session.logged_in %}
    <li><a href="/facebook_login">Login or Signup</a></li>
    {% else %}
    <li><a href="/logout">Logout</a></li>
    {% endif %}
</ul>

get user data from Facebook

If your user is logged in, you can submit any Facebook query with facebook.get(). Here is an example:

data = facebook.get('/me').data
if 'id' in data and 'name' in data:
    user_id = data['id']
    user_name = data['name']

And that's it! You're done! Your users can now authorize with Facebook and login and logout with your app.

bonus: add Facebook og (Open Graph) tags

Place the following in base.html anywhere in the head section (a good place would be below the existing meta tags).

<meta property="og:title" content=""/>
<meta property="og:type" content=""/>
<meta property="og:url" content=""/>
<meta property="og:image" content="" />
<meta property="og:site_name" content=""/>
<meta property="og:description" content=""/>

Make sure to fill in the content="" fields. For og:site_name, for instance, you could use content="MY_NEW_APP".

Check out Facebook's open graph protocol site for more guidelines on how to fill in the various properties.

Ryan Shea

Co-Founder of OneName.io. Hacking on Bitcoin. Trying to build the identity layer of the Internet.


comments powered by Disqus