OAuth2 callback for SmartApp

I need some pointers w.r.t. defining an OAuth2 callback in a SmartApp in order to connect to a web service:

Assuming the service uses Google OAuth2, the response callback can’t be dynamic. As for most authentication providers, the redirect URI must be known beforehand, so using an endpoint URL won’t work (it has the SmartApp installation id in the path).

Does SmartThings provide some sort of static callback that SmartApps can use to dispatch responses back to the dynamic endpoint?

Thanks!

That’s not how oath works. Your service should handle the callback, so it should point to your service web presence, where your client code receives the callback, saves the data, uses it to get the access token, etc.

There are many implementations of oauth clients out there, see http://oauth.net/2/ under client libraries

I should have made clear that this is for a SmartApp to authenticate with a service not the other way around. So, yes, I still need the app to provide some sort of authentication callback.

Take a look at the ecobee (connect) smartapp. It implements the OAUTH2 methods correctly using a round trip OATUH endpoint. Very cool.

Thanks @pstuart.

Unfortunately, the ‘Ecobee (Connect)’ app also uses a dynamic redirect URI for the authentication callback. Most OAuth2 authentication providers do not support that pattern anymore. The redirect URI must be constant and known ahead of time. I needs to be specified when registering the client id.

Specifically, ecobee uses this URI to redirect the callback: /api/token/${atomicState.accessToken}/smartapps/installations/${app.id}/swapToken. With that URI, at least the app installation id is dynamic, and cannot be known ahead of time.

I think the only way this could work is if SmartThings were to provide a constant callback URI. Most providers DO allow for passing some sort of state token through the redirect URI, and SmartThings could use this state for the constant callback to dispatch / redirect to the dynamic, app installation dependent callback:

So, /api/token/constantCallback?state=${app.id} (provided by SmartThings) could redirect to /api/token/.../smartapps/installations/${app.id}/dynamicCallback (implemented as app endpoint). Does that make sense?

+1

Same issue here.
I need to send a redirect_uri which cannots contains variable parts

Curious if anyone has a recommended solution to this problem. I am trying to get OAUTH setup with Insteon but it requires the same redirect URI to be sent in the AUTH call as well as the call to retrieve the token.

Is there still no solution to this? I’m having the same problem… The only solution I can think of is to set the redirect_uri to somewhere outside the SmartThings cloud and then use information from the state to redirect it back into the cloud.

@unixbeast just updated docs around this that should help: http://docs.smartthings.com/en/latest/cloud-and-lan-connected-device-types-developers-guide/building-cloud-connected-device-types/building-the-service-manager.html

1 Like

Thanks! Followed the tutorial and was able to get Oauth working for the Insteon Hub. Noticed when I install it on my mobile the embedded redirect works perfectly but if I try it on the ide/simulator it fails to redirect properly. Got around it by just outputting the link in the debug log and hitting it in a separate browser windows. The app in the simulator is then still able to answer the callback and receive the token just fine.

Wasn’t sure if this is just a limitation of the ide/simulator or if there is anything I can do to have it work in the ide.

I have also worked through the page you mentioned and found it very helpful.

A couple of slight points regarding the documentation that caused me a few headaches:

In the preferences section of the example the page name is ‘Credentials’….

preferences {
page(name: “Credentials”, title: “Sample Authentication”, content: “authPage”, nextPage: “sampleLoggedInPage”, install: false)

}

however in the authPage example the dynamicPage name is ‘auth’, it appears these names have to match.

return dynamicPage(name: “auth”, title: “Login”, nextPage: “”, uninstall: false) {

Also the refreshAuthToken() example is not complete as the ‘try’ requires a ‘catch’ and an extra ‘}’ is required.

catch(Exception e){
Log.error(e)

}
}

1 Like

Thanks @MightyJudge, tagging @unixbeast here since he knows more about this.