Search code examples
pythonflaskoauth-2.0fitbitflask-dance

Flask OAuth 2.0 Authorization Code Flow Invalid Authorization Token with Fitbit API


I've been trying to use Flask-dance's OAuth2ConsumerBlueprint to make requests to the Fitbit API. So far, I've managed to get the authorization page to come up on my Flask app but I haven't been able to route to a page where I can view the data yet.

In browser, when I try to make a request I get the output of the CURL response {"errors":[{"errorType":"system","fieldName":"n/a","message":"Authorization Error: Invalid authorization token type"}],"success":false}

My goal right now is just to be able to view the user's fitbit dashboard in my app through the API by making a request through the app to "https://api.fitbit.com/1/user/-/profile.json"

This is my code so far. If anyone could offer some guidance as to where I'm going wrong with the Oauth2.0 authorization code flow, flask, or the fitbit api I would greatly appreciate it.

from flask import Flask, redirect, url_for, render_template
from flask_dance import OAuth2ConsumerBlueprint

import os
os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'


CLIENT_ID = 'CLIENT_ID'  # OAuth 2.0 Client ID
CLIENT_SECRET = CLIENT_SECRET'
scope = ["activity",
         "nutrition",
         "heartrate",
         "location",
         "nutrition",
         "profile",
         "settings",
         "sleep",
         "social",
         "weight",
         ]

# Flask OAuth2 Custom Blueprint for Fitbit API
app = Flask(__name__)
fitbit_blueprint = OAuth2ConsumerBlueprint(
    "fitbit-api", __name__,
    client_id=CLIENT_ID,
    client_secret=CLIENT_SECRET,
    base_url="https://www.fitbit.com",
    token_url="https://api.fitbit.com/oauth2/token",
    authorization_url="https://www.fitbit.com/oauth2/authorize",
    scope=scope
)
app.register_blueprint(fitbit_blueprint, url_prefix="/login")
app.secret_key = "supersecret"  # Replace this

app.token = fitbit_blueprint.token
print(app.token)


@app.route("/")
def index():
    #return redirect(url_for("fitbit-api.login"))
    return render_template('index.html')


@app.route("/success")
def access():
    return "Success"


@app.route('/login')
def login():
    return redirect(url_for("fitbit-api.login"))


# Redirect URI = http://127.0.0.1:
if __name__ == '__main__':
    app.run(host="localhost", port=5000, debug=True)


Solution

  • You can not access the (user profile) resource before you get authorized from fitbit. Once you got authorized, you will need to exchange your authorization code with a Token Pair and save the tokens - namely Access Token and Refresh Token - somewhere in your code.

    Solely being able to reach and pass the authorization page does not mean that you've been authorized. You can check if your authorization is completed within your fitbit profile: Open your Fitbit profile -> My Dashboard -> Settings. From the left panel choose Applications. There you should be able to see a list of authorized apps: If you don't, you haven't changed your authorization code with a token pair yet!

    You can only then be able to make requests to the user-profile endpoint in which case you have to build up an http post with your valid saved Access Token in its header as in https://dev.fitbit.com/build/reference/web-api/oauth2/#making-requests.