Connecting to Garmin Connect with Elixir

October 15, 2019
by
Evan Dancer

This is a bit of a tutorial on how to connect to the Garmin API using Phoenix Elixir. While this is written in Elixir, my thought is that the general steps are the same regardless of the language.


Garmin uses OAuth 1.0 which I have never used before. I found it a little bit more difficult than I expected. As usual, you will save some time if you read the documentation first. Jumping right into developing this feature lost me quite a bit of time. 


 A little bit about OAuth 1.0 to start in case you have never used it before. With all OAuth 1.0 requests, you have to send a signature with the request. First, you must build a string encoding of the request. This takes the shape of {{request method}}&{{url}}&{{params}}. These parameters are joined by ampersands and must be encoded as well. Here is an example: 


Unescaped:

POST&https://connectapi.garmin.com/oauth-service/oauth/request_token&oauth_consumer_key=1&oauth_nonce=1&oauth_signature_method=HMAC-SHA&oauth_timestamp=1572409117&oauth_version=1.0


Escaped:

POST&https%3A%2F%2Fconnectapi.garmin.com%2Foauth-service%2Foauth%2Frequest_token&oauth_consumer_key%3D1%26oauth_nonce%3D1%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1572409117%26oauth_version%3D1.0


You next take the escaped string from above and sign it using the signature method (HMAC-SHA1 in this case) and the string {{consumer_secret}}&{{secret_token}}. If you do not have a secret token, you leave the ampersand and the secret token off of the string.


Alright, let's get back to Garmin authentication. Using the signature method above, you need to make a post request to get the request token. You can see my code for this below:


https://github.com/edance/openpace/blob/43688c8528c27f92408db4c3624f7f8f3753e937/lib/squeeze/garmin/auth.ex#L24


This function gives you two things: a token and a token secret. We have to save the token secret for a later step. I stored this in the session to make it easier to grab later. 


https://github.com/edance/openpace/blob/43688c8528c27f92408db4c3624f7f8f3753e937/lib/squeeze_web/controllers/integration_controller.ex#L11


Next using the token, we construct the URL where the user can sign into Garmin. We also add a callback param to our URL. This tells Garmin where to send the user after they have successfully signed in with their account and allowed our app to connect. We redirect the user to this URL.


https://github.com/edance/openpace/blob/43688c8528c27f92408db4c3624f7f8f3753e937/lib/squeeze/garmin/auth.ex#L18


Putting it all together with our integration controller request method for Garmin now looks like this:


https://github.com/edance/openpace/blob/43688c8528c27f92408db4c3624f7f8f3753e937/lib/squeeze_web/controllers/integration_controller.ex#L11


When Garmin redirects the user back to our website, they now include two parameters. The first one is the token from before. The second is the verifier. This verifier is required because without this piece of information we wouldn’t have needed to talk to Garmin and we wouldn’t know which user. With all this information we send a request to Garmin with the token and verifier (from this request) and the token secret from the request step.


With this information, we can save the users token and token secret to our database to use later on.


Here is the commit with all of my changes to get Garmin authentication working so that I can track my runs as I train for my marathon. If this interests you, feel free to make a pull request for OpenPace. I would love any help!

Keep in the Loop

Be the first to know when we launch new features, training tools, posts, and much more.

You're all set. Stay tuned!
Oops! Something went wrong.