A Flask-Dance blueprint has a token storage associated with it, which is an object that knows how to store and retrieve OAuth tokens from some kind of persistent storage. A storage is most often some kind of database, but it doesn’t have to be.
The default token storage uses the Flask session to store OAuth tokens, which is simple and requires no configuration. However, when the user closes their browser, their OAuth token will be lost, so its not a good choice for production usage.
This is a great option for hobby projects, and for a “proof of concept” to show that an idea is viable.
SQLAlchemy is the “standard” ORM for Flask applications, and Flask-Dance
has great support for it. First, define your database model with a
column and a
provider column. Flask-Dance includes a
class to make this easier:
from flask_sqlalchemy import SQLAlchemy from flask_dance.consumer.storage.sqla import OAuthConsumerMixin db = SQLAlchemy() class OAuth(OAuthConsumerMixin, db.Model): pass
Next, create an instance of the SQLAlchemy storage and assign it to your blueprint:
from flask_dance.consumer.storage.sqla import SQLAlchemyStorage blueprint.storage = SQLAlchemyStorage(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.storage.sqla import OAuthConsumerMixin, SQLAlchemyStorage db = SQLAlchemy() class User(db.Model): id = db.Column(db.Integer, primary_key=True) # ... other columns as needed class OAuth(OAuthConsumerMixin, db.Model): user_id = db.Column(db.Integer, db.ForeignKey(User.id)) user = db.relationship(User) blueprint.storage = SQLAlchemyStorage(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)
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 also integrates with Flask-Caching if you pass an instance of Flask-Caching to the storage, like this:
from flask import Flask from flask_caching import Cache app = Flask(__name__) cache = Cache(app) # setup Flask-Dance with SQLAlchemy models... blueprint.storage = SQLAlchemyStorage(OAuth, db.session, cache=cache)
Of course, you don’t have to use SQLAlchemy, you’re free to use whatever
storage system you want. Writing a custom token storage is easy:
For example, here’s a storage that uses a file on disk:
import os import os.path import json from flask_dance.consumer.storage import BaseStorage class FileStorage(BaseStorage): 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(token, f) def delete(self, blueprint): os.remove(self.filepath)
Then, just create an instance of your storage and assign it to the
storage attribute of your blueprint, and Flask-Dance will use it.