07-28-2018 14:04
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

07-28-2018 14:04
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
I'm hoping someone can help me figuring out how to refresh my authorization tokens when using the web api. I'm a software developer, so I have some clue, but I'm pretty new to Fitbit's API and totally out of my depth when it comes to OAuth and web development in general.
Anyway, I am writing a simple app for the Ionic, but needed some extra information from the Web API, since not everything is available in the SDK. I got the Web API access working (yay), but currently I have to keep manually refreshing the access tokens whenever they expire. I'm trying to write code to do the refresh, but I've run into a snag. My refresh is failing, but I'm not getting any error information to help me debug. Here is the code I'm currently using to run the refresh:
function refreshOauthTokens() { fetch(`https://api.fitbit.com/oauth2/token`, { method: "GET", headers: { "Authorization": `Basic XXXXX`, grant_type: 'refresh_token' }, body: urlEncodePost({ grant_type: 'refresh_token', refresh_token: refreshToken }) }) .then(function(res) { console.log("RES", res); return res.json(); }) .then(function(data) { console.log("Refreshed:",data); accessToken = data.access_token; refreshToken = data.refresh_token; }) .catch(function(error) { console.log("Error: Refreshing tokens failed:", error); }); }
Unfortunately, the Error message prints, but with an empty dictionary, so something is failing, but I'm not sure where or what. Is there anyone that can help?
Any ideas would be very welcome. Alternatively, if someone has or can direct me to a working example of the refresh operations that'd really help. I've gotten as far as I have by looking at lots of examples, so just a working example I can dissect would probably get me unstuck.
Thanks in advance!
Geoff
Answered! Go to the Best Answer.

Accepted Solutions
07-28-2018 16:12 - edited 07-28-2018 17:01
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

07-28-2018 16:12 - edited 07-28-2018 17:01
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Ok, I made some progress, and in the interest of others not making the same mistakes, here's where I'm at at the moment:
- Need to use "POST" for refresh action. Copy/paste error on my part (tried to adapt code for getting data).
- grant_type and refresh_token are encoded in the URL. This is non-obvious in the docs. Many other (non-fitbit) OAuth cases use "body" or "form" or other stuff in the data dictionary passed to fetch, so this should really be better documented by Fitbit in their developer pages (an example would go a long way).
Here's my code (still needs cleanups):
function refreshOauthTokens() { var URL = "https://api.fitbit.com/oauth2/token?" + urlEncodePost({ grant_type: 'refresh_token', refresh_token: refreshToken }); fetch(URL, { method: "POST", headers: { "Authorization": `Basic ${b64Client}`, "Content-Type": "application/x-www-form-urlencoded" } }) .then(function(res) { return res.json(); }) .then(function(data) { console.log("Refreshed:",data); accessToken = data.access_token; refreshToken = data.refresh_token; }) .catch(function(error) { console.log("Error: Refreshing tokens failed:", error); }); }
Thanks!
Geoff

07-28-2018 16:12 - edited 07-28-2018 17:01
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

07-28-2018 16:12 - edited 07-28-2018 17:01
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Ok, I made some progress, and in the interest of others not making the same mistakes, here's where I'm at at the moment:
- Need to use "POST" for refresh action. Copy/paste error on my part (tried to adapt code for getting data).
- grant_type and refresh_token are encoded in the URL. This is non-obvious in the docs. Many other (non-fitbit) OAuth cases use "body" or "form" or other stuff in the data dictionary passed to fetch, so this should really be better documented by Fitbit in their developer pages (an example would go a long way).
Here's my code (still needs cleanups):
function refreshOauthTokens() { var URL = "https://api.fitbit.com/oauth2/token?" + urlEncodePost({ grant_type: 'refresh_token', refresh_token: refreshToken }); fetch(URL, { method: "POST", headers: { "Authorization": `Basic ${b64Client}`, "Content-Type": "application/x-www-form-urlencoded" } }) .then(function(res) { return res.json(); }) .then(function(data) { console.log("Refreshed:",data); accessToken = data.access_token; refreshToken = data.refresh_token; }) .catch(function(error) { console.log("Error: Refreshing tokens failed:", error); }); }
Thanks!
Geoff

07-28-2018 17:03
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

07-28-2018 17:03
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Ok, I made some progress, and in the interest of others not making the same mistakes, here's where I'm at at the moment:
- Need to use "POST" for refresh action. Copy/paste error on my part (tried to adapt code for getting data. Oops).
- grant_type and refresh_token are encoded in the URL. This is non-obvious in the docs. Many other (non-fitbit) OAuth cases use "body" or "form" or other stuff in the data dictionary passed to fetch, so this should really be better documented by Fitbit in their developer pages (an example would go a long way).
Here's my code (still needs cleanups):
function refreshOauthTokens() { var URL = "https://api.fitbit.com/oauth2/token?" + urlEncodePost({ grant_type: 'refresh_token', refresh_token: refreshToken }); fetch(URL, { method: "POST", headers: { "Authorization": `Basic ${b64Client}`, "Content-Type": "application/x-www-form-urlencoded" } }) .then(function(res) { return res.json(); }) .then(function(data) { console.log("Refreshed:",data); accessToken = data.access_token; refreshToken = data.refresh_token; }) .catch(function(error) { console.log("Error: Refreshing tokens failed:", error); }); }
Thanks!
Geoff

07-28-2018 18:53
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post


07-28-2018 18:53
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
I'm currently traveling at the moment, so I haven't been able to test this, but, I've seen it done a few ways:
let tokenUrl = "xxx"; let clientId = "xxx"; let clientSecret = "xxx"; let refreshToken = "xxx"; let body = `grant_type=refresh_token&refresh_token=${refreshToken}`; body += `&client_id=${clientId}&client_secret=${clientSecret}`; const response = await fetch( tokenUrl, { method: 'POST', body, headers: { 'content-type': 'application/x-www-form-urlencoded', } }, ); return response.json(); //////// let body = { grant_type: 'refresh_token', client_id: 'xxxx', refresh_token: 'xxxx' }; let urlEncodedBody = Object.keys(body).map(key => key + '=' + body[key]).join('&'); urlEncodedBody = urlEncodedBody.split('\"').join(''); let requestOptions = { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: urlEncodedBody };
Please update with the working solution!

07-29-2018 15:52
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

07-29-2018 15:52
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Well, I'm still working on getting the system to call the refresh reliably, but I've gotten the refresh operation to work. Here's my code:
function refreshOauthTokens() { var URL = "https://api.fitbit.com/oauth2/token?" + urlEncodePost({ grant_type: 'refresh_token', refresh_token: refreshToken }); fetch(URL, { method: "POST", headers: { "Authorization": `Basic ${b64Client}`, "Content-Type": "application/x-www-form-urlencoded" } }) .then(function(res) { return res.json(); }) .then(function(data) { if (!("errors" in data)) { accessToken = data.access_token; refreshToken = data.refresh_token; } else { // Error handling? } }) .catch(function(error) { console.log("Error: Refreshing tokens failed:", error); }); }
This is based upon code for getting sleep data (assuming valid token) from https://github.com/Fitbit/sdk-oauth, which I used pretty extensively for figuring out how to access the web api.
Thanks for the other examples. I haven't tried them either, but will keep them in mind if I need to revise further. I think I came close to one or the other of them, but never quite there. I know I worked with 'body' a lot before hitting on the building my own URL solution.
Geoff

