11-26-2018 01:09
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

11-26-2018 01:09
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Hello,
I'm trying to write an app that runs on the Ionic (+ companion) and connects to the SmartThings web service. I followed the FitBit App OAuth example here, with a SmartThings Client ID and Client Secret generated as described here. I'm running the app in the simulator and getting the following error:
"Failed to load https://graph.api.smartthings.com/oauth/token: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://app-settings.fitbitdevelopercontent.com' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled."
Also, my settingsStorage.onchange handler never gets called, presumably due to the error above.
The odd thing is, if I run Fiddler while the simulator is making its calls, it looks like the call to graph.api.smartthings.com goes through fine (returns 200 OK), and even returns a proper bearer token. This is a valid bearer token, as I can use it in the Fiddler Composer to make successful calls to the SmartThings web service.
I have two resulting questions:
1. Which call results in the error reported in the simulator? Everything seems fine on the wire...
2. How do I fix the error and get the bearer token in the companion app, ready for subsequent calls?
Thanks for the help!
Cheers,
~alex
Answered! Go to the Best Answer.

Accepted Solutions
11-26-2018 14:06
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post


11-26-2018 14:06
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
It's a CORS issue with the settings page. The only way to do this would be to use the <WebConfig> component and handle the token request manually. This isn't really documented, but you should find examples on Discord.

11-26-2018 14:06
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post


11-26-2018 14:06
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
It's a CORS issue with the settings page. The only way to do this would be to use the <WebConfig> component and handle the token request manually. This isn't really documented, but you should find examples on Discord.

11-27-2018 12:09
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

11-27-2018 12:09
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
- Who Voted for this post?
Wow, that worked like a charm... Thank you, @JonFitbit!
The gist of the solution, for reference:
1. Use the onReturn functionality of the OAuth component to persist the authorization response, including the short-lived OAuth code.
2. In the companion app, listen to storage events. When the persisted information from 1 (above), shows up, manually call the token endpoint of the OAuth WebApp to exchange the code for an actual token (for an example of how to do this, see the ExchangeToken function below, suggested by @JonFitbit). Then, store the token and use it as you see fit (likely an "Authorization: Bearer <token>" header on outgoing calls)
3. Enjoy the benefits of securely authenticated REST calls.
async function tokenRequest(body) { body += `&client_id=${oauthConfig.clientId}&client_secret=${oauthConfig.clientSecret}`; const response = await fetch( oauthConfig.requestTokenUrl, { method: 'POST', body, headers: { 'content-type': 'application/x-www-form-urlencoded', } }, ); const tokenResponse = await response.json(); if (tokenResponse.error) throw new Error(tokenResponse.error_description); return tokenResponse; } async function exchangeToken({ code }) { settingsStorage.removeItem('oauthResponse'); const redirectUri = 'https://app-settings.fitbitdevelopercontent.com/simple-redirect.html'; const data = `grant_type=authorization_code&code=${code}&redirect_uri=${redirectUri}`; const tokens = await tokenRequest(data); settingsStorage.setItem('oauthTokens', JSON.stringify(tokens)); }
01-15-2022 01:19
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

01-15-2022 01:19
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Hello @Jon,
The solution above has been working great for my Fitbit to SmartThings integration. Unfortunately, without any code change (that is, I'm using the code above), I just started getting this error:
"Access to fetch at 'https://graph.api.smartthings.com/oauth/token' from origin 'https://app-settings.fitbitdevelopercontent.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled."
Any idea what might be going on? Thanks!
Cheers,
~alex

01-19-2022 21:30
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

01-19-2022 21:30
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
@JonFitbit, one more thing. It appears that the settingsStorage.onChange event no longer gets invoked when the OAuth code is fetched, which meant that I can't just take the code and exchange it for an OAuth token outside of the browser, and therefore impervious to CORS policies. Because of this, the previous workaround is unfortunately no longer an option. Any thoughts would be much appreciated. Thanks!

01-20-2022 07:27
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post


01-20-2022 07:27
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Do you know when this started happening? Is it the same on iOS or Android?

01-20-2022 09:26
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

01-20-2022 09:26
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
- Who Voted for this post?
Unfortunately, I'm not sure exactly when it started happening. I noticed it over the winter holidays (late December 2021, early January 2022). It happens when the companion runs on my Android phone or in the desktop-based simulator. FWIW, when I'm the simulator, I can run Fiddler and see the /token call coming back fine over the wire - it's the browser that then notices that the domain of the current page is not in the access-control-allow-origin header returned by the server and refuses to render or, in this case, hand over the data to the settings code. If I manually tamper with the call and add access-control-allow-origin: * to the return, the code runs as expected.
