I developed a smart app for my personal use - controlling home automation routines and getting status of SmartThings-connected devices, from my programmable Fitbit wearable. It essentially consists of securely calling SmartApp-exposed APIs via REST, controlling ST-connected devices and reading their state via the ST graph, and returning state to the caller. It was written in Groovy, on the legacy platform at graph.api.smartthings.com, hence “classic” (probably more aptly called “legacy”).
Use the base URL and the token to formulate and invoke the REST endpoint with a JSON payload and receive results back.
Recently, step 1 started failing, because the /token endpoint’s Access-Control-Allow-Origin CORS header does not specify the domain to which the /authorize endpoint correctly performs the redirect (app-settings.fitbitdevelopercontent.com).
Right now, I’m trying to figure out if I can make a minimal change to get the system working again without a full rewrite of the app in the new infrastructure. In that context, my (rephrased) questions are:
Is it possible to fix the OAuth flow for the legacy platform to allow CORS for the registered redirect domain?
If not, can I use a PAT for my legacy platform smart app? Or are the PAT and OAuth2 authorization mechanisms reserved only for the new platform?
If the latter, then it sounds like I have no other choice than to rewrite the smart app in the new platform, which I’ll do at some point, but I’d prefer not to be forced into it right now. If so, it sounds like a PAT is the way to go, and I don’t need to bother with the OAuth2 exchange (initial fetch and refresh), since this is a 1-user (me) solution. Is that correct?
In case you cannot avoid using the Access-Control-Allow-Origin header, yes, the easy path would be editing the app on the fitbit side to point at the ST API endpoints and use the PAT for the authorization. This way, you wouldn’t need the OAuth flow to get Access Tokens anymore.
I used the PAT for the endpoint https://graph.api.smartthings.com/api/smartapps/endpoints and I didn’t get any information, only the one from the SmartApp (“API endpoint” and “API token” in the IDE simulator), eg. https://graph-na04-useast2.api.smartthings.com/api/smartapps/installations/appId.
The node JS example you posted would work because it’s not running in a browser. With CORS, the call succeeds over the wire, and even returns a valid token, as evidenced by a Fiddler trace. It’s the browser itself that performs the current domain enforcement against the Access-Control-Allow-Origin header.
" I used the PAT for the endpoint https://graph.api.smartthings.com/api/smartapps/endpoints and I didn’t get any information"
I can confirm I see the same thing on my side - an empty JSON. In the legacy API, without a location, I cannot interact with SmartApps (right?), so that seems like a dead-end.
“, only the one from the SmartApp.”
I’m not sure what “only the one from the SmartApp” means in this case. It looks like the suggestions to use the PAT to “Get devices (list)”, “Get a device status” and “Send commands to devices” only talk about the new ST APIs, not the legacy ones. Can you please confirm that’s the case, rather than me misunderstanding your explanation?
Overall, it looks like using the PAT with the legacy endpoints is not an option, so I started looking into using a full control PAT (granted all the scopes, for testing purposes) from the Fiddler composer:
Apologies for the confusion, what I meant was using the endpoint https://graph-na04-useast2.api.smartthings.com/api/smartapps/installations/appId with the Access Token provided by the SmartApp in the IDE.
About the endpoints, these are part of the SmartThings API, before, you had to expose the endpoints through a SmartApp so you could interact with it and now, the communication is more direct.
In the case of the device endpoint (list, status, and command), you’ll be able to interact with all the devices no matter they’re using a DTH, because it is not limited to “non-Groovy devices”.
It could be caused by this section, using Postman, I got this snippet of the request using HTTP:
GET /v1/devices HTTP/1.1
Authorization: Bearer PAT
This was very helpful in confirming my expectations.
Fiddler Composer and SmartThings don’t seem to play well together. I tried using curl instead, with the same parameters, and that worked as expected. Not sure whether the fault lies with Fiddler, with the SmartThings endpoints, or with a system in between the two.
My observations based on the curl invocations:
New APIs (api.smartthings.com) work with my (manually created) PAT
Old/Legacy APIs (graph.api.smartthings.com) work with my (manually fetched via the OAuth code exchange protocol) OAuth token
New APIs don’t work with the legacy OAuth token.
Old/Legacy APIs don’t work with the PAT.
Given that the Fitbit browser’s CORS protection is getting in the way of doing the code exchange and fetching a legacy OAuth token, I’ll have to move to the new APIs at some point.