11-28-2017 08:13 - edited 11-30-2017 05:01
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

11-28-2017 08:13 - edited 11-30-2017 05:01
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
I need to use the companion for handling the communication to 3rd party REST Web API.
I am able to perform the web requests (GET and POST) using fetch but for some of them the authentication is required.
I see that in Strava app, the user can click on Strava Login in settings area and an instance of the browser is opened on Strava authentication page.
As soon as the credentials are provided the user and - I guess 🙂 - a token are saved in companion settings. In this way I could avoid to store user and password directly in app settings.
How can I implement something similar?
Answered! Go to the Best Answer.

- Labels:
-
JavaScript
Accepted Solutions
12-07-2017 12:02
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post


12-07-2017 12:02
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
- Who Voted for this post?
As a workaround, you can handle the token request yourself.
onReturn={async (data) => { console.log(JSON.stringify(data)); getToken(data.code).then(function(result) { console.log(result); try { settingsStorage.setItem('access_token', result.access_token); settingsStorage.setItem('refresh_token', result.refresh_token); settingsStorage.setItem('genDateToken', new Date().toISOString()); } catch(err) { console.log('Storage err: '+ err); } }).catch(function(err){ console.log('Err: '+ err); }) }}
async function getToken(exchangeCode) { const urlEncodePost = function (object) { let fBody = []; for (let prop in object) { let key = encodeURIComponent(prop); let value = encodeURIComponent(object[prop]); fBody.push(key + "=" + value); } fBody = fBody.join("&"); return fBody; };
// https://dev.fitbit.com/reference/web-api/oauth2/#authorization-header const Token_Body = { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic XXXXXX' }, body: urlEncodePost({ grant_type: 'authorization_code', client_id: "xxxxxx", client_secret: "xxxxxx", code: exchangeCode, redirect_uri:'https://app-settings.fitbitdevelopercontent.com/simple-redirect.html', }) }; return await fetch('xxxxxxxx', Token_Body) .then(function(data){ return data.json(); }).catch(function(err) { console.log('Err on token gen '+ err); }) }
11-28-2017 08:47 - edited 11-28-2017 09:35
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

11-28-2017 08:47 - edited 11-28-2017 09:35
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
- Who Voted for this post?
I found the answer here
https://dev.fitbit.com/reference/settings-api/#oauth-button
https://dev.fitbit.com/reference/settings-api/#strava-login-button
I'll do some experiments and I'll let you know my findings
11-28-2017 14:30
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post


11-28-2017 14:30
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
There is also a sample app which shows how to use OAuth. https://github.com/Fitbit/sdk-oauth

11-30-2017 05:29
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

11-30-2017 05:29
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
I am able to perform the login operation for 3rd party web API using OAuth button but it does not work properly every time.
Sometimes it works as expected, storing inside the setting key the access token.
Sometimes it fails.
I've attached the onAccessToken callback to OAuth button
onAccessToken={async (data) => {
console.log(data);
}}
and when the token retrieving fails, it logs the following error
{ error = "invalid_grant"; "error_description" = "Invalid authorization code"; }
Investigating server side on this issue we found that after the retrieving of authorization code (from authorizeUrl) the fitbit app calls 2 times the token exchange request using requestTokenUrl.
It looks pretty strange because my expectation is to receive just one token exchange request.
I see the following pattern:
if the first request has success and the second has failure then the token is retrieved properly.
if the first request has failure and the second has success then the token is not retrieved and I see the "invalid_grant" error.

11-30-2017 06:50
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

11-30-2017 06:50
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
I can confirm the invalid grant behavior in my app. It makes refreshing tokens very precarious. The occasional double-call would explain why it's been difficult to diagnose.
Can you elaborate as to what "investigating server side" means?

11-30-2017 06:56 - edited 11-30-2017 07:20
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

11-30-2017 06:56 - edited 11-30-2017 07:20
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Fortunately I have access to the Auth0 service that it is handling the authentication request.
Taking a look at the Auth0 logs, I have found the double requests.
This problem is present only on iOS. I have just tried on Android and the authentication is working fine and I see only one token exchange request on Auth0 logs (as expected).
It looks definitely like a fitbit app for iOS bug.

12-07-2017 12:02
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post


12-07-2017 12:02
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
- Who Voted for this post?
As a workaround, you can handle the token request yourself.
onReturn={async (data) => { console.log(JSON.stringify(data)); getToken(data.code).then(function(result) { console.log(result); try { settingsStorage.setItem('access_token', result.access_token); settingsStorage.setItem('refresh_token', result.refresh_token); settingsStorage.setItem('genDateToken', new Date().toISOString()); } catch(err) { console.log('Storage err: '+ err); } }).catch(function(err){ console.log('Err: '+ err); }) }}
async function getToken(exchangeCode) { const urlEncodePost = function (object) { let fBody = []; for (let prop in object) { let key = encodeURIComponent(prop); let value = encodeURIComponent(object[prop]); fBody.push(key + "=" + value); } fBody = fBody.join("&"); return fBody; };
// https://dev.fitbit.com/reference/web-api/oauth2/#authorization-header const Token_Body = { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic XXXXXX' }, body: urlEncodePost({ grant_type: 'authorization_code', client_id: "xxxxxx", client_secret: "xxxxxx", code: exchangeCode, redirect_uri:'https://app-settings.fitbitdevelopercontent.com/simple-redirect.html', }) }; return await fetch('xxxxxxxx', Token_Body) .then(function(data){ return data.json(); }).catch(function(err) { console.log('Err on token gen '+ err); }) }
02-24-2018 04:19
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

02-24-2018 04:19
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Has this issue been resolved yet?

03-29-2018 18:11
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

03-29-2018 18:11
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Hello there,
I have same issue. I haven't been able to get redirected back to settings page on clockface app on fitbit app on redirection from a third party oauth2 provider. It always redirects to "
https://app-settings.fitbitdevelopercontent.com/simple-redirect.html" but am not getting control back to the Fitbit app setting page. I am using Fitbit provided oauth button from Setting API. Please help. thank you
<Oauth
settingsKey="oauth"
align="center"
title="Login"
status="Login"
authorizeUrl="https://sandbox-api.example.com/v1/oauth2/login"
requestTokenUrl="https://sandbox-api.example.com/v1/oauth2/token"
response_type="code"
clientId="<removed>"
clientSecret="<removed>"
grant_type="authorization_code"
scope="offline_access"
state="Test by Sri"
/>

