Flask-Dance

Doing the OAuth dance with style using Flask, requests, and oauthlib. Currently, only OAuth consumers are supported, but this project could easily support OAuth providers in the future, as well.

User Guide:

Installation

Use pip to install Flask-Dance. To use basic functionality, run this:

$ pip install Flask-Dance

To also use the SQLAlchemy backend, specify the sqla extra, like this:

$ pip install Flask-Dance[sqla]

Library development

Use tox to execute unit tests on multiple python versions. You can also use tox to build the documentation.

Quickstarts

Contents:

GitHub Quickstart

Set up the application

Visit https://github.com/settings/applications/new to register an application on GitHub. The application’s “authorization callback URL” must be http://localhost:5000/login/github/authorized. Take note of the “Client ID” and “Client Secret” for the application.

Code

from flask import Flask, redirect, url_for
from flask_dance.contrib.github import make_github_blueprint, github

app = Flask(__name__)
app.secret_key = "supersekrit"
blueprint = make_github_blueprint(
    client_id="my-key-here",
    client_secret="my-secret-here",
)
app.register_blueprint(blueprint, url_prefix="/login")

@app.route("/")
def index():
    if not github.authorized:
        return redirect(url_for("github.login"))
    resp = github.get("/user")
    assert resp.ok
    return "You are @{login} on GitHub".format(login=resp.json()["login"])

if __name__ == "__main__":
    app.run()

Note

You must replace my-key-here and my-secret-here with the client ID and client secret that you got from your GitHub application.

Note

If you are running this code on Heroku, you’ll need to use the werkzeug.contrib.fixers.ProxyFix middleware. See Proxies and HTTPS.

If you run this code locally or without HTTPS enabled (see warning below), you must set the OAUTHLIB_INSECURE_TRANSPORT environment variable to to disable the HTTPS requirement imposed by oauthlib, which is part of Flask-Dance. For example, if you put this code in a file named github.py on your machine, you could run:

$ export OAUTHLIB_INSECURE_TRANSPORT=1
$ python github.py

Visit http://localhost:5000 in your browser, and you should start the OAuth dance immediately.

Warning

OAUTHLIB_INSECURE_TRANSPORT should only be used for local testing or over trusted connections. By default, all OAuth interactions must occur over secure https connections (this is enforced by oauthlib). However, setting OAUTHLIB_INSECURE_TRANSPORT disables this enforcement and allows OAuth to occur over insecure http connections.

Explanation

This code makes a blueprint that implements the views necessary to be a consumer in the OAuth dance. The blueprint has two views: /github, which is the view that the user visits to begin the OAuth dance, and /github/authorized, which is the view that the user is redirected to at the end of the OAuth dance. Because we set the url_prefix to be /login, the end result is that the views are at /login/github and /login/github/authorized. The second view is the “authorized callback URL” that you must tell GitHub about when you create the application.

The github variable is a requests.Session instance, which will be be preloaded with the user’s access token once the user has gone through the OAuth dance. You can check the github.authorized boolean to determine if the access token is loaded. Whether the access token is loaded or not, you can use all the normal requests methods, like get() and post(), to make HTTP requests. If you only specify the path component of the URL, the domain will default to https://api.github.com.

Google Quickstart

Set up the application

Visit the Google Developers Console at https://console.developers.google.com and create a new project. In the “APIs & auth” section, click on “Credentials”, and then click the “Create a new Client ID” button. Select “Web Application” for the application type, and click the “Configure consent screen” button. Put in your application information, and click Save. Once you’ve done that, you’ll see two new fields: “Authorized JavaScript origins” and “Authorized redirect URIs”. Put http://localhost:5000/login/google/authorized into “Authorized redirect URIs”, and click “Create Client ID”. Take note of the “Client ID” and “Client Secret” for the application.

Code

from flask import Flask, redirect, url_for
from flask_dance.contrib.google import make_google_blueprint, google

app = Flask(__name__)
app.secret_key = "supersekrit"
blueprint = make_google_blueprint(
    client_id="my-key-here",
    client_secret="my-secret-here",
    scope=[
        "https://www.googleapis.com/auth/plus.me",
        "https://www.googleapis.com/auth/userinfo.email",
    ]
)
app.register_blueprint(blueprint, url_prefix="/login")

@app.route("/")
def index():
    if not google.authorized:
        return redirect(url_for("google.login"))
    resp = google.get("/oauth2/v2/userinfo")
    assert resp.ok, resp.text
    return "You are {email} on Google".format(email=resp.json()["email"])

if __name__ == "__main__":
    app.run()

Note

You must replace my-key-here and my-secret-here with the client ID and client secret that you got from your Google application.

Note

If you are running this code on Heroku, you’ll need to use the werkzeug.contrib.fixers.ProxyFix middleware. See Proxies and HTTPS.

Note

If you set the hosted_domain argument of make_google_blueprint, be aware that this only provides UI optimization and is not a way of restricting access to users of a single domain. See the make_google_blueprint documentation warning.

If you run this code locally or without HTTPS enabled (see warning below), you must set the OAUTHLIB_INSECURE_TRANSPORT environment variable to to disable the HTTPS requirement imposed by oauthlib, which is part of Flask-Dance. For example, if you put this code in a file named google.py on your machine, you could run:

$ export OAUTHLIB_INSECURE_TRANSPORT=1
$ export OAUTHLIB_RELAX_TOKEN_SCOPE=1
$ python google.py

Visit http://localhost:5000 in your browser, and you should start the OAuth dance immediately.

Warning

OAUTHLIB_INSECURE_TRANSPORT should only be used for local testing or over trusted connections. By default, all OAuth interactions must occur over secure https connections (this is enforced by oauthlib). However, setting OAUTHLIB_INSECURE_TRANSPORT disables this enforcement and allows OAuth to occur over insecure http connections.

However, you can (and probably should) set OAUTHLIB_RELAX_TOKEN_SCOPE when running in production.

Explanation

This code makes a blueprint that implements the views necessary to be a consumer in the OAuth dance. The blueprint has two views: /google, which is the view that the user visits to begin the OAuth dance, and /google/authorized, which is the view that the user is redirected to at the end of the OAuth dance. Because we set the url_prefix to be /login, the end result is that the views are at /login/google and /login/google/authorized. The second view is the “authorized redirect URI” that you must tell Google about when you create the application.

The google variable is a requests.Session instance, which will be be preloaded with the user’s access token once the user has gone through the OAuth dance. You can check the google.authorized boolean to determine if the access token is loaded. Whether the access token is loaded or not, you can use all the normal requests methods, like get() and post(), to make HTTP requests. If you only specify the path component of the URL, the domain will default to https://www.googleapis.com.

Twitter Quickstart

Set up the application

Go to Twitter Application Manager at https://apps.twitter.com and create a new app. The application’s “Callback URL” must be http://localhost:5000/login/twitter/authorized. Take note of the “API Key” and “API Secret” for the application.

Code

from flask import Flask, redirect, url_for
from flask_dance.contrib.twitter import make_twitter_blueprint, twitter

app = Flask(__name__)
app.secret_key = "supersekrit"
blueprint = make_twitter_blueprint(
    api_key="my-key-here",
    api_secret="my-secret-here",
)
app.register_blueprint(blueprint, url_prefix="/login")

@app.route("/")
def index():
    if not twitter.authorized:
        return redirect(url_for("twitter.login"))
    resp = twitter.get("account/settings.json")
    assert resp.ok
    return "You are @{screen_name} on Twitter".format(screen_name=resp.json()["screen_name"])

if __name__ == "__main__":
    app.run()

Note

You must replace my-key-here and my-secret-here with the API key and API secret that you got from your Twitter application.

Note

If you are running this code on Heroku, you’ll need to use the werkzeug.contrib.fixers.ProxyFix middleware. See Proxies and HTTPS.

If you run this code locally or without HTTPS enabled (see warning below), you must set the OAUTHLIB_INSECURE_TRANSPORT environment variable to to disable the HTTPS requirement imposed by oauthlib, which is part of Flask-Dance. For example, if you put this code in a file named twitter.py on your machine, you could run:

$ export OAUTHLIB_INSECURE_TRANSPORT=1
$ python twitter.py

Visit http://localhost:5000 in your browser, and you should start the OAuth dance immediately.

Warning

OAUTHLIB_INSECURE_TRANSPORT should only be used for local testing or over trusted connections. By default, all OAuth interactions must occur over secure https connections (this is enforced by oauthlib). However, setting OAUTHLIB_INSECURE_TRANSPORT disables this enforcement and allows OAuth to occur over insecure http connections.

Explanation

This code makes a blueprint that implements the views necessary to be a consumer in the OAuth dance. The blueprint has two views: /twitter, which is the view that the user visits to begin the OAuth dance, and /twitter/authorized, which is the view that the user is redirected to at the end of the OAuth dance. Because we set the url_prefix to be /login, the end result is that the views are at /login/twitter and /login/twitter/authorized. The second view is the “Callback URL” that you must tell Twitter about when you create the application.

The twitter variable is a requests.Session instance, which will be be preloaded with the user’s access token once the user has gone through the OAuth dance. You can check the twitter.authorized boolean to determine if the access token is loaded. Whether the access token is loaded or not, you can use all the normal requests methods, like get() and post(), to make HTTP requests. If you only specify the path component of the URL, the domain will default to https://www.googleapis.com.

Dropbox Quickstart

Set up the application

Visit the Dropbox App Console at https://www.dropbox.com/developers/apps and create a new app. Select “Dropbox API app”, not “Drop-ins app”. Decide if your app can be limited to its own folder, provide an app name, and agree to the terms of service. Once the app has been created, you need to add at least one redirect URI under the OAuth 2 section: put in http://localhost:5000/login/dropbox/authorized and click Add. Take note of the “App key” and “App Secret” for the application.

Code

from flask import Flask, redirect, url_for
from flask_dance.contrib.dropbox import make_dropbox_blueprint, dropbox

app = Flask(__name__)
app.secret_key = "supersekrit"
blueprint = make_dropbox_blueprint(
    app_key="my-key-here",
    app_secret="my-secret-here",
)
app.register_blueprint(blueprint, url_prefix="/login")

@app.route("/")
def index():
    if not dropbox.authorized:
        return redirect(url_for("dropbox.login"))
    resp = dropbox.post("users/get_current_account")
    assert resp.ok
    return "You are {email} on Dropbox".format(email=resp.json()["email"])

if __name__ == "__main__":
    app.run()

Note

You must replace my-key-here and my-secret-here with the client ID and client secret that you got from your Dropbox application.

Note

If you are running this code on Heroku, you’ll need to use the werkzeug.contrib.fixers.ProxyFix middleware. See Proxies and HTTPS.

If you run this code locally or without HTTPS enabled (see warning below), you must set the OAUTHLIB_INSECURE_TRANSPORT environment variable to to disable the HTTPS requirement imposed by oauthlib, which is part of Flask-Dance. For example, if you put this code in a file named dropbox.py on your machine, you could run:

$ export OAUTHLIB_RELAX_TOKEN_SCOPE=1
$ python dropbox.py

Visit http://localhost:5000 in your browser, and you should start the OAuth dance immediately.

Warning

OAUTHLIB_INSECURE_TRANSPORT should only be used for local testing or over trusted connections. By default, all OAuth interactions must occur over secure https connections (this is enforced by oauthlib). However, setting OAUTHLIB_INSECURE_TRANSPORT disables this enforcement and allows OAuth to occur over insecure http connections.

Explanation

This code makes a blueprint that implements the views necessary to be a consumer in the OAuth dance. The blueprint has two views: /dropbox, which is the view that the user visits to begin the OAuth dance, and /dropbox/authorized, which is the view that the user is redirected to at the end of the OAuth dance. Because we set the url_prefix to be /login, the end result is that the views are at /login/dropbox and /login/dropbox/authorized. The second view is the “redirect URI” that you must tell Dropbox about when you create the app.

The dropbox variable is a requests.Session instance, which will be be preloaded with the user’s access token once the user has gone through the OAuth dance. You can check the dropbox.authorized boolean to determine if the access token is loaded. Whether the access token is loaded or not, you can use all the normal requests methods, like get() and post(), to make HTTP requests. If you only specify the path component of the URL, the domain will default to https://api.dropbox.com.

Meetup Quickstart

Set up the application

Visit the Meetup OAuth Consumer page at https://secure.meetup.com/meetup_api/oauth_consumers/ and create a new consumer. Put in http://localhost:5000/login/meetup/authorized for the redirect URI. Agree to the terms of service, and register your consumer to get an OAuth key and secret.

Code

from flask import Flask, redirect, url_for
from flask_dance.contrib.meetup import make_meetup_blueprint, meetup

app = Flask(__name__)
app.secret_key = "supersekrit"
blueprint = make_meetup_blueprint(
    key="my-key-here",
    secret="my-secret-here",
)
app.register_blueprint(blueprint, url_prefix="/login")

@app.route("/")
def index():
    if not meetup.authorized:
        return redirect(url_for("meetup.login"))
    resp = meetup.get("member/self")
    assert resp.ok
    return "You are {name} on Meetup".format(name=resp.json()["name"])

if __name__ == "__main__":
    app.run()

Note

You must replace my-key-here and my-secret-here with the client ID and client secret that you got from your Meetup application.

Note

If you are running this code on Heroku, you’ll need to use the werkzeug.contrib.fixers.ProxyFix middleware. See Proxies and HTTPS.

If you run this code locally or without HTTPS enabled (see warning below), you must set the OAUTHLIB_INSECURE_TRANSPORT environment variable to to disable the HTTPS requirement imposed by oauthlib, which is part of Flask-Dance. For example, if you put this code in a file named meetup.py on your machine, you could run:

$ export OAUTHLIB_RELAX_TOKEN_SCOPE=1
$ python meetup.py

Visit http://localhost:5000 in your browser, and you should start the OAuth dance immediately.

Warning

OAUTHLIB_INSECURE_TRANSPORT should only be used for local testing or over trusted connections. By default, all OAuth interactions must occur over secure https connections (this is enforced by oauthlib). However, setting OAUTHLIB_INSECURE_TRANSPORT disables this enforcement and allows OAuth to occur over insecure http connections.

Explanation

This code makes a blueprint that implements the views necessary to be a consumer in the OAuth dance. The blueprint has two views: /meetup, which is the view that the user visits to begin the OAuth dance, and /meetup/authorized, which is the view that the user is redirected to at the end of the OAuth dance. Because we set the url_prefix to be /login, the end result is that the views are at /login/meetup and /login/meetup/authorized. The second view is the “redirect URI” that you must tell Meetup about when you create the app.

The meetup variable is a requests.Session instance, which will be be preloaded with the user’s access token once the user has gone through the OAuth dance. You can check the meetup.authorized boolean to determine if the access token is loaded. Whether the access token is loaded or not, you can use all the normal requests methods, like get() and post(), to make HTTP requests. If you only specify the path component of the URL, the domain will default to https://api.meetup.com.

Slack Quickstart

Set up the application

Visit https://api.slack.com/applications/new to register an application on Slack. The application’s “Redirect URI(s)” must contain http://localhost:5000/login/slack/authorized. Take note of the “Client ID” and “Client Secret” for the application.

Code

from flask import Flask, redirect, url_for
from flask_dance.contrib.slack import make_slack_blueprint, slack

app = Flask(__name__)
app.secret_key = "supersekrit"
blueprint = make_slack_blueprint(
    client_id="my-key-here",
    client_secret="my-secret-here",
    scope=["identify", "chat:write:bot"],
)
app.register_blueprint(blueprint, url_prefix="/login")

@app.route("/")
def index():
    if not slack.authorized:
        return redirect(url_for("slack.login"))
    resp = slack.post("chat.postMessage", data={
        "channel": "#general",
        "text": "Hello, world!",
        "icon_emoji": ":robot_face:",
    })
    assert resp.json()["ok"], resp.text
    return 'I just said "Hello, world!" in the #general channel!'

if __name__ == "__main__":
    app.run()

Note

You must replace my-key-here and my-secret-here with the client ID and client secret that you got from your Slack application.

Note

If you are running this code on Heroku, you’ll need to use the werkzeug.contrib.fixers.ProxyFix middleware. See Proxies and HTTPS.

When you run this code locally, you must set the OAUTHLIB_INSECURE_TRANSPORT environment variable for it to work. You also must set the OAUTHLIB_RELAX_TOKEN_SCOPE environment variable to account for Slack changing the requested OAuth scopes on you. For example, if you put this code in a file named slack.py, you could run:

$ export OAUTHLIB_INSECURE_TRANSPORT=1
$ export OAUTHLIB_RELAX_TOKEN_SCOPE=1
$ python slack.py

Visit http://localhost:5000 in your browser, and you should start the OAuth dance immediately.

Warning

OAUTHLIB_INSECURE_TRANSPORT should only be used for local testing or over trusted connections. By default, all OAuth interactions must occur over secure https connections (this is enforced by oauthlib). However, setting OAUTHLIB_INSECURE_TRANSPORT disables this enforcement and allows OAuth to occur over insecure http connections.

However, you can (and probably should) set OAUTHLIB_RELAX_TOKEN_SCOPE when running in production.

Explanation

This code makes a blueprint that implements the views necessary to be a consumer in the OAuth dance. The blueprint has two views: /slack, which is the view that the user visits to begin the OAuth dance, and /slack/authorized, which is the view that the user is redirected to at the end of the OAuth dance. Because we set the url_prefix to be /login, the end result is that the views are at /login/slack and /login/slack/authorized. The second view is the “Redirect URI” that you must tell Slack about when you create the application.

The slack variable is a requests.Session instance, which will be be preloaded with the user’s access token once the user has gone through the OAuth dance. You can check the slack.authorized boolean to determine if the access token is loaded. Whether the access token is loaded or not, you can use all the normal requests methods, like get() and post(), to make HTTP requests. If you only specify the Slack method name you want to call, the rest of the URL will be filled in for you. For example, if you want to make a request to https://slack.com/api/auth.test, you can simply refer to auth.test.

Azure Quickstart

Set up the application

Visit https://apps.dev.microsoft.com/ to register an application on Azure AD. The application’s “Redirect URI” must be http://localhost:5000/login/azure/authorized. You can also follow the detailed steps described at: https://azure.microsoft.com/en-us/documentation/articles/active-directory-v2-app-registration/ Take note of the “Application ID” (Client ID) and “Password” (Client Secret) for the application.

Code

from flask import Flask, redirect, url_for
from flask_dance.contrib.azure import make_azure_blueprint, azure

app = Flask(__name__)
app.secret_key = "supersekrit"
blueprint = make_azure_blueprint(
    client_id="my-key-here",
    client_secret="my-secret-here",
)
app.register_blueprint(blueprint, url_prefix="/login")

@app.route("/")
def index():
    if not azure.authorized:
        return redirect(url_for("azure.login"))
    resp = azure.get("/v1.0/me")
    assert resp.ok
    return "You are {mail} on Azure AD".format(mail=resp.json()["userPrincipalName"])

if __name__ == "__main__":
    app.run()

Note

You must replace my-key-here and my-secret-here with the client ID and client secret that you got from your Azure application.

Note

If you are running this code on Heroku, you’ll need to use the werkzeug.contrib.fixers.ProxyFix middleware. See Proxies and HTTPS.

If you run this code locally or without HTTPS enabled (see warning below), you must set the OAUTHLIB_INSECURE_TRANSPORT environment variable to disable the HTTPS requirement imposed by oauthlib, which is part of Flask-Dance. For example, if you put this code in a file named azure.py on your machine, you could run:

$ export OAUTHLIB_INSECURE_TRANSPORT=1
$ python azure.py

Visit http://localhost:5000 in your browser, and you should start the OAuth dance immediately.

Warning

OAUTHLIB_INSECURE_TRANSPORT should only be used for local testing or over trusted connections. By default, all OAuth interactions must occur over secure https connections (this is enforced by oauthlib). However, setting OAUTHLIB_INSECURE_TRANSPORT disables this enforcement and allows OAuth to occur over insecure http connections.

Explanation

This code makes a blueprint that implements the views necessary to be a consumer in the OAuth dance. The blueprint has two views: /azure, which is the view that the user visits to begin the OAuth dance, and /azure/authorized, which is the view that the user is redirected to at the end of the OAuth dance. Because we set the url_prefix to be /login, the end result is that the views are at /login/azure and /login/azure/authorized. The second view is the “authorized callback URL” that you must tell Azure about when you create the application.

The azure variable is a requests.Session instance, which will be be preloaded with the user’s access token once the user has gone through the OAuth dance. You can check the azure.authorized boolean to determine if the access token is loaded. Whether the access token is loaded or not, you can use all the normal requests methods, like get() and post(), to make HTTP requests. If you only specify the path component of the URL, the domain will default to https://graph.microsoft.com.

Nylas Quickstart

Set up the application

Visit https://developer.nylas.com/ to sign up for a Nylas Developer account. On the Nylas Developer dashboard, click on the “Settings” button, and in the “Callbacks” tab, add http://localhost:5000/login/nylas/authorized as a callback URL. Take note of the API ID and API Secret displayed on the dashboard.

Code

from flask import Flask, redirect, url_for
from flask_dance.contrib.nylas import make_nylas_blueprint, nylas

app = Flask(__name__)
app.secret_key = "supersekrit"
nylas_bp = make_nylas_blueprint(
    app_id="my-app-id-here",
    app_secret="my-app-secret-here",
)
app.register_blueprint(nylas_bp, url_prefix="/login")

@app.route("/")
def index():
    if not nylas.authorized:
        return redirect(url_for("nylas.login"))
    resp = nylas.get("/account")
    assert resp.ok
    return "You are {name} on Nylas".format(name=resp.json()["name"])

if __name__ == "__main__":
    app.run()

Note

You must replace my-key-here and my-secret-here with the API ID and API Secret that you got from the Nylas Developer dashboard.

Note

If you are running this code on Heroku, you’ll need to use the werkzeug.contrib.fixers.ProxyFix middleware. See Proxies and HTTPS.

If you run this code locally or without HTTPS enabled (see warning below), you must set the OAUTHLIB_INSECURE_TRANSPORT environment variable to to disable the HTTPS requirement imposed by oauthlib, which is part of Flask-Dance. For example, if you put this code in a file named nylas.py on your machine, you could run:

$ export OAUTHLIB_INSECURE_TRANSPORT=1
$ python nylas.py

Visit http://localhost:5000 in your browser, and you should start the OAuth dance immediately.

Warning

OAUTHLIB_INSECURE_TRANSPORT should only be used for local testing or over trusted connections. By default, all OAuth interactions must occur over secure https connections (this is enforced by oauthlib). However, setting OAUTHLIB_INSECURE_TRANSPORT disables this enforcement and allows OAuth to occur over insecure http connections.

Explanation

This code makes a blueprint that implements the views necessary to be a consumer in the OAuth dance. The blueprint has two views: /nylas, which is the view that the user visits to begin the OAuth dance, and /nylas/authorized, which is the view that the user is redirected to at the end of the OAuth dance. Because we set the url_prefix to be /login, the end result is that the views are at /login/nylas and /login/nylas/authorized. The second view is the callback URL that you must tell Nylas about when you create your developer account.

The nylas variable is a requests.Session instance, which will be be preloaded with the user’s access token once the user has gone through the OAuth dance. You can check the nylas.authorized boolean to determine if the access token is loaded. Whether the access token is loaded or not, you can use all the normal requests methods, like get() and post(), to make HTTP requests. If you only specify the path component of the URL, the domain will default to https://api.nylas.com/.

SQLAlchemy Multi-User Quickstart

This quickstart will help you get started with a multi-user application where OAuth tokens are stored using the SQLAlchemy backend. You should already be familiar with setting up a single-use Flask-Dance application – you can consult some of the other quickstarts for that.

Further details are available in the documentation for Multi-User Setups.

Code

Create a file called multi.py with the following contents:

import sys
from flask import Flask, redirect, url_for, flash, render_template
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.orm.exc import NoResultFound
from flask_dance.contrib.github import make_github_blueprint, github
from flask_dance.consumer.backend.sqla import OAuthConsumerMixin, SQLAlchemyBackend
from flask_dance.consumer import oauth_authorized, oauth_error
from flask_login import (
    LoginManager, UserMixin, current_user,
    login_required, login_user, logout_user
)

# setup Flask application
app = Flask(__name__)
app.secret_key = "supersekrit"
blueprint = make_github_blueprint(
    client_id="my-key-here",
    client_secret="my-secret-here",
)
app.register_blueprint(blueprint, url_prefix="/login")

# setup database models
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///multi.db"
db = SQLAlchemy()

class User(db.Model, UserMixin):
    id = db.Column(db.Integer, primary_key=True)
    # Your User model can include whatever columns you want: Flask-Dance doesn't care.
    # Here are a few columns you might find useful, but feel free to modify them
    # as your application needs!
    username = db.Column(db.String(256), unique=True)
    email = db.Column(db.String(256), unique=True)
    name = db.Column(db.String(256))

class OAuth(OAuthConsumerMixin, db.Model):
    provider_user_id = db.Column(db.String(256), unique=True)
    user_id = db.Column(db.Integer, db.ForeignKey(User.id))
    user = db.relationship(User)

# setup login manager
login_manager = LoginManager()
login_manager.login_view = 'github.login'

@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))

# setup SQLAlchemy backend
blueprint.backend = SQLAlchemyBackend(OAuth, db.session, user=current_user)

# create/login local user on successful OAuth login
@oauth_authorized.connect_via(blueprint)
def github_logged_in(blueprint, token):
    if not token:
        flash("Failed to log in with GitHub.", category="error")
        return False

    resp = blueprint.session.get("/user")
    if not resp.ok:
        msg = "Failed to fetch user info from GitHub."
        flash(msg, category="error")
        return False

    github_info = resp.json()
    github_user_id = str(github_info["id"])

    # Find this OAuth token in the database, or create it
    query = OAuth.query.filter_by(
        provider=blueprint.name,
        provider_user_id=github_user_id,
    )
    try:
        oauth = query.one()
    except NoResultFound:
        oauth = OAuth(
            provider=blueprint.name,
            provider_user_id=github_user_id,
            token=token,
        )

    if oauth.user:
        login_user(oauth.user)
        flash("Successfully signed in with GitHub.")

    else:
        # Create a new local user account for this user
        user = User(
            # Remember that `email` can be None, if the user declines
            # to publish their email address on GitHub!
            email=github_info["email"],
            name=github_info["name"],
        )
        # Associate the new local user account with the OAuth token
        oauth.user = user
        # Save and commit our database models
        db.session.add_all([user, oauth])
        db.session.commit()
        # Log in the new local user account
        login_user(user)
        flash("Successfully signed in with GitHub.")

    # Disable Flask-Dance's default behavior for saving the OAuth token
    return False

# notify on OAuth provider error
@oauth_error.connect_via(blueprint)
def github_error(blueprint, error, error_description=None, error_uri=None):
    msg = (
        "OAuth error from {name}! "
        "error={error} description={description} uri={uri}"
    ).format(
        name=blueprint.name,
        error=error,
        description=error_description,
        uri=error_uri,
    )
    flash(msg, category="error")

@app.route("/logout")
@login_required
def logout():
    logout_user()
    flash("You have logged out")
    return redirect(url_for("index"))

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

# hook up extensions to app
db.init_app(app)
login_manager.init_app(app)

if __name__ == "__main__":
    if "--setup" in sys.argv:
        with app.app_context():
            db.create_all()
            db.session.commit()
            print("Database tables created")
    else:
        app.run(debug=True)

Make a templates directory next to multi.py. In that directory, create a file called home.html with the following contents:

<!DOCTYPE html>
<head>
    <title>Flask-Dance Multi-User SQLAlchemy</title>
</head>
<body>
{% with messages = get_flashed_messages(with_categories=true) %}
  {% if messages %}
    <ul class="flash">
    {% for category, message in messages %}
      <li class="{{ category }}">{{ message }}</li>
    {% endfor %}
    </ul>
  {% endif %}
{% endwith %}
{% if current_user.is_authenticated %}
  You are logged in as {{ current_user.username }}!
  <a href="{{ url_for("logout") }}">Log out</a>
{% else %}
  You are not logged in.
  <a href="{{ url_for("github.login") }}">Log in</a>
{% endif %}
</body>

For this to work properly, you must also do these things:

  1. Register an application with GitHub, where the “authorization callback URL” is http://localhost:5000/login/github/authorized
  2. Replace my-key-here and my-secret-here with the client ID and client secret that you got from your GitHub application
  3. Install Flask-Dance, Flask-SQLAlchemy, Flask-Login, and blinker
  4. Run python multi.py --setup to create your sqlite database
  5. Set the OAUTHLIB_INSECURE_TRANSPORT environment variable, so OAuthlib doesn’t complain about running over http (for testing only!)
  6. Run python multi.py to run the application, and visit http://localhost:5000 in your browser.

Explanation

There’s a lot going on here, so let’s break it down. This code uses Flask-Dance, Flask-SQLAlchemy for a database, and Flask-Login for user management. It also hooks into several signals, powered by the blinker library.

# setup Flask application
app = Flask(__name__)
app.secret_key = "supersekrit"
blueprint = make_github_blueprint(
    client_id="my-key-here",
    client_secret="my-secret-here",
)
app.register_blueprint(blueprint, url_prefix="/login")

This is the standard pattern for creating a Flask-Dance blueprint and attaching it to your Flask application.

# setup database models
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///multi.db"
db = SQLAlchemy()

class User(db.Model, UserMixin):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(256), unique=True)
    # ... other columns as needed

class OAuth(OAuthConsumerMixin, db.Model):
    provider_user_id = db.Column(db.String(256), unique=True)
    user_id = db.Column(db.Integer, db.ForeignKey(User.id))
    user = db.relationship(User)

This code sets up Flask-SQLAlchemy, and configures it to use a sqlite database called multi.db. You can change this to use any database that SQLAlchemy supports. This code also defines two database models: a User model that inherits from flask_login.UserMixin (to ensure it has the methods that Flask-Login expects), and an OAuth model for actually storing OAuth tokens. In addition to providing a connection to the User model, the OAuth model also stores the user ID that the provider uses – in this case, the GitHub user ID.

# setup login manager
login_manager = LoginManager()
login_manager.login_view = 'github.login'

@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))

This code sets up Flask-Login, informing it about our User model and the “github.login” view, so that it can properly redirect users if they try to access views that are login-protected.

# setup SQLAlchemy backend
blueprint.backend = SQLAlchemyBackend(OAuth, db.session, user=current_user)

This code hooks up the SQLAlchemyBackend backend to Flask-Dance, so that it can store OAuth tokens in the database. Notice that we also pass user=current_user, where current_user is a proxy provided by Flask-Login. This will ensure that OAuth tokens are scoped to individual users.

# create/login local user on successful OAuth login
@oauth_authorized.connect_via(blueprint)
def github_logged_in(blueprint, token):
    if not token:
        flash("Failed to log in with GitHub.", category="error")
        return False

    resp = blueprint.session.get("/user")
    if not resp.ok:
        msg = "Failed to fetch user info from GitHub."
        flash(msg, category="error")
        return False

    github_info = resp.json()
    github_user_id = str(github_info["id"])

    # Find this OAuth token in the database, or create it
    query = OAuth.query.filter_by(
        provider=blueprint.name,
        provider_user_id=github_user_id,
    )
    try:
        oauth = query.one()
    except NoResultFound:
        oauth = OAuth(
            provider=blueprint.name,
            provider_user_id=github_user_id,
            token=token,
        )

    if oauth.user:
        login_user(oauth.user)
        flash("Successfully signed in with GitHub.")

    else:
        # Create a new local user account for this user
        user = User(
            # Remember that `email` can be None, if the user declines
            # to publish their email address on GitHub!
            email=github_info["email"],
            name=github_info["name"],
        )
        # Associate the new local user account with the OAuth token
        oauth.user = user
        # Save and commit our database models
        db.session.add_all([user, oauth])
        db.session.commit()
        # Log in the new local user account
        login_user(user)
        flash("Successfully signed in with GitHub.")

    # Disable Flask-Dance's default behavior for saving the OAuth token
    return False)

This code hooks into the oauth_authorized signal, which is triggered when a user successfully completes the OAuth dance. We make an HTTP request to GitHub using blueprint.session, which already has the OAuth token loaded, in order to determine some basic information for the user, like their GitHub user ID. Then we look up in our local database to see if we already have a user associated with that GitHub user ID – if not, we create a new user. We then log that user in, using Flask-Login’s login_user() function.

We also use the flash() function to display status messages to the user, so that they understand that they’ve just logged in. Good feedback to the user is crucial for a good user experience.

# notify on OAuth provider error
@oauth_error.connect_via(blueprint)
def github_error(blueprint, error, error_description=None, error_uri=None):
    msg = (
        "OAuth error from {name}! "
        "error={error} description={description} uri={uri}"
    ).format(
        name=blueprint.name,
        error=error,
        description=error_description,
        uri=error_uri,
    )
    flash(msg, category="error")

Sometimes, the OAuth provider may throw an error message instead of allowing the OAuth dance to complete successfully. If so, Flask-Dance will redirect the user just as though the dance did complete successfully, so it is crucial to provide feedback to the user by hooking into the oauth_error signal.

@app.route("/logout")
@login_required
def logout():
    logout_user()
    flash("You have logged out")
    return redirect(url_for("index"))

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

This code sets up some routes for our application: a logout route, so that users can choose to log out of their user account, and an index route, so that there’s something to see in the application.

# hook up extensions to app
db.init_app(app)
login_manager.init_app(app)

Since we set up the Flask-SQLAlchemy and Flask-Login extensions initally without passing the application object, we have to pass the app to them after they’ve been fully configured. This is called the application factory pattern.

if __name__ == "__main__":
    if "--setup" in sys.argv:
        with app.app_context():
            db.create_all()
            db.session.commit()
            print("Database tables created")
    else:
        app.run(debug=True)

We need a way to set up the database tables before the application is run, so this code checks for a --setup flag when running the code, and if so it sets up the database tables instead of running the application. Note that the application is running in debug mode – be sure to turn this off before running your application in production!

Providers

Flask-Dance comes with pre-set OAuth consumer configurations for a few popular OAuth providers. Flask-Dance also works with providers that aren’t in this list: see the Custom section at the bottom of the page. We also welcome pull requests to add new pre-set provider configurations to Flask-Dance!

Facebook

flask_dance.contrib.facebook.make_facebook_blueprint(client_id=None, client_secret=None, scope=None, redirect_url=None, redirect_to=None, login_url=None, authorized_url=None, rerequest_declined_permissions=False, session_class=None, backend=None)[source]

Make a blueprint for authenticating with Facebook using OAuth 2. This requires a client ID and client secret from Facebook. You should either pass them to this constructor, or make sure that your Flask application config defines them, using the variables FACEBOOK_OAUTH_CLIENT_ID and FACEBOOK_OAUTH_CLIENT_SECRET.

Parameters:
  • client_id (str) – The client ID for your application on Facebook.
  • client_secret (str) – The client secret for your application on Facebook
  • scope (str, optional) – comma-separated list of scopes for the OAuth token
  • redirect_url (str) – the URL to redirect to after the authentication dance is complete
  • redirect_to (str) – if redirect_url is not defined, the name of the view to redirect to after the authentication dance is complete. The actual URL will be determined by flask.url_for()
  • login_url (str, optional) – the URL path for the login view. Defaults to /facebook
  • authorized_url (str, optional) – the URL path for the authorized view. Defaults to /facebook/authorized.
  • rerequest_declined_permissions (bool, optional) – should the blueprint ask again for declined permissions. Defaults to False
  • session_class (class, optional) – The class to use for creating a Requests session. Defaults to OAuth2Session.
  • backend – A storage backend class, or an instance of a storage backend class, to use for this blueprint. Defaults to SessionBackend.
Return type:

OAuth2ConsumerBlueprint

Returns:

A blueprint to attach to your Flask app.

flask_dance.contrib.facebook.facebook

A LocalProxy to a requests.Session that already has the Facebook authentication token loaded (assuming that the user has authenticated with Facebook at some point in the past).

GitHub

flask_dance.contrib.github.make_github_blueprint(client_id=None, client_secret=None, scope=None, redirect_url=None, redirect_to=None, login_url=None, authorized_url=None, session_class=None, backend=None)[source]

Make a blueprint for authenticating with GitHub using OAuth 2. This requires a client ID and client secret from GitHub. You should either pass them to this constructor, or make sure that your Flask application config defines them, using the variables GITHUB_OAUTH_CLIENT_ID and GITHUB_OAUTH_CLIENT_SECRET.

Parameters:
  • client_id (str) – The client ID for your application on GitHub.
  • client_secret (str) – The client secret for your application on GitHub
  • scope (str, optional) – comma-separated list of scopes for the OAuth token
  • redirect_url (str) – the URL to redirect to after the authentication dance is complete
  • redirect_to (str) – if redirect_url is not defined, the name of the view to redirect to after the authentication dance is complete. The actual URL will be determined by flask.url_for()
  • login_url (str, optional) – the URL path for the login view. Defaults to /github
  • authorized_url (str, optional) – the URL path for the authorized view. Defaults to /github/authorized.
  • session_class (class, optional) – The class to use for creating a Requests session. Defaults to OAuth2Session.
  • backend – A storage backend class, or an instance of a storage backend class, to use for this blueprint. Defaults to SessionBackend.
Return type:

OAuth2ConsumerBlueprint

Returns:

A blueprint to attach to your Flask app.

flask_dance.contrib.github.github

A LocalProxy to a requests.Session that already has the GitHub authentication token loaded (assuming that the user has authenticated with GitHub at some point in the past).

GitLab

flask_dance.contrib.gitlab.make_gitlab_blueprint(client_id=None, client_secret=None, scope=None, redirect_url=None, redirect_to=None, login_url=None, authorized_url=None, session_class=None, backend=None, hostname='gitlab.com')[source]

Make a blueprint for authenticating with GitLab using OAuth 2. This requires a client ID and client secret from GitLab. You should either pass them to this constructor, or make sure that your Flask application config defines them, using the variables GITLAB_OAUTH_CLIENT_ID and GITLAB_OAUTH_CLIENT_SECRET.

Parameters:
  • client_id (str) – The client ID for your application on GitLab.
  • client_secret (str) – The client secret for your application on GitLab
  • scope (str, optional) – comma-separated list of scopes for the OAuth token
  • redirect_url (str) – the URL to redirect to after the authentication dance is complete
  • redirect_to (str) – if redirect_url is not defined, the name of the view to redirect to after the authentication dance is complete. The actual URL will be determined by flask.url_for()
  • login_url (str, optional) – the URL path for the login view. Defaults to /gitlab
  • authorized_url (str, optional) – the URL path for the authorized view. Defaults to /gitlab/authorized.
  • session_class (class, optional) – The class to use for creating a Requests session. Defaults to OAuth2Session.
  • backend – A storage backend class, or an instance of a storage backend class, to use for this blueprint. Defaults to SessionBackend.
  • hostname (str, optional) – If using a private instance of GitLab CE/EE, specify the hostname, default is gitlab.com
Return type:

OAuth2ConsumerBlueprint

Returns:

A blueprint to attach to your Flask app.

flask_dance.contrib.gitlab.gitlab

A LocalProxy to a requests.Session that already has the GitLab authentication token loaded (assuming that the user has authenticated with GitLab at some point in the past).

Google

flask_dance.contrib.google.make_google_blueprint(client_id=None, client_secret=None, scope=None, offline=False, reprompt_consent=False, redirect_url=None, redirect_to=None, login_url=None, authorized_url=None, session_class=None, backend=None, hosted_domain=None)[source]

Make a blueprint for authenticating with Google using OAuth 2. This requires a client ID and client secret from Google. You should either pass them to this constructor, or make sure that your Flask application config defines them, using the variables GOOGLE_OAUTH_CLIENT_ID and GOOGLE_OAUTH_CLIENT_SECRET.

Parameters:
  • client_id (str) – The client ID for your application on Google
  • client_secret (str) – The client secret for your application on Google
  • scope (str, optional) – comma-separated list of scopes for the OAuth token. Defaults to the “https://www.googleapis.com/auth/userinfo.profile” scope.
  • offline (bool) – Whether to request offline access for the OAuth token. Defaults to False
  • reprompt_consent (bool) – If True, force Google to re-prompt the user for their consent, even if the user has already given their consent. Defaults to False
  • redirect_url (str) – the URL to redirect to after the authentication dance is complete
  • redirect_to (str) – if redirect_url is not defined, the name of the view to redirect to after the authentication dance is complete. The actual URL will be determined by flask.url_for()
  • login_url (str, optional) – the URL path for the login view. Defaults to /google
  • authorized_url (str, optional) – the URL path for the authorized view. Defaults to /google/authorized.
  • session_class (class, optional) – The class to use for creating a Requests session. Defaults to OAuth2Session.
  • backend – A storage backend class, or an instance of a storage backend class, to use for this blueprint. Defaults to SessionBackend.
  • hosted_domain (str, optional) – The domain of the G Suite user. Used to indicate that the account selection UI should be optimized for accounts at this domain. Note that this only provides UI optimization, and requires response validation (see warning).

Warning

The hosted_domain argument only provides UI optimization. Don’t rely on this argument to control who can access your application. You must verify that the hd claim of the response ID token matches the hosted_domain argument passed to make_google_blueprint. For example:

from flask import session, abort
from flask_dance.consumer import oauth_authorized
from flask_dance.contrib.google import make_google_blueprint, google
import requests

google_bp = make_google_blueprint(
    client_id="foo",
    client_secret="bar",
    scope=["profile", "email"],
    hosted_domain="example.com"
)

@oauth_authorized.connect_via(google_bp)
def logged_in(blueprint, token):
    resp_json = google.get("/oauth2/v2/userinfo").json()
    if resp_json["hd"] != blueprint.authorization_url_params["hd"]:
        requests.post(
            "https://accounts.google.com/o/oauth2/revoke",
            params={"token": token["access_token"]}
        )
        session.clear()
        abort(403)
Return type:OAuth2ConsumerBlueprint
Returns:A blueprint to attach to your Flask app.
flask_dance.contrib.google.google

A LocalProxy to a requests.Session that already has the Google authentication token loaded (assuming that the user has authenticated with Google at some point in the past).

Twitter

flask_dance.contrib.twitter.make_twitter_blueprint(api_key=None, api_secret=None, redirect_url=None, redirect_to=None, login_url=None, authorized_url=None, session_class=None, backend=None)[source]

Make a blueprint for authenticating with Twitter using OAuth 1. This requires an API key and API secret from Twitter. You should either pass them to this constructor, or make sure that your Flask application config defines them, using the variables TWITTER_OAUTH_API_KEY and TWITTER_OAUTH_API_SECRET.

Parameters:
  • api_key (str) – The API key for your Twitter application
  • api_secret (str) – The API secret for your Twitter application
  • redirect_url (str) – the URL to redirect to after the authentication dance is complete
  • redirect_to (str) – if redirect_url is not defined, the name of the view to redirect to after the authentication dance is complete. The actual URL will be determined by flask.url_for()
  • login_url (str, optional) – the URL path for the login view. Defaults to /twitter
  • authorized_url (str, optional) – the URL path for the authorized view. Defaults to /twitter/authorized.
  • session_class (class, optional) – The class to use for creating a Requests session. Defaults to OAuth1Session.
  • backend – A storage backend class, or an instance of a storage backend class, to use for this blueprint. Defaults to SessionBackend.
Return type:

OAuth1ConsumerBlueprint

Returns:

A blueprint to attach to your Flask app.

flask_dance.contrib.twitter.twitter

A LocalProxy to a requests.Session that already has the Twitter authentication token loaded (assuming that the user has authenticated with Twitter at some point in the past).

JIRA

flask_dance.contrib.jira.make_jira_blueprint(base_url, consumer_key=None, rsa_key=None, redirect_url=None, redirect_to=None, login_url=None, authorized_url=None, session_class=None, backend=None)[source]

Make a blueprint for authenticating with JIRA using OAuth 1. This requires a consumer key and RSA key for the JIRA appication link. You should either pass them to this constructor, or make sure that your Flask application config defines them, using the variables JIRA_OAUTH_CONSUMER_KEY and JIRA_OAUTH_RSA_KEY.

Parameters:
  • base_url (str) – The base URL of your JIRA installation. For example, for Atlassian’s hosted Cloud JIRA, the base_url would be https://jira.atlassian.com
  • consumer_key (str) – The consumer key for your Application Link on JIRA
  • rsa_key (str or path) – The RSA private key for your Application Link on JIRA. This can be the contents of the key as a string, or a path to the key file on disk.
  • redirect_url (str) – the URL to redirect to after the authentication dance is complete
  • redirect_to (str) – if redirect_url is not defined, the name of the view to redirect to after the authentication dance is complete. The actual URL will be determined by flask.url_for()
  • login_url (str, optional) – the URL path for the login view. Defaults to /jira
  • authorized_url (str, optional) – the URL path for the authorized view. Defaults to /jira/authorized.
  • session_class (class, optional) – The class to use for creating a Requests session. Defaults to JsonOAuth1Session.
  • backend – A storage backend class, or an instance of a storage backend class, to use for this blueprint. Defaults to SessionBackend.
Return type:

OAuth1ConsumerBlueprint

Returns:

A blueprint to attach to your Flask app.

flask_dance.contrib.jira.jira

A LocalProxy to a requests.Session that already has the JIRA authentication token loaded (assuming that the user has authenticated with JIRA at some point in the past).

Dropbox

flask_dance.contrib.dropbox.make_dropbox_blueprint(app_key=None, app_secret=None, scope=None, force_reapprove=False, disable_signup=False, require_role=None, redirect_url=None, redirect_to=None, login_url=None, authorized_url=None, session_class=None, backend=None)[source]

Make a blueprint for authenticating with Dropbox using OAuth 2. This requires a client ID and client secret from Dropbox. You should either pass them to this constructor, or make sure that your Flask application config defines them, using the variables DROPBOX_OAUTH_APP_KEY and DROPBOX_OAUTH_APP_SECRET.

For more information about the force_reapprove, disable_signup, and require_role arguments, check the Dropbox API documentation.

Parameters:
  • app_key (str) – The client ID for your application on Dropbox.
  • app_secret (str) – The client secret for your application on Dropbox
  • scope (str, optional) – Comma-separated list of scopes for the OAuth token
  • force_reapprove (bool) – Force the user to approve the app again if they’ve already done so.
  • disable_signup (bool) – Prevent users from seeing a sign-up link on the authorization page.
  • require_role (str) – Pass the string work to require a Dropbox for Business account, or the string personal to require a personal account.
  • redirect_url (str) – the URL to redirect to after the authentication dance is complete
  • redirect_to (str) – if redirect_url is not defined, the name of the view to redirect to after the authentication dance is complete. The actual URL will be determined by flask.url_for()
  • login_url (str, optional) – the URL path for the login view. Defaults to /dropbox
  • authorized_url (str, optional) – the URL path for the authorized view. Defaults to /dropbox/authorized.
  • session_class (class, optional) – The class to use for creating a Requests session. Defaults to OAuth2Session.
  • backend – A storage backend class, or an instance of a storage backend class, to use for this blueprint. Defaults to SessionBackend.
Return type:

OAuth2ConsumerBlueprint

Returns:

A blueprint to attach to your Flask app.

flask_dance.contrib.dropbox.dropbox

A LocalProxy to a requests.Session that already has the Dropbox authentication token loaded (assuming that the user has authenticated with Dropbox at some point in the past).

Meetup

flask_dance.contrib.meetup.make_meetup_blueprint(key=None, secret=None, scope=None, redirect_url=None, redirect_to=None, login_url=None, authorized_url=None, session_class=None, backend=None)[source]

Make a blueprint for authenticating with Meetup using OAuth 2. This requires an OAuth consumer from Meetup. You should either pass the key and secret to this constructor, or make sure that your Flask application config defines them, using the variables MEETUP_OAUTH_KEY and MEETUP_OAUTH_SECRET.

Parameters:
  • key (str) – The OAuth consumer key for your application on Meetup
  • secret (str) – The OAuth consumer secret for your application on Meetup
  • scope (str, optional) – comma-separated list of scopes for the OAuth token
  • redirect_url (str) – the URL to redirect to after the authentication dance is complete
  • redirect_to (str) – if redirect_url is not defined, the name of the view to redirect to after the authentication dance is complete. The actual URL will be determined by flask.url_for()
  • login_url (str, optional) – the URL path for the login view. Defaults to /meetup
  • authorized_url (str, optional) – the URL path for the authorized view. Defaults to /meetup/authorized.
  • session_class (class, optional) – The class to use for creating a Requests session. Defaults to OAuth2Session.
  • backend – A storage backend class, or an instance of a storage backend class, to use for this blueprint. Defaults to SessionBackend.
Return type:

OAuth2ConsumerBlueprint

Returns:

A blueprint to attach to your Flask app.

flask_dance.contrib.meetup.meetup

A LocalProxy to a requests.Session that already has the Meetup authentication token loaded (assuming that the user has authenticated with Meetup at some point in the past).

Slack

flask_dance.contrib.slack.make_slack_blueprint(client_id=None, client_secret=None, scope=None, redirect_url=None, redirect_to=None, login_url=None, authorized_url=None, session_class=None, backend=None)[source]

Make a blueprint for authenticating with Slack using OAuth 2. This requires a client ID and client secret from Slack. You should either pass them to this constructor, or make sure that your Flask application config defines them, using the variables SLACK_OAUTH_CLIENT_ID and SLACK_OAUTH_CLIENT_SECRET.

Parameters:
  • client_id (str) – The client ID for your application on Slack.
  • client_secret (str) – The client secret for your application on Slack
  • scope (str, optional) – comma-separated list of scopes for the OAuth token
  • redirect_url (str) – the URL to redirect to after the authentication dance is complete
  • redirect_to (str) – if redirect_url is not defined, the name of the view to redirect to after the authentication dance is complete. The actual URL will be determined by flask.url_for()
  • login_url (str, optional) – the URL path for the login view. Defaults to /slack
  • authorized_url (str, optional) – the URL path for the authorized view. Defaults to /slack/authorized.
  • session_class (class, optional) – The class to use for creating a Requests session. Defaults to OAuth2Session.
  • backend – A storage backend class, or an instance of a storage backend class, to use for this blueprint. Defaults to SessionBackend.
Return type:

OAuth2ConsumerBlueprint

Returns:

A blueprint to attach to your Flask app.

flask_dance.contrib.slack.slack

A LocalProxy to a requests.Session that already has the Slack authentication token loaded (assuming that the user has authenticated with Slack at some point in the past).

Azure

flask_dance.contrib.azure.make_azure_blueprint(client_id=None, client_secret=None, scope=None, redirect_url=None, redirect_to=None, login_url=None, authorized_url=None, session_class=None, backend=None, tenant='common')[source]

Make a blueprint for authenticating with Azure AD using OAuth 2. This requires a client ID and client secret from Azure AD. You should either pass them to this constructor, or make sure that your Flask application config defines them, using the variables AZURE_OAUTH_CLIENT_ID and AZURE_OAUTH_CLIENT_SECRET.

Parameters:
  • client_id (str) – The client ID for your application on Azure AD.
  • client_secret (str) – The client secret for your application on Azure AD
  • scope (str, optional) – comma-separated list of scopes for the OAuth token
  • redirect_url (str) – the URL to redirect to after the authentication dance is complete
  • redirect_to (str) – if redirect_url is not defined, the name of the view to redirect to after the authentication dance is complete. The actual URL will be determined by flask.url_for()
  • login_url (str, optional) – the URL path for the login view. Defaults to /azure
  • authorized_url (str, optional) – the URL path for the authorized view. Defaults to /azure/authorized.
  • session_class (class, optional) – The class to use for creating a Requests session. Defaults to OAuth2Session.
  • backend – A storage backend class, or an instance of a storage backend class, to use for this blueprint. Defaults to SessionBackend.
  • tenant – Determine which accounts are allowed to authenticate with Azure. See the Azure documentation for more information about this parameter. Defaults to common.
Return type:

OAuth2ConsumerBlueprint

Returns:

A blueprint to attach to your Flask app.

flask_dance.contrib.azure.azure

A LocalProxy to a requests.Session that already has the Azure AD authentication token loaded (assuming that the user has authenticated with Azure AD at some point in the past).

Nylas

flask_dance.contrib.nylas.make_nylas_blueprint(client_id=None, client_secret=None, scope='email', redirect_url=None, redirect_to=None, login_url=None, authorized_url=None, session_class=None, backend=None)[source]

Make a blueprint for authenticating with Nylas using OAuth 2. This requires an API ID and API secret from Nylas. You should either pass them to this constructor, or make sure that your Flask application config defines them, using the variables NYLAS_OAUTH_CLIENT_KEY and NYLAS_OAUTH_CLIENT_SECRET.

Parameters:
  • client_id (str) – The client ID for your developer account on Nylas.
  • client_secret (str) – The client secret for your developer account on Nylas.
  • scope (str, optional) – comma-separated list of scopes for the OAuth token. Defaults to “email”.
  • redirect_url (str) – the URL to redirect to after the authentication dance is complete
  • redirect_to (str) – if redirect_url is not defined, the name of the view to redirect to after the authentication dance is complete. The actual URL will be determined by flask.url_for()
  • login_url (str, optional) – the URL path for the login view. Defaults to /nylas
  • authorized_url (str, optional) – the URL path for the authorized view. Defaults to /nylas/authorized.
  • session_class (class, optional) – The class to use for creating a Requests session. Defaults to OAuth2Session.
  • backend – A storage backend class, or an instance of a storage backend class, to use for this blueprint. Defaults to SessionBackend.
Return type:

OAuth2ConsumerBlueprint

Returns:

A blueprint to attach to your Flask app.

flask_dance.contrib.nylas.nylas

A LocalProxy to a requests.Session that already has the Nylas authentication token loaded (assuming that the user has authenticated with Nylas at some point in the past).

Spotify

flask_dance.contrib.spotify.make_spotify_blueprint(client_id=None, client_secret=None, scope=None, redirect_url=None, redirect_to=None, login_url=None, authorized_url=None, session_class=None, backend=None)[source]

Make a blueprint for authenticating with Spotify using OAuth 2. This requires a client ID and client secret from Spotify. You should either pass them to this constructor, or make sure that your Flask application config defines them, using the variables SPOTIFY_OAUTH_CLIENT_ID and SPOTIFY_OAUTH_CLIENT_SECRET.

Parameters:
  • client_id (str) – The client ID for your application on Spotify.
  • client_secret (str) – The client secret for your application on Spotify
  • scope (str, optional) – comma-separated list of scopes for the OAuth token
  • redirect_url (str) – the URL to redirect to after the authentication dance is complete
  • redirect_to (str) – if redirect_url is not defined, the name of the view to redirect to after the authentication dance is complete. The actual URL will be determined by flask.url_for()
  • login_url (str, optional) – the URL path for the login view. Defaults to /spotify
  • authorized_url (str, optional) – the URL path for the authorized view. Defaults to /spotify/authorized.
  • session_class (class, optional) – The class to use for creating a Requests session. Defaults to OAuth2Session.
  • backend – A storage backend class, or an instance of a storage backend class, to use for this blueprint. Defaults to SessionBackend.
Return type:

OAuth2ConsumerBlueprint

Returns:

A blueprint to attach to your Flask app.

flask_dance.contrib.spotify.spotify

A LocalProxy to a requests.Session that already has the Spotify authentication token loaded (assuming that the user has authenticated with Spotify at some point in the past).

Discord

flask_dance.contrib.discord.make_discord_blueprint(client_id=None, client_secret=None, scope=None, redirect_url=None, redirect_to=None, login_url=None, authorized_url=None, session_class=None, backend=None)[source]

Make a blueprint for authenticating with Discord using OAuth 2. This requires a client ID and client secret from Discord. You should either pass them to this constructor, or make sure that your Flask application config defines them, using the variables DISCORD_OAUTH_CLIENT_ID and DISCORD_OAUTH_CLIENT_SECRET.

Parameters:
  • client_id (str) – The client ID for your application on Discord.
  • client_secret (str) – The client secret for your application on Discord
  • scope (list, optional) – list of scopes (str) for the OAuth token
  • redirect_url (str) – the URL to redirect to after the authentication dance is complete
  • redirect_to (str) – if redirect_url is not defined, the name of the view to redirect to after the authentication dance is complete. The actual URL will be determined by flask.url_for()
  • login_url (str, optional) – the URL path for the login view. Defaults to /discord
  • authorized_url (str, optional) – the URL path for the authorized view. Defaults to /discord/authorized.
  • session_class (class, optional) – The class to use for creating a Requests session. Defaults to OAuth2Session.
  • backend – A storage backend class, or an instance of a storage backend class, to use for this blueprint. Defaults to SessionBackend.
Return type:

OAuth2ConsumerBlueprint

Returns:

A blueprint to attach to your Flask app.

flask_dance.contrib.discord.discord

A LocalProxy to a requests.Session that already has the Discord authentication token loaded (assuming that the user has authenticated with Discord at some point in the past).

Okta

flask_dance.contrib.okta.make_okta_blueprint(client_id=None, client_secret=None, base_url=None, scope=None, redirect_url=None, token_url=None, redirect_to=None, login_url=None, authorization_url=None, session_class=None, backend=None)[source]

Make a blueprint for authenticating with Okta using OAuth 2. This requires a client ID and client secret from OKta. You should either pass them to this constructor, or make sure that your Flask application config defines them, using the variables OKTA_OAUTH_CLIENT_ID and OKTA_OAUTH_CLIENT_SECRET.

Parameters:
  • client_id (str) – The client ID for your application on Okta.
  • client_secret (str) – The client secret for your application on Okta
  • scope (list, optional) – list of scopes (str) for the OAuth token
  • redirect_url (str) – the URL to redirect to after the authentication dance is complete
  • redirect_to (str) – if redirect_url is not defined, the name of the view to redirect to after the authentication dance is complete. The actual URL will be determined by flask.url_for()
  • login_url (str, optional) – the URL path for the login view. Defaults to /okta
  • authorized_url (str, optional) – the URL path for the authorized view. Defaults to /okta/authorized.
  • session_class (class, optional) – The class to use for creating a Requests session. Defaults to OAuth2Session.
  • backend – A storage backend class, or an instance of a storage backend class, to use for this blueprint. Defaults to SessionBackend.
Return type:

OAuth2ConsumerBlueprint

Returns:

A blueprint to attach to your Flask app.

flask_dance.contrib.okta.okta

A LocalProxy to a requests.Session that already has the Okta authentication token loaded (assuming that the user has authenticated with Okta at some point in the past).

Reddit

flask_dance.contrib.reddit.make_reddit_blueprint(client_id=None, client_secret=None, scope='identity', permanent=False, redirect_url=None, redirect_to=None, login_url=None, authorized_url=None, session_class=None, backend=None, user_agent=None)[source]

Make a blueprint for authenticating with Reddit using OAuth 2. This requires a client ID and client secret from Reddit. You should either pass them to this constructor, or make sure that your Flask application config defines them, using the variables REDDIT_OAUTH_CLIENT_ID and REDDIT_OAUTH_CLIENT_SECRET.

Parameters:
  • client_id (str) – The client ID for your application on Reddit.
  • client_secret (str) – The client secret for your application on Reddit
  • scope (str, optional) – space-separated list of scopes for the OAuth token Defaults to identity
  • permanent (bool, optional) – Whether to request permanent access token. Defaults to False, access will be valid for 1 hour
  • redirect_url (str) – the URL to redirect to after the authentication dance is complete
  • redirect_to (str) – if redirect_url is not defined, the name of the view to redirect to after the authentication dance is complete. The actual URL will be determined by flask.url_for()
  • login_url (str, optional) – the URL path for the login view. Defaults to /reddit
  • authorized_url (str, optional) – the URL path for the authorized view. Defaults to /reddit/authorized.
  • session_class (class, optional) – The class to use for creating a Requests session. Defaults to RedditOAuth2Session.
  • backend – A storage backend class, or an instance of a storage backend class, to use for this blueprint. Defaults to SessionBackend.
  • user_agent (str, optional) – User agent for the requests to Reddit API. Defaults to Flask-Dance/{{version}}
Return type:

OAuth2ConsumerBlueprint

Returns:

A blueprint to attach to your Flask app.

flask_dance.contrib.reddit.reddit

A LocalProxy to a requests.Session that already has the Reddit authentication token loaded (assuming that the user has authenticated with Reddit at some point in the past).

Zoho

flask_dance.contrib.zoho.make_zoho_blueprint(client_id=None, client_secret=None, scope=None, redirect_url=None, offline=False, redirect_to=None, login_url=None, session_class=None, backend=None, reprompt_consent=False)[source]

Make a blueprint for authenticating with Zoho using OAuth 2. This requires a client ID and client secret from Zoho. You should either pass them to this constructor, or make sure that your Flask application config defines them, using the variables ZOHO_OAUTH_CLIENT_ID and ZOHO_OAUTH_CLIENT_SECRET. IMPORTANT: Configuring the base_url is not supported in this config.

Parameters:
  • client_id (str) – The client ID for your application on Zoho.
  • client_secret (str) – The client secret for your application on Zoho
  • scope (list, optional) – list of scopes (str) for the OAuth token
  • redirect_url (str) – the URL to redirect to after the authentication dance is complete
  • redirect_to (str) – if redirect_url is not defined, the name of the view to redirect to after the authentication dance is complete. The actual URL will be determined by flask.url_for()
  • login_url (str, optional) – the URL path for the login view. Defaults to /zoho
  • authorized_url (str, optional) – the URL path for the authorized view. Defaults to /zoho/authorized.
  • session_class (class, optional) – The class to use for creating a Requests session. Defaults to OAuth2Session.
  • backend – A storage backend class, or an instance of a storage backend class, to use for this blueprint. Defaults to SessionBackend.
  • offline (bool) – Whether to request offline access for the OAuth token. Defaults to False
  • reprompt_consent (bool) – If True, force Zoho to re-prompt the user for their consent, even if the user has already given their consent. Defaults to False
Return type:

OAuth2ConsumerBlueprint

Returns:

A blueprint to attach to your Flask app.

flask_dance.contrib.zoho.zoho

A LocalProxy to a requests.Session that already has the Zoho authentication token loaded (assuming that the user has authenticated with Zoho at some point in the past).

Custom

Flask-Dance allows you to build authentication blueprints for any OAuth provider, not just the ones listed above. For example, let’s create a blueprint for a fictional OAuth provider called oauth-example.com. We check the documentation for oauth-example.com, and discover that they’re using OAuth 2, the access token URL is https://oauth-example.com/login/access_token, and the authorization URL is https://oauth-example.com/login/authorize. We could then build the blueprint like this:

from flask import Flask
from flask_dance.consumer import OAuth2ConsumerBlueprint

app = Flask(__name__)
example_blueprint = OAuth2ConsumerBlueprint(
    "oauth-example", __name__,
    client_id="my-key-here",
    client_secret="my-secret-here",
    base_url="https://oauth-example.com",
    token_url="https://oauth-example.com/login/access_token",
    authorization_url="https://oauth-example.com/login/authorize",
)
app.register_blueprint(example_blueprint, url_prefix="/login")

Now, in your page template, you can do something like:

<a href="{{ url_for("oauth-example.login") }}">Login with OAuth Example</a>

And in your views, you can make authenticated requests using the session attribute on the blueprint:

resp = example_blueprint.session.get("/user")
assert resp.ok
print("Here's the content of my response: " + resp.content)

It all follows the same patterns as the Quickstarts. You can also read the code to see how the pre-set configurations are implemented – it’s very short.

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” ORM 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(OAuthConsumerMixin, db.Model):
    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(OAuthConsumerMixin, db.Model):
    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 SQLAlchemyBackend. 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-Caching if you just pass an Flask-Caching instance to the backend, like this:

from flask import Flask
from flask_caching 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(FileBackend, 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 backend and assign it to the backend attribute of your blueprint, and Flask-Dance will use it.

Multi-User Setups

Many websites are designed to have multiple user accounts, where each user has one or more OAuth connections to other websites, like Google or Twitter. This is a perfectly valid use-case for OAuth, but in order to implement it correctly, you need to think carefully about how these OAuth connections are created and used. There are a lot of unexpected edge-cases that can take you by surprise.

Defining Expected Behavior

User Association vs User Creation

Are users expected to create an account on your website first, and then assocation OAuth connections afterwards? Or does logging in with an an OAuth provider create an account for the user on your site automatically?

The first option (user association) is useful when you expect users to primarily log in to your website using a username/password combination, but want to allow your users to perform actions on other sites via OAuth. For example, maybe you want to build your own social network website, and allow users to invite their friends from Facebook and their followers on Twitter. Typically, this setup means that users are able to associate their accounts with other websites via OAuth, but they are not required to do so.

The second option (user creation) is useful when you expect users to primarily (or exclusively) log in to your website using an OAuth connection. For example, maybe you don’t want your users to have to remember another username/password combination, so instead, you have a “Log In with Google” or “Log In with GitHub” button on your website. When a user clicks on that button and logs in with the respective service, they automatically create an account on your website in the process. Typically, this setup means that users cannot create an account on your website without associating it with an OAuth connection.

Associations with Multiple Providers

Can a user associate one account with multiple different OAuth providers? For example, can a user login with Google or login with GitHub, and log into the same account whichever option they pick?

This is particularly complicated if you’ve chosen user creation via OAuth, instead of user association. When a user logs in with a provider, and your website hasn’t seen that particular user on that particular provider before, how does your website know whether to create a new user on your website, or link this provider to an existing user on your website? If you use user association, you can simply require that the user should already be logged in to their local account before they can associate that local account with an OAuth provider. But if you use user creation, that requirement is almost impossible to enforce, because typically people don’t understand that they have a local user account.

Flask-Dance’s Default Behavior

Flask-Dance does the best it can to resolve these issues for you, while allowing you to take control in complex circumstances. Different backends may handle this differently, but for simplicity, this document will refer to the SQLAlchemy backend.

User Association vs User Creation

Flask-Dance will never create user accounts for your users automatically. Flask-Dance only handles creating OAuth associations and retrieving them on a per-user basis. By default, Flask-Dance will associate new OAuth connections with the local user that is currently logged in.

What happens if there no local user is currently logged in? That depends on the user_required parameter of the SQLAlchemyBackend class. If it is False, Flask-Dance will create an association that isn’t linked to any particular user in your application. This is handy if you don’t actually have local user accounts in your application, and are using Flask-Dance to connect your entire website to one single remote user. For example, this could be the desired behavior if your website is actually a bot that responds to incoming requests by making API calls to a third-party website, like a Twitter bot that tweets in response to certain HTTP requests.

If the user_required parameter is set to True, and no local user is currently logged in, then Flask-Dance will raise an exception when trying to associate an OAuth connection with the local user. The only way to correctly resolve this situation is to override Flask-Dance’s default behavior and specify exactly how to create a local user.

Associations with Multiple Providers

By default, Flask-Dance will happily associate multiple different OAuth providers with a single user account. This is why the OAuth model in SQLAlchemy must be separate from the User model: so that you can associate multiple different OAuth models with a single User model.

Since Flask-Dance does user association by default, rather than user creation, you don’t need to worry about the question of how Flask-Dance will handle new OAuth associations. Using the default behavior, Flask-Dance will never create a new user for the connection; instead, it will always associate the connection with an existing user.

Overriding the Default Behavior

If you want to allow users to log in with OAuth, and create local user accounts automatically when they do so, you’ll need to override Flask-Dance’s default behavior. To do so, you’ll need to hook into the oauth_authorized signal.

Flask-Dance’s default behavior comes from storing the OAuth token for you automatically. To override the default behavior, write a function that subscribes to this signal, handles it the way you want, and returns False. Returning False from this signal handler indicates to Flask-Dance that it should not try to store the OAuth token for you.

Warning

If you return False from a oauth_authorized signal handler, and you do not store the OAuth token in your database, the OAuth token will be lost, and you will not be able to use it to make API calls in the future!

Here’s an example of how you might want to override Flask-Dance’s default behavior in order to create user accounts automatically:

import flask
from flask import flash
from flask_security import current_user, login_user
from flask_dance.consumer import oauth_authorized
from flask_dance.consumer.backend.sqla import SQLAlchemyBackend
from flask_dance.contrib.github import make_github_blueprint
from sqlalchemy.orm.exc import NoResultFound
from myapp.models import db, OAuth, User


github_bp = make_github_blueprint(
    backend=SQLAlchemyBackend(OAuth, db.session, user=current_user)
)


# create/login local user on successful OAuth login
@oauth_authorized.connect_via(github_bp)
def github_logged_in(blueprint, token):
    if not token:
        flash("Failed to log in with GitHub.", category="error")
        return False

    resp = blueprint.session.get("/user")
    if not resp.ok:
        msg = "Failed to fetch user info from GitHub."
        flash(msg, category="error")
        return False

    github_info = resp.json()
    github_user_id = str(github_info["id"])

    # Find this OAuth token in the database, or create it
    query = OAuth.query.filter_by(
        provider=blueprint.name,
        provider_user_id=github_user_id,
    )
    try:
        oauth = query.one()
    except NoResultFound:
        oauth = OAuth(
            provider=blueprint.name,
            provider_user_id=github_user_id,
            token=token,
        )

    if oauth.user:
        # If this OAuth token already has an associated local account,
        # log in that local user account.
        # Note that if we just created this OAuth token, then it can't
        # have an associated local account yet.
        login_user(oauth.user)
        flash("Successfully signed in with GitHub.")

    else:
        # If this OAuth token doesn't have an associated local account,
        # create a new local user account for this user. We can log
        # in that account as well, while we're at it.
        user = User(
            # Remember that `email` can be None, if the user declines
            # to publish their email address on GitHub!
            email=github_info["email"],
            name=github_info["name"],
        )
        # Associate the new local user account with the OAuth token
        oauth.user = user
        # Save and commit our database models
        db.session.add_all([user, oauth])
        db.session.commit()
        # Log in the new local user account
        login_user(user)
        flash("Successfully signed in with GitHub.")

    # Since we're manually creating the OAuth model in the database,
    # we should return False so that Flask-Dance knows that
    # it doesn't have to do it. If we don't return False, the OAuth token
    # could be saved twice, or Flask-Dance could throw an error when
    # trying to incorrectly save it for us.
    return False

This example code does not include implementations for the User and OAuth models: you can see that these models are imported from another file. However, notice that the OAuth model has a field called provider_user_id, which is used to store the user ID of the GitHub user. The example code uses that ID to check if we’ve already saved an OAuth token in the database for this GitHub user.

Logging Out

Many websites use OAuth as an authentication system (see Multi-User Setups for more information). Although this can work quite well, it gets more complicated when you want to allow the user to log out of your website. For starters, we need to understand what “logging out” even means.

Local Accounts vs Provider Accounts

When you use OAuth as an authentication system, your users still have local accounts on your system. OAuth allows your users to log in with a provider (such as Google or Facebook), and use their provider login to authenticate to your local account. Essentially, the exchange looks something like this, if we assume that “CustomSite” is the name of your website, and it’s using the Google provider:

  1. User: Hey CustomSite, I’m user ShinyStar99. Let me in.
  2. CustomSite: Sorry user, anyone could claim that and I don’t trust you. How do I know you’re telling the truth?
  3. User: My friend Google can back me up. You trust Google, right?
  4. CustomSite: Yes, I trust Google. Hey Google, who is this user?
  5. Google: Hold on, I need to ask my user if I have permission to give you any information at all. Hey User, CustomSite wants to know who you are. Do you want me to tell CustomSite some basic information about you?
  6. User: Yes, please.
  7. Google: Alright CustomSite, I can tell you that on my website, this user has the ID 987654.
  8. CustomSite: Alright, let me check my database. Google user ID 987654 matches up with one of my local users, with ID 12345. And it looks like that local user is ShinyStar99!
  9. User: You see? I told you so!
  10. CustomSite: Come in, ShinyStar99. Who’s next?

In this exchange, you can see that there are two different user accounts involved: one user account on Google, and one user account on CustomSite. They have different user IDs, and could contain different sets of information, even though they both represent the same user.

So if you want to cause a user to log out, what exactly do you mean? We’ll go step-by-step through the different options.

Log Out Local Account

If you want to cause a user to log out of their local user account, check the documentation for whatever system you’re using to manage local accounts. If you’re using Flask-Login (or Flask-Security, which is built on top of Flask-Login), you can import and call the flask_login.logout_user() function, like this:

from flask_login import logout_user
# other imports as necessary

@app.route("/logout")
def logout():
    logout_user()
    return redirect(somewhere)

After you do this, your application will treat the user like any other anonymous user. However, logging out your user from their local account doesn’t do anything about the provider account. As a result, if the user tries to log in again after you’ve logged them out this way, the conversation will look like this:

  1. User: Hey CustomSite, I’m user ShinyStar99. Let me in. Ask Google if you don’t believe me.
  2. CustomSite: Hey Google, who is this user?
  3. Google: My user already gave me permission to tell you some basic information. On my website, this user has the ID 987654.
  4. CustomSite: Oh right, it’s ShinyStar99 again. Go ahead.

In most cases, this is what you want. However, sometimes you want to really reset things back to the start, as though the user had never granted consent to share information in the first place.

Revoking Access with the Provider

Undoing the user’s permission to share information from the provider to your custom site is called “revoking access”. Unfortunately, every provider has a different way of doing this, so you’ll need to check the OAuth documentation provided by your OAuth provider.

When you are granted access by a user, the provider will give your application a “token” that is used for making subsequent API requests. In order to revoke access for a user, you may need to include this token as an argument, so the provider knows which token to revoke. You can get this information by checking the token property of the Flask-Dance blueprint.

We’ll use Google as an example. First, check Google’s documentation for how to revoke access via OAuth2. Notice that you do indeed need to provide the token in order to revoke it.

Here’s some sample code that works with Google:

from flask import Flask, redirect
from flask_dance.contrib.google import make_google_blueprint, google
from flask_login import logout_user

app = Flask(__name__)
blueprint = make_google_blueprint()
app.register_blueprint(blueprint, url_prefix="/login")

@app.route("/logout")
def logout():
    token = blueprint.token["access_token"]
    resp = google.post(
        "https://accounts.google.com/o/oauth2/revoke",
        params={"token": token},
        headers={"Content-Type": "application/x-www-form-urlencoded"}
    )
    assert resp.ok, resp.text
    logout_user()
    return redirect(somewhere)

After the user uses this method to log out, Google will not remember that they granted consent to share information with your website.

Warning

In this sample code, we are using an assert statement. This works fine for debugging, but not for production. Be sure to modify this code to appropriately handle cases where there is an API failure when trying to revoke the token.

Note

In this code, we already have a reference to the blueprint object, so we could grab the token easily. But what if you don’t have access to that object? Instead, you can use the flask.current_app proxy to pull out the blueprint object you need. For example, instead of this line:

token = blueprint.token["access_token"]

You could use this line instead:

token = current_app.blueprints["google"].token["access_token]

Log Out Provider Account

You can log out the user from their local account, and you can revoke access with the provider. But what about logging the user out from their provider account? Can you force the user to type their password into Google again if they want to log in to your website in the future?

The short answer is: no, you can’t. You can’t control how a user interacts with other websites, except for in the ways that those other websites specifically allow you to. And since this could potentially be used as part of a security exploit, websites will generally not allow you to force users to log out.

Proxies and HTTPS

Running a secure HTTPS website is important, but encrypting and decrypting HTTPS traffic is computationally expensive. Many people running large-scale websites (including Heroku) use a TLS termination proxy to reduce load on the HTTP server. This works great, but means that the webserver running your Flask application is actually speaking HTTP, not HTTPS.

As a result, Flask-Dance can get confused, and generate callback URLs that have an http:// scheme, instead of an https:// scheme. This is bad, because OAuth requires that all connections use HTTPS for security purposes, and OAuth providers will reject requests that suggest a callback URL with a http:// scheme.

When you proxy the request from a TLS termination proxy, probably your load balancer, you need to ensure a few headers are set/proxied correctly for Flask to do the right thing out of the box:

  • Host: preserve the Host header of the original request
  • X-Real-IP: preserve the source IP of the original request
  • X-Forwarded-For: a list of IP addresses of the source IP and any HTTP proxies we’ve been through
  • X-Forwarded-Proto: the protocol, http or https, that the request came in with

In 99.9% of the cases the TLS termination proxy will be configured to do the right thing by default and any well-behaved Flask application will work out of the box. However, if you’re accessing the WSGI environment directly, you will run into trouble. Don’t do this and instead use the functions provided by Werkzeug’s wsgi module or Flask’s request to access things like a Host header.

If your Flask app is behind a TLS termination proxy, and you need to make sure that Flask is aware of that, check Flask’s documentation for how to deploy a proxy setup.

Please read it and follow its instructions. This is not unique to Flask-Dance and there’s nothing to configure on Flask-Dance’s side to solve this. It’s also worth noting you might wish to set Flask’s PREFERRED_URL_SCHEME.

Signals

New in version 0.2.

Flask-Dance supports signals, just as Flask does. Signals are perfect for custom processing code that you want to run at a certain point in the OAuth dance. For example, after the dance is complete, you might need to update the user’s profile, kick off a long-running task, or simply flash a message to let the user know that the login was successful. It’s easy, just import the appropriate signal of the ones listed below, and connect your custom processing code to the signal.

The following signals exist in Flask-Dance:

flask_dance.consumer.oauth_authorized

This signal is sent when a user completes the OAuth dance by receiving a response from the OAuth provider’s authorize URL. The signal is invoked with the blueprint instance as the first argument (the sender), and with a dict of the OAuth provider’s response (the token).

Example subscriber:

from flask import flash
from flask_dance.consumer import oauth_authorized

@oauth_authorized.connect
def logged_in(blueprint, token):
    flash("Signed in successfully with {name}!".format(
        name=blueprint.name.capitalize()
    ))

If you are linking OAuth records to User records, you must implement an @oauth_authorized subscriber that creates new User and OAuth database entries for any new users, and links those two new records via the OAuth table’s user_id field.

If you’re using OAuth 2, the user may grant you different scopes from the ones you requested: check the scope key in the token dict to determine what scopes were actually granted. If you don’t want the token to be stored, simply return False from one of your signal receiver functions – this can be useful if the user has declined to authorize your OAuth request, has granted insufficient scopes, or in some other way has given you a token that you don’t want.

You can also return a Response instance from an event subscriber. If you do, that response will be returned to the user instead of the normal redirect. For example:

from flask import redirect, url_for

@oauth_authorized.connect
def logged_in(blueprint, token):
    return redirect(url_for("after_oauth"))
flask_dance.consumer.oauth_error

This signal is sent when the OAuth provider indicates that there was an error with the OAuth dance. This can happen if your application is misconfigured somehow. The user will be redirected to the redirect_url anyway, so it is your responsibility to hook into this signal and inform the user that there was an error.

Advanced Topics:

How OAuth Works

Definitions

OAuth uses a series of specially-crafted HTTP views and redirects to allow websites to share information with each other securely, and with the user’s consent [1]. There are four roles in an OAuth interaction:

provider
A website that has information about a user. Well-known OAuth providers include Google, Facebook, Twitter, etc.
consumer
A website that wants to obtain some information about a user from the provider.
user
An actual person who controls information stored with the provider.
client
A program (usually a web browser) that interacts with the provider and consumer on behalf of the user.

In order to securely interact with each other, the provider and consumer must exchange secrets ahead of time, before any OAuth communication actually happens. Generally, this happens when someone who runs the consumer website goes to the provider website and registers an application with the provider, putting in information about the name and URL of the consumer website. The provider then gives the consumer a “client secret”, which is a random string of letters and numbers. By presenting this client secret in future OAuth communication, the provider website can verify that the consumer is who they say they are, and not some other website trying to intercept the communication.

Note

Even though it is called a “client secret”, the secret represents the consumer website, not the client (the user’s web browser).

After the consumer has registered an application with the provider and gotten a client secret, the consumer can do the “OAuth dance” to get consent from a user to share information with the consumer. There are two different versions of the dance: OAuth 1, which is the original version; and OAuth 2, the successor to OAuth 1 which is more flexible and more widely used today.

OAuth 2

  1. The client visits the consumer at a special URL, indicating that they want to connect to the provider with OAuth. Typically, there is a button on the consumer’s website labelled “Log In with Google” or similar, which takes the user to this special URL.
  2. The consumer decides how much of the user’s data they want to access, using specfic keywords called “scopes”. The consumer also makes up a random string of letters and numbers, called a “state” token. The consumer crafts a special URL that points to the provider, but has the client secret, the scopes, the state token embedded in it. The consumer asks the client to visit the provider using this special URL.
  3. When the client visits the provider at that URL, the provider notices the client secret, and looks up the consumer that it belongs to. The provider also notices the scopes that the consumer is requesting. The provider displays a page informing the user what information the consumer wants access to – it may be all of the user’s information, or just some of the user’s information. The user gets to decide if this is OK or not. If the user decides that this is not OK, the dance is over.
  4. If the user grants consent, the provider makes up a new secret, called the “authorization code”. The provider crafts a special URL that points to the consumer, but has the authorization code and the state token embedded in it. The provider asks the client to visit the consumer using this special URL.
  5. When the client visits the consumer at that URL, the consumer first checks the state token to be sure that it hasn’t changed, just to verify that no one has tampered with the request. Then, the consumer makes a separate request to the provider, passing along the client secret and the authorization code. If everything looks good to the provider, the provider makes up one final secret, called the “access token”, and sends it back to the consumer. This completes the dance.

OAuth 1

  1. The client visits the consumer at a special URL, indicating that they want to connect to the provider with OAuth. Typically, there is a button on the consumer’s website labelled “Log In with Twitter” or similar, which takes the user to this special URL.
  2. The consumer tells the provider that they’re about to do the OAuth dance. The consumer gives the provider the client secret, to verify that everything’s cool. The provider checks the OAuth secret, and if it looks good, the provider makes up a new secret called a “request token”, and gives it to the consumer.
  3. The consumer crafts a special URL that points to the provider, but has the client secret and request token embedded in it. The consumer asks the client to visit the provider using this special URL.
  4. When the client visits the provider at that URL, the provider notices the request token, and looks up the consumer that it belongs to. The provider tells the user that this consumer wants to access some or all of the user’s information. The user gets to decide if this is OK or not. If the user decides that this is not OK, the dance is over.
  5. If the user grants consent, the provider makes up another new secret, called the “authorization code”. The provider crafts a special URL that points to the consumer, but has the authorization code embedded in it. The provider asks the client to go visit the consumer at that special URL.
  6. When the client visits the consumer at that URL, the consumer notices the authorization code. The consumer makes another request to the provider, passing along the client secret and the authorization code. If everything looks good to the provider, the provider makes up one final secret, called the “access token”, and sends it back to the consumer. This completes the dance.

Dance Complete

Phew, that was complicated! But the end result is, the consumer has an access token, which proves that the user has given consent for the provider to give the consumer information about that user. Now, whenever the consumer needs information from the provider about the user, the consumer simply makes an API request to the provider and passes the access token along with the request. The provider sees the access token, looks up the user that granted consent, and determines whether the requested information falls within what the user authorized. If so, the provider returns that information to the consumer. In effect, the consumer is now the user’s client!

Warning

Keep your access tokens secure! Treat a user’s access token like you would treat their password.

Note

The OAuth dance normally only needs to be performed once per user. Once the consumer has an access token, that access token can be used to make many API requests on behalf of the user. Some OAuth implementations put a lifespan on the access token, after which it must be refreshed, but refreshing an access token does not require any interaction from the user.

[1]Not all OAuth interactions share information about specific users. When no user-specific information is involved, then the consumer is able to get information from the provider without getting a user’s consent, since there is no one to get consent from. In practice, however, most OAuth interactions are about sharing information about users, so this documentation assumes that use-case.

Testing

When building Flask apps that have integrated Flask-Dance you’ll eventually run into the need to test your app. But if routes are guarded by the requirement of having a valid OAuth2 session, i.e getting past the .authorized() call on a provider, how do you test this?

One possible way of solving this is by injecting the necessary information into the Flask session. The following examples assume you’re using py.test and the Google provider, but the same trick applies to any of the supported providers.

Creating a session

In your conftest.py create two fixtures, like this:

import time

import pytest

from your_app import create_app
from your_app.settings import Testing

fake_time = time.time()


@pytest.fixture
def app():
    """Returns an app fixture with the testing configuration."""
    app = create_app(config_object=Testing)
    yield app


@pytest.fixture
def loggedin_app(app):
    """Creates a logged-in test client instance."""
    with app.test_client() as client:
        with client.session_transaction() as sess:
            sess['google_oauth_token'] = {
                'access_token': 'this is totally fake',
                'id_token': 'this is not a real token',
                'token_type': 'Bearer',
                'expires_in': '3600',
                'expires_at': fake_time + 3600,
            }
        yield client

This will inject the necessary information in order to ensure that Flask-Dance, requests-oauthlib and oauthlib believe there is a valid session, and one that won’t need to be refreshed for another hour (3600 seconds). If your tests run longer than that, you’ll need to adjust that value.

The fake_time is created so that you can always refer to the same point in time throughout tests, and in any other fixture you might create. Alternatively you can use something like pytest-freezegun and then call any of the time and datetime functions as you normally would:

@pytest.fixture
@pytest.mark.freeze_time('2018-05-04')
def loggedin_app(app):
    """Creates a logged-in test client instance."""
    with app.test_client() as client:
        with client.session_transaction() as sess:
            sess['domain'] = 'example.com'
            sess['google_oauth_token'] = {
                'access_token': 'this is totally fake',
                'id_token': 'this is not a real token',
                'token_type': 'Bearer',
                'expires_in': '3600',
                'expires_at': time.time() + 3600,
            }
        yield client

Now that we have a logged-in client you can call any of the routes using the test client and check their responses.

def test_not_logged_in(app):
    """Test that we redirect to Google to login."""
    res = app.test_client().get('/')
    assert ('redirected automatically to target URL: <a href="/login/'
            'google">/login/google</a>').lower() in res.get_data(as_text=True).lower()
    assert res.status_code == 302


def test_logged_in_index(loggedin_app):
    """Tests getting the index route.

    This will render the normal template as we have a valid oauth2 session.
    """
    res = loggedin_app.get('/')
    assert res.content_type == 'text/html; charset=utf-8'
    assert res.status_code == 200
    assert 'something only shown when logged in' in res.get_data(as_text=True).lower()

Calling authenticated APIs

Though we’ve managed to create a working session a problem now arises if you try to actually call an API, by using google.get('some url') for example. Your token will fail to validate and the request will be denied.

This can be handled by a Python library called responses, which lets us control the full HTTP request cycle.

Warning

Note that this means we’re essentially mocking the API we’re calling, so your tests will continue passing even if the real API has changed behaviour.

Let’s assume the index route calls out to the Google Plus API and displays some profile information. Here’s how you could handle that.

import pytest
import responses


@responses.activate
def test_getting_profile(loggedin_app):
    """Test displaying profile information."""
    responses.add(
        responses.GET,
        'https://www.googleapis.com/plus/v1/people/me',
        status=200,
        json={
          'kind': 'plus#person',
          'id': '118051310819094153327',
          'displayName': 'Chirag Shah',
          'url': 'https://plus.google.com/118051310819094153327',
          'image': {
            'url': 'https://lh5.googleusercontent.com/-XnZDEoiF09Y/AAAAAAAAAAI/AAAAAAAAYCI/7fow4a2UTMU/photo.jpg'
          }
        })
    res = loggedin_app.get('/')
    assert len(responses.calls) == 1
    assert res.status_code == 200
    assert res.content_type == 'text/html; charset=utf-8'
    assert 'some profile information we fetched' in res.get_data(as_text=True).lower()

Responses can do a lot more for you, but you’ll have to refer to its documentation instead.

Developer Interface

Consumers

An OAuth consumer is a website that allows users to log in with other websites (known as OAuth providers). Once a user has gone through the OAuth dance, the consumer website is allowed to interact with the provider website on behalf of the user.

class flask_dance.consumer.OAuth1ConsumerBlueprint(...)[source]

A subclass of flask.Blueprint that sets up OAuth 1 authentication.

__init__(name, import_name, client_key=None, client_secret=None, signature_method='HMAC-SHA1', signature_type='AUTH_HEADER', rsa_key=None, client_class=None, force_include_body=False, static_folder=None, static_url_path=None, template_folder=None, url_prefix=None, subdomain=None, url_defaults=None, root_path=None, login_url=None, authorized_url=None, base_url=None, request_token_url=None, authorization_url=None, access_token_url=None, redirect_url=None, redirect_to=None, session_class=None, backend=None, **kwargs)[source]

Most of the constructor arguments are forwarded either to the flask.Blueprint constructor or the requests_oauthlib.OAuth1Session construtor, including **kwargs (which is forwarded to OAuth1Session). Only the arguments that are relevant to Flask-Dance are documented here.

Parameters:
  • base_url – The base URL of the OAuth provider. If specified, all URLs passed to this instance will be resolved relative to this URL.
  • request_token_url – The URL specified by the OAuth provider for obtaining a request token. This can be an fully-qualified URL, or a path that is resolved relative to the base_url.
  • authorization_url – The URL specified by the OAuth provider for the user to grant token authorization. This can be an fully-qualified URL, or a path that is resolved relative to the base_url.
  • access_token_url – The URL specified by the OAuth provider for obtaining an access token. This can be an fully-qualified URL, or a path that is resolved relative to the base_url.
  • login_url – The URL route for the login view that kicks off the OAuth dance. This string will be formatted with the instance so that attributes can be interpolated. Defaults to /{bp.name}, so that the URL is based on the name of the blueprint.
  • authorized_url – The URL route for the authorized view that completes the OAuth dance. This string will be formatted with the instance so that attributes can be interpolated. Defaults to /{bp.name}/authorized, so that the URL is based on the name of the blueprint.
  • redirect_url – When the OAuth dance is complete, redirect the user to this URL.
  • redirect_to – When the OAuth dance is complete, redirect the user to the URL obtained by calling url_for() with this argument. If you do not specify either redirect_url or redirect_to, the user will be redirected to the root path (/).
  • session_class – The class to use for creating a Requests session between the consumer (your website) and the provider (e.g. Twitter). Defaults to OAuth1Session.
  • backend – A storage backend class, or an instance of a storage backend class, to use for this blueprint. Defaults to SessionBackend.
session[source]

An OAuth1Session instance that automatically loads tokens for the OAuth provider from the backend. This instance is automatically created the first time it is referenced for each request to your Flask application.

backend

The token storage backend that this blueprint uses.

token

The OAuth token currently loaded in the session attribute.

config

A special dictionary that holds information about the current state of the application, which the backend can use to look up the correct OAuth token from storage. For example, in a multi-user system, where each user has their own OAuth token, information about which user is currently logged in for this request is stored in this dictionary. This dictionary is special because it automatically alerts the backend when any attribute in the dictionary is changed, so that the backend’s caches are appropriately invalidated.

from_config

A dictionary used to dynamically load variables from the Flask application config into the blueprint at the start of each request. To tell this blueprint to pull configuration from the app, set key-value pairs on this dict. Keys are the name of the local variable to set on the blueprint object, and values are the variable name in the Flask application config. Variable names can be a dotpath. For example:

blueprint.from_config["session.client_id"] = "GITHUB_OAUTH_CLIENT_ID"

Which will cause this line to execute at the start of every request:

blueprint.session.client_id = app.config["GITHUB_OAUTH_CLIENT_ID"]
class flask_dance.consumer.OAuth2ConsumerBlueprint(...)[source]

A subclass of flask.Blueprint that sets up OAuth 2 authentication.

__init__(name, import_name, client_id=None, client_secret=None, client=None, auto_refresh_url=None, auto_refresh_kwargs=None, scope=None, state=None, static_folder=None, static_url_path=None, template_folder=None, url_prefix=None, subdomain=None, url_defaults=None, root_path=None, login_url=None, authorized_url=None, base_url=None, authorization_url=None, authorization_url_params=None, token_url=None, token_url_params=None, redirect_url=None, redirect_to=None, session_class=None, backend=None, **kwargs)[source]

Most of the constructor arguments are forwarded either to the flask.Blueprint constructor or the requests_oauthlib.OAuth2Session construtor, including **kwargs (which is forwarded to OAuth2Session). Only the arguments that are relevant to Flask-Dance are documented here.

Parameters:
  • base_url – The base URL of the OAuth provider. If specified, all URLs passed to this instance will be resolved relative to this URL.
  • authorization_url – The URL specified by the OAuth provider for obtaining an authorization grant. This can be an fully-qualified URL, or a path that is resolved relative to the base_url.
  • authorization_url_params (dict) – A dict of extra key-value pairs to include in the query string of the authorization_url, beyond those necessary for a standard OAuth 2 authorization grant request.
  • token_url – The URL specified by the OAuth provider for obtaining an access token. This can be an fully-qualified URL, or a path that is resolved relative to the base_url.
  • token_url_params (dict) – A dict of extra key-value pairs to include in the query string of the token_url, beyond those necessary for a standard OAuth 2 access token request.
  • login_url – The URL route for the login view that kicks off the OAuth dance. This string will be formatted with the instance so that attributes can be interpolated. Defaults to /{bp.name}, so that the URL is based on the name of the blueprint.
  • authorized_url – The URL route for the authorized view that completes the OAuth dance. This string will be formatted with the instance so that attributes can be interpolated. Defaults to /{bp.name}/authorized, so that the URL is based on the name of the blueprint.
  • redirect_url – When the OAuth dance is complete, redirect the user to this URL.
  • redirect_to – When the OAuth dance is complete, redirect the user to the URL obtained by calling url_for() with this argument. If you do not specify either redirect_url or redirect_to, the user will be redirected to the root path (/).
  • session_class – The class to use for creating a Requests session between the consumer (your website) and the provider (e.g. Twitter). Defaults to OAuth2Session.
  • backend – A storage backend class, or an instance of a storage backend class, to use for this blueprint. Defaults to SessionBackend.
session[source]

An OAuth2Session instance that automatically loads tokens for the OAuth provider from the backend. This instance is automatically created the first time it is referenced for each request to your Flask application.

backend

The token storage backend that this blueprint uses.

token

The OAuth token currently loaded in the session attribute.

config

A special dictionary that holds information about the current state of the application, which the backend can use to look up the correct OAuth token from storage. For example, in a multi-user system, where each user has their own OAuth token, information about which user is currently logged in for this request is stored in this dictionary. This dictionary is special because it automatically alerts the backend when any attribute in the dictionary is changed, so that the backend’s caches are appropriately invalidated.

from_config

A dictionary used to dynamically load variables from the Flask application config into the blueprint at the start of each request. To tell this blueprint to pull configuration from the app, set key-value pairs on this dict. Keys are the name of the local variable to set on the blueprint object, and values are the variable name in the Flask application config. Variable names can be a dotpath. For example:

blueprint.from_config["session.client_id"] = "GITHUB_OAUTH_CLIENT_ID"

Which will cause this line to execute at the start of every request:

blueprint.session.client_id = app.config["GITHUB_OAUTH_CLIENT_ID"]

Backends

class flask_dance.consumer.backend.session.SessionBackend(...)[source]

The default storage backend. Stores and retrieves OAuth tokens using the Flask session.

__init__(key='{bp.name}_oauth_token')[source]
Parameters:key (str) – The name to use as a key for storing the OAuth token in the Flask session. This string will have .format(bp=self.blueprint) called on it before it is used. so you can refer to information on the blueprint as part of the key. For example, {bp.name} will be replaced with the name of the blueprint.
class flask_dance.consumer.backend.sqla.SQLAlchemyBackend(...)[source]

Stores and retrieves OAuth tokens using a relational database through the SQLAlchemy ORM.

__init__(model, session, user=None, user_id=None, user_required=None, anon_user=None, cache=None)[source]
Parameters:
  • model – The SQLAlchemy model class that represents the OAuth token table in the database. At a minimum, it must have a provider column and a token column. If tokens are to be associated with individual users in the application, it must also have a user relationship to your User model. It is recommended, though not required, that your model class inherit from OAuthConsumerMixin.
  • session – The SQLAlchemy session for the database. If you’re using Flask-SQLAlchemy, this is db.session.
  • user – If you want OAuth tokens to be associated with individual users in your application, this is a reference to the user that you want to use for the current request. It can be an actual User object, a function that returns a User object, or a proxy to the User object. If you’re using Flask-Login, this is current_user.
  • user_id – If you want to pass an identifier for a user instead of an actual User object, use this argument instead. Sometimes it can save a database query or two. If both user and user_id are provided, user_id will take precendence.
  • user_required – If set to True, an exception will be raised if you try to set or retrieve an OAuth token without an associated user. If set to False, OAuth tokens can be set with or without an associated user. The default is auto-detection: it will be True if you pass a user or user_id parameter, False otherwise.
  • anon_user – If anonymous users are represented by a class in your application, provide that class here. If you are using Flask-Login, anonymous users are represented by the flask_login.AnonymousUserMixin class, but you don’t have to provide that – Flask-Dance treats it as the default.
  • cache – An instance of Flask-Caching. Providing a caching system is highly recommended, but not required.
get(blueprint, user=None, user_id=None)[source]

When you have a statement in your code that says “if <provider>.authorized:” (for example “if twitter.authorized:”), a long string of function calls result in this function being used to check the Flask server’s cache and database for any records associated with the current_user. The user and user_id parameters are actually not set in that case (see base.py:token(), that’s what calls this function), so the user information is instead loaded from the current_user (if that’s what you specified when you created the blueprint) with blueprint.config.get(‘user_id’).

Parameters:
  • blueprint
  • user
  • user_id
Returns:

Indices and tables