a tale of complexity

Let me tell you a tale – a tale of magic and power. Ok, maybe there isn’t any real magic to this other than the magic described by Arthur Clarke in this quote: “Any sufficiently advanced technology is indistinguishable from magic.”

My reference to power is in the sense of what you as a third party are authorized to do on behalf of another user. This is the magical1 world of Oauth.

1 It’s not really magic.

Oauth, you say? That’s been around since the mid 2000s with Twitter forcing it onto developers in 2010. That’s more than a decade old, ancient history. Fair enough. I connected howmuchtogo.com in 2014 with Strava using Oauth v1. It was a great learning experience. With Oauth v1, you direct your user to an authorization page on the Oauth server to obtain a “forever access token” that your app uses to access Strava on behalf of the user. Most, but not all, websites have upgraded to Oauth v2, which replaces the forever token with an access/refresh token pair. If you are interested in more details about how Oauth works, skip to the Oauth Overview section at the end of this post.

Let the tale begin…

The stage has been set! The die has been cast! Let us begin our tale of complexity. There are THREE primary actors in this tale: mybiketraffic.com, Garmin Connect, and Strava.

Garmin Connect is the web service provided by Garmin for programmatically accessing activities recorded on Garmin cycling computers and smart watches. Garmin Connect still uses Oauth v1 forever tokens.

Strava provides a similar API for accessing any activities (i.e., rides) that a user creates via manual upload or automatic sync. Strava started out using Oauth v1, but is now using Oauth v2.

mybiketraffic.com is my research project for analyzing the radar data collected during a ride. My website is an Oauth client only – meaning I manage all the IDs, tokens, and secrets provided by Garmin and Strava, but I don’t have to worry about generating any of these tokens or secrets.

Where it gets complex is how these three services interact with each other, and in particular, the order in which the communication needs to happen.

Let me paint you a picture. Imagine it’s a clear, blue sunny day (or it could be pouring down rain, it doesn’t matter). I set out on a bike ride that is recorded with any compatible Garmin Edge cycling GPS computer or sport watch with the MyBikeTraffic ConnectIQ app installed (37,500+ 50,000 users!). Paired with that bike computer is a Garmin Varia radar tail light camera collecting speed and location data for all the cars passing me. Given that it’s Birmingham, a million (not literally) vehicles pass me on my ride to and from work. I make it back home and end my ride.

What happens next? Buckle up.

First, all of the cycling and radar data from the ride stored inside my bicycle computer is wirelessly transferred to my smartphone.

Next, my smartphone, via the Garmin Connect app, uploads all of that data to the Garmin Connect website.

After that, Garmin Connect itself starts to send out push messages to any Oauth authenticated clients. In this case, mybiketraffic.com AND Strava both receive notifications that a new ride has been uploaded to Garmin Connect. It’s unclear in what order those messages are sent. Let’s assume it’s essentially in parallel or the order could be random based on network conditions.

Either my website or Strava receives notification of the new activity available for downloading. Both my website and Strava essentially do the same thing: use the stored Oauth forever token to download all the details of the activity to add the activity to our websites as shown below.

mybiketraffic.com view of a radar-enabled ride automatically imported from Garmin Connect. Note the total number of cars reported at the top as well as the individual passing location of each car. Furthermore the video recorded matches the location of the moving tan circle shown on the left near the Pell City Fire Department.
Strava view of my ride automatically imported from Garmin Connect. Note that by default, Strava throws away all the radar data. It’s only by jumping through a bunch of complex hoops that I am now able to automatically get the radar data onto my Strava ride description automatically. Continue reading the blog post to see how that data gets there.

So where are we at now? Mybiketraffic.com now has the ride data. Strava now has the ride data, but they are not connected in any way … yet.

Again, what happens next?

Mybiketraffic.com receives a push notification from Strava that a new activity has been “created” (i.e., uploaded/synced). I then launch a background process that sleeps for the first two minutes and doesn’t do anything. The idea is to guarantee that my website has had a chance to receive the push notification from Garmin Connect, retrieve the ride, and import it onto the website.

At this point, the rides should match since they originated from the same Garmin connect data. Depending on the user settings below, my website can then use the Strava API to automatically add a summary of the radar data to the Strava ride description.

mybiketraffic.com Strava integration settings for controlling how the radar data is summarized and added to the ride description for the matching Strava ride.

And that’s how it’s done … magic!

Oauth Overview

This section explain Oauth in a little more detail. The “forever” nature of the Oauth v1 tokens represent a security risk in that the forever token is essentially a permanent password being sent back and forth (encrypted hopefully) and stored on a potentially vulnerable third party server that Strava has no control over. For Strava to accept this forever token, it must be paired with the correct client ID and client secret associated with your app. But if those are all stored insecurely or ever sent via plain text HTTP, then that poses a risk to Strava user data! Imagine a hacker who is able to obtain all three pieces: the client id, the client secret, and one or more users forever access tokens. That hacker could do anything with the user’s data. Not good.

Enter Oauth 2, which replaced forever tokens with temporary access tokens that must be refreshed after a fairly short period of time (usually just 1-2 days). The access token can only be refreshed with a separate user-specific refresh token that is essentially a one-time usage token as you get a new access token and new refresh token each time the access token expires. Theoretically, on the server side (Strava), this setup makes it easier to revoke the access token even if it hasn’t expired. Although, it is not entirely clear to me why invalidating a forever token or refresh token is particularly difficult?

In some sense, there’s not much additional security here. Playback requests for a new access token can be thwarted since the refresh token is a one-time use only. Yet, a hacker still only need three pieces of data: the client id, the client secret, and the refresh token to obtain a new access token. If the website it not heavily used by a given user, than it’s likely the hacker would be the first to access and use the refresh token while it is still valid.

If you are interested, there are plenty of other places that go into all the Oauth details. Interestingly, it’s up to each Oauth server to determine exactly how they implement those details. Strava documents their process here along with a quite complex diagram showing the process: Strava Oauth guide

Keep in mind, this is just Strava! Garmin’s implementation of Oauth is still using v1, and is completely different. They document the process in a very long PDF file that is only available to approved developers (although I imagine if you look hard enough it should be fairly easy to find online).

1 comment

  1. Love the tone and explanations of the article. Though I understand partially, it is a very intersection read. Nice especially to get a glimpse into this world you know.

Leave a comment

Your email address will not be published. Required fields are marked *