A Guide To Continuously Querying User Data via the Fitbit API

Qi Xuan Khoo
Digital Biomarker Discovery
9 min readJan 26, 2022

As wearable devices become increasingly popular, the user data generated from these devices are an invaluable source of information for digital health research. For instance, wearables data have facilitated the development of predictive models for viral infection in light of the pandemic. To enable such analysis, a secure method of accessing data is required. OAuth 2.0 is the industry-standard authorization protocol that enables one application to access resources from a second application’s resources on a user’s behalf. For instance, OAuth 2.0 enables continuous access to Fitbit data through the Fitbit API. This guide provides a high-level overview of the OAuth 2.0 workflow for the Fitbit Web API and a four-step approach to querying Fitbit user data.

Photo by John Schnobrich on Unsplash

The Concert Ticket Analogy

Let’s start by understanding how OAuth 2.0 works through a simple analogy, with key terms italicized:

Imagine you are attending a classical music concert. As a concert-goer, you are the client and the musicians performing at the concert are the resource owner (the resource being the musicians’ music). You purchase a ticket online and receive a receipt (the authorization code) with which you will redeem a concert ticket (the access token) at the ticketing booth on concert day to enjoy the music (the resource). Fast forward to concert day: you enter the concert hall with your ticket (analogous to querying data from the API using an access token). Suppose you need to leave for the bathroom during the intermission. You’ll need to have your ticket stamped so that you’ll be admitted back to the concert hall — this is analogous to obtaining a refresh token with which you use to obtain a new access token after the previous token expires. Voila, that’s OAuth 2.0 in a nutshell!

(Check out this article by Aaron Parecki to dive deeper into the world of OAuth 2.0)

OAuth 2.0 for the Fitbit API (in Four Steps)

Keeping the concert ticket analogy in mind, let’s now explore how we, the client, would access users’ data through the Fitbit API via four steps. Before diving into the steps, let’s break down some key terms specific to the Fitbit Web API (all data types are strings):

  • Authorization code: This is the code we first receive once the user consents to sharing their data. Think of it as the online purchase receipt with which you can redeem a concert ticket — the access token — at the ticket booth on concert day.
  • Access token: This is the token we use to query user data. Think of it as the concert ticket that allows us to enter the concert hall and enjoy the music.
  • Refresh token: This is the token we need to obtain a new pair of access and refresh tokens when the current access token expires. Think of it as the stamp on our concert ticket to guarantee readmission into the concert hall.

As with all other APIs, all interactions with the Fitbit Web API are conducted via Hypertext Transfer Protocol (HTTP) requests.

(If you are not familiar with HTTP requests, specifically the GET and POST requests, we strongly encourage you to read through this excellent article by W3Schools before moving on.)

We outline the following four steps for continuously querying user data via the Fitbit Web API:

  1. Obtain an authorization code by acquiring user consent (POST request)
  2. Trade the authorization code for access and refresh tokens (POST request)
  3. Query user data with the access token (GET request)
  4. Trade the refresh token for a new pair of access and refresh tokens
    (POST request)

Step 1: Obtain the authorization code

To begin, let’s figure out how we would obtain the authorization code by acquiring a user’s consent, which is analogous to obtaining our online purchase receipt to redeem our concert ticket. Here’s a quick overview of the workflow:

Figure 1: Steps for the POST request to obtain an Authorization Token

The required fields for the POST request to obtain an authorization code are:

  • Client ID: The public identifier of our registered app (see Figure 2 below)
  • Redirect URL: The link to the page to which the user will be re-routed after granting consent (see Figure 2 below)
  • Response type: Always set to “code” by default
  • Scope: All of the different scopes and types of data. In the case of Fitbit data, this includes heart rate, activity etc.

Figure 2: A screenshot of the CovIdentify app’s Registered App Account in the Fitbit API portal (https://dev.fitbit.com/apps/details/{your client ID})

First, construct a url (example shown below) with the clientid (orange), redirect url (yellow), and all the different scopes (green) that the user should grant permission for:

This url will direct a user (the person who wears the Fitbit) to the Fitbit consent page (Figure 3):

Figure 3: Consent Form which enables the User to allow the Client access to the different Scopes

Upon form submission, we (the Client) will receive the authorization code in the form of a string of characters in a url with the prefix “code=” and a suffix (a unique alphanumeric string)” (the red box in Figure 4):

Figure 4: Authorization Code embedded in the redirect URL that is sent once the User hits “Allow”

Ideally, the webpage that the user is redirected to after hitting “Allow” (Figure 3), which is defined in the above URL and highlighted in yellow, is a page we own or control so that the authorization code can be obtained and stored easily. The redirect url of this page can be configured on your Registered App Account on the Fitbit Web API website (see Figure 2 above).

Step 2: Exchange the authorization code for an access/refresh token package

With our authorization code (our online purchase receipt) in hand, we’re ready to redeem it for our access token (concert ticket). We will now make a POST request with 3 parameters — the url endpoint, headers, and data — to trade the authorization code for an access token:

  • Data: a dictionary with 3 key/value pairs

We can interpret the response we receive upon making the POST request as a JSON (JavaScript Object Notation) and isolate the new access token or refresh token as we would get a value from a dictionary. The red boxes in the image below of a sample Python script that executes this POST request indicate which request parameters need to be replaced:

Step 3: Query the user data with the access token

Now that we have redeemed our concert ticket, let the show begin! Here’s a quick overview of the Fitbit API query workflow (see steps 1 and 2 in Figure 5 below) :

Figure 5: Fitbit API Query Workflow

To retrieve user data, we make a GET request with two parameters: the endpoint and the headers. Depending on the data we want, we will make a request to a certain endpoint (a url). For example, the following endpoint will give us the intraday time series for heart rate. Fitbit defines the intraday time series as measurements at a frequency of one minute for each day.

https://api.fitbit.com/1/user/user_id/activities/heart/date/today/1d/1min.json

We will represent the headers as a dictionary containing one key/value pair, the key being “Authorization” and its value being “Bearer “ (note the space) concatenated with the access token from the previous step. We can interpret the response as JSON and isolate the data by treating the returned response as a dictionary.

Step 4: Exchange the refresh token for a new access-refresh token pair

Having gone through the first half of the concert, we’re now at the intermission and we need to have our ticket stamped for readmission — obtaining a new access token and refresh token with our current refresh token. To do so, we will make a POST request with three parameters — the redirect url, the headers, and the data — to obtain a new pair of access and refresh tokens (see items 3 and 4 in Figure 6). The redirect url should correspond with the one in our Fitbit application portal (see Figure 1).

As before, the headers should be a dictionary with two sets of key/value pairs:

The data will be a dictionary with two key/value pairs:

We will receive the response in the JSON format from which we can extract the new access token and refresh token as we would get a value from a dictionary. The red boxes indicate which credentials need to be replaced:

A Caveat on Refresh Tokens

Recall that unlike access tokens, refresh tokens do not expire, but they can become expended. Here is the caveat on using the same refresh-access token pair to access the same user’s data from multiple apps via the Fitbit Web API: if you and your colleague are accessing the same user data with the same access token, it is possible to invalidate the tokens, as in Figure 6:

Figure 6: The Caveat on Using Refresh Tokens

Therefore, to ensure continuous access to user data for both you and your colleague, we would recommend exchanging the current refresh token immediately for the next access-refresh token pair and storing them away every time you receive a new access token and a refresh token. This would ensure the ability of both you and your colleague to renew the access token before it expires and that all clients trying to access the data are at the same checkpoint.

Summary

In short, we have covered the key steps of:

  1. Obtaining the user’s consent to share data
  2. Obtaining the first refresh-access token pair via the authorization code
  3. Exchanging the refresh token for a new refresh-access token pair to ensure continuous access to the user’s data

for the Fitbit Web API. The original Fitbit documentation can be found here.

As the industry-standard authorization protocol for access to third-party resources, OAuth 2.0 is perhaps the most common and crucial component in establishing secure access to health data. As part of Open DBDP, we hope this resource will help researchers develop secure data pipelines to access real world data for digital biomarker discovery.

Special thanks to Yvonne Kuo and Sean Fiscus who worked with the author on this project, and to the Bass Connections CovIdentify Team and Dr. Jessilyn Dunn for their support and guidance.

--

--