Backends¶
A Flask-Dance blueprint has a backend associated with it, which is simply an object that knows how to store and retrieve OAuth tokens from some kind of persistent storage. The default storage backend uses the Flask session to store OAuth tokens, which is simple and requires no configuration. However, when the user closes their browser, the OAuth token will be lost, so its not a good choice for production usage. Fortunately, Flask-Dance comes with some other backends to choose from.
SQLAlchemy¶
SQLAlchemy is the “standard” database for Flask applications, and Flask-Dance
has great support for it. First, define your database model with a token
column and a provider
column. Flask-Dance includes a
OAuthConsumerMixin
class to make this easier:
from flask_sqlalchemy import SQLAlchemy
from flask_dance.consumer.backend.sqla import OAuthConsumerMixin
db = SQLAlchemy()
class OAuth(db.Model, OAuthConsumerMixin):
pass
Next, create an instance of the SQLAlchemy backend and assign it to your blueprint:
from flask_dance.consumer.backend.sqla import SQLAlchemyBackend
blueprint.backend = SQLAlchemyBackend(OAuth, db.session)
And that’s all you need – if you don’t have user accounts in your application. If you do, it’s slightly more complicated:
from flask_sqlalchemy import SQLAlchemy
from flask_login import current_user
from flask_dance.consumer.backend.sqla import OAuthConsumerMixin, SQLAlchemyBackend
db = SQLAlchemy()
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
# ... other columns as needed
class OAuth(db.Model, OAuthConsumerMixin):
user_id = db.Column(db.Integer, db.ForeignKey(User.id))
user = db.relationship(User)
blueprint.backend = SQLAlchemyBackend(OAuth, db.session, user=current_user)
There are two things to notice here. One, the model that you use for storing
OAuth tokens must have a user relationship to the user that it is associated
with. Two, you must pass a reference to the currently logged-in user (if any)
to SQLAlchemyStorage
.
If you’re using Flask-Login, the current_user
proxy works great,
but you could instead pass a function that returns the current
user, if you want.
You also probably want to use a caching system for your database, so that it is more performant under heavy load. The SQLAlchemy token storage backend also integrates with Flask-Cache if you just pass an Flask-Cache instance to the backend, like this:
from flask import Flask
from flask_cache import Cache
app = Flask(__name__)
cache = Cache(app)
# setup Flask-Dance with SQLAlchemy models...
blueprint.backend = SQLAlchemyBackend(OAuth, db.session, cache=cache)
Custom¶
Of course, you don’t have to use SQLAlchemy, you’re free to use whatever
storage system you want. Writing a custom backend is easy:
just subclass flask_dance.consumer.backend.BaseBackend
and
override the get, set, and delete methods. For example, here’s a
backend that uses a file on disk:
import os
import os.path
import json
from flask_dance.consumer.backend import BaseBackend
class FileBackend(BaseBackend):
def __init__(self, filepath):
super(FileStorage, self).__init__()
self.filepath = filepath
def get(self, blueprint):
if not os.path.exists(self.filepath):
return None
with open(self.filepath) as f:
return json.load(f)
def set(self, blueprint, token):
with open(self.filepath, "w") as f:
json.dump(f)
def delete(self, blueprint):
os.remove(self.filepath)
Then, just create an instance of your backend and assign it to the
backend
attribute of your blueprint, and Flask-Dance will use it.