Flask-Social sets up endpoints for your app to make it easy for you to let your users connect and/or login using Facebook and Twitter. Flask-Social persists the connection information and allows you to get a configured instance of an API object with your user’s token so you can make API calls on behalf of them. Currently Facebook, Twitter, foursquare and Google are supported out of the box as long as you install the appropriate API library.
First, install Flask-Social:
$ mkvirtualenv app-name
$ pip install Flask-Social
Then install your datastore requirement.
SQLAlchemy:
$ pip install Flask-SQLAlchemy
MongoEngine:
$ pip install https://github.com/sbook/flask-mongoengine/tarball/master
Then install your provider API libraries.
Facebook:
$ pip install http://github.com/pythonforfacebook/facebook-sdk/tarball/master
Twitter:
$ pip install python-twitter
foursquare:
$ pip install foursquare
Google:
$ pip install oauth2client google-api-python-client
If you plan on allowing your users to connect with Facebook or Twitter, the first thing you’ll want to do is register an application with either service provider:
Bear in mind that Flask-Social requires Flask-Security. It would be a good idea to review the documentation for Flask-Security before moving on here as it assumes you have knowledge and a working Flask-Security app already.
After you register your application(s) you’ll need to configure your Flask app with the consumer key and secret. When dealing with Facebook, the consumer key is also referred to as the App ID/API Key. The following is an example of how to configure your application with your provider’s application values
Twitter:
app.config['SOCIAL_TWITTER'] = {
'consumer_key': 'twitter consumer key',
'consumer_secret': 'twitter consumer secret'
}
Facebook:
app.config['SOCIAL_FACEBOOK'] = {
'consumer_key': 'facebook app id',
'consumer_secret': 'facebook app secret'
}
foursquare:
app.config['SOCIAL_FOURSQUARE'] = {
'consumer_key': 'client id',
'consumer_secret': 'client secret'
}
Google:
app.config['SOCIAL_GOOGLE'] = {
'consumer_key': 'xxxx',
'consumer_secret': 'xxxx'
}
Next you’ll want to setup the Social extension and give it an instance of your datastore. In the following code the post login page is set to a hypothetical profile page instead of Flask-Security’s default of the root index:
# ... other required imports ...
from flask.ext.social import Social
from flask.ext.social.datastore import SQLAlchemyConnectionDatastore
# ... create the app ...
app.config['SECURITY_POST_LOGIN'] = '/profile'
db = SQLAlchemy(app)
# ... define user and role models ...
class Connection(db.Model):
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
provider_id = db.Column(db.String(255))
provider_user_id = db.Column(db.String(255))
access_token = db.Column(db.String(255))
secret = db.Column(db.String(255))
display_name = db.Column(db.String(255))
profile_url = db.Column(db.String(512))
image_url = db.Column(db.String(512))
rank = db.Column(db.Integer)
Security(app, SQLAlchemyUserDatastore(db, User, Role))
Social(app, SQLAlchemyConnectionDatastore(db, Connection))
In order to let users connect their Facebook or Twitter accounts you’ll want to add a mechanism on the profile page to do so. First the view method:
@app.route('/profile')
@login_required
def profile():
return render_template(
'profile.html',
content='Profile Page',
twitter_conn=social.twitter.get_connection(),
facebook_conn=social.facebook.get_connection(),
foursquare_conn=social.foursquare.get_connection())
You should notice the mechanism for retreiving the current user’s connection with each service provider. If a connection is not found, the value will be None. Now lets take a look at the profile template:
{% macro show_provider_button(provider_id, display_name, conn) %}
{% if conn %}
<form action="{{ url_for('social.remove_connection', provider_id=conn.provider_id, provider_user_id=conn.provider_user_id) }}" method="DELETE">
<input type="submit" value="Disconnect {{ display_name }}" />
</form>
{% else %}
<form action="{{ url_for('social.connect', provider_id=provider_id) }}" method="POST">
<input type="submit" value="Connect {{ display_name }}" />
</form>
{% endif %}
{% endmacro %}
{{ show_provider_button('twitter', 'Twitter', twitter_conn) }}
{{ show_provider_button('facebook', 'Facebook', facebook_conn) }}
{{ show_provider_button('foursquare', 'foursquare', foursquare_conn) }}
In the above template code a form is displayed depending on if a connection for the current user exists or not. If the connection exists a disconnect button is displayed and if it doesn’t exist a connect button is displayed. Clicking the connect button will initiate the OAuth flow with the given provider, allowing the user to authorize the application and return a token and/or secret to be used when configuring an API instance.
If a user has a connection established to a service provider then it is possible for them to login via the provider. A login form would look like the following:
<form action="{{ url_for('security.authenticate') }}" method="POST" name="login_form">
{{ form.hidden_tag() }}
{{ form.username.label }} {{ form.username }}<br/>
{{ form.password.label }} {{ form.password }}<br/>
{{ form.remember.label }} {{ form.remember }}<br/>
{{ form.submit }}
</form>
{% macro social_login(provider_id, display_name) %}
<form action="{{ url_for('social.login', provider_id=provider_id) }}" method="POST">
<input type="submit" value="Login with {{ display_name }}" />
</form>
{% endmacro %}
{{ social_login('twitter', 'Twitter' )}}
{{ social_login('facebook', 'Facebook' )}}
{{ social_login('foursquare', 'foursquare' )}}
In the above template code you’ll notice the regular username and password login form and forms for the user to login via Twitter, Facebook, and foursquare. If the user has an existing connection with the provider they will automatically be logged in without having to enter their username or password.
Flask Social is opinionated and uses available Python libraries when possible to interact with the API’s of the stock providers. This means that you’ll need to install the appropriate library for this functionality to work.
Configured instances of an API client are available via the get_api method of the provider instance. For example, lets say you wany to post the current user’s Twitter feed:
social = Social(...)
@app.route('/profile')
def profile():
twitter_api = social.twitter.get_api()
twitter_api.PostUpdate('hello from my Flask app!')
Initialize the application with the Social extension
Parameters: |
|
---|
See the Flask documentation on signals for information on how to use these signals in your code.
Sent when a user successfully authorizes a connection with a provider provider. In addition to the app (which is the sender), it is passed user, which is the current user and connection which is the connection that was created
Sent when a user attempts to authorize a connection with a provider but it fails because it already exists. In addition to the app (which is the sender), it is passed user, which is the current user
Sent when a user removes a connection to a provider. In addition to the app (which is the sender), it is passed user, which is the current user and provider_id which is the ID of the provider that was removed
Sent when a login attempt via a provider fails. In addition to the app (which is the sender), it is passed provider which is the service provider, and oauth_response which is the response returned by the provider
Sent when a login attempt via a provider fails. In addition to the app (which is the sender), it is passed provider which is the service provider, and user which is the current user