peter-murray / node-hue-api

Node.js Library for interacting with the Philips Hue Bridge and Lights
Apache License 2.0
1.18k stars 145 forks source link

504 Error When Attempting To Make Remote API Calls #187

Closed brokyo closed 3 years ago

brokyo commented 3 years ago

Hi there. Thanks for the library, it has helped me build some really cool stuff and I appreciate all the work you've put in.

However, I'm attempting to connect remotely for the first time and I just can't get things to work, despite pretty directly following the docs. Filing this here on the off-chance this is the library rather than the user.


Goal: Connect to a Hue Bridge via connectWithTokens() and make an API call Problem: Every API request returns a 504 error, even after a seemingly successful connectWithTokens() connection using just-generated credentials. Context: The Hue error docs and this tweet make me think a 504 error is the result of a bridge being not being connected to the internet. My understanding is that connectWithCode() only works if a connection to the bridge has been established.

As a further complication: I checked locally and I can see that no user associated with my new app which makes me think I'm missing something?


Flow That I Would Expect To Work

  1. Send visitor to authorization URL created via getAuthCodeUrl()

    const remoteBootstrap = hue_api.api.createRemote(CLIENT_ID, CLIENT_SECRET);
    document.location.href = remoteBootstrap.getAuthCodeUrl('my-app', APP_ID, STATE)
  2. In node catch callback from above URL and use it to connect to bridge via connectWithCode()

    const remoteBootstrap = hue_api.api.createRemote(CLIENT_ID, CLIENT_SECRET);
    remoteBootstrap.connectWithCode(authCode, USERNAME)
    .catch(err => {
         // Error stuff
  3. Then swap code for refresh and access tokens from bridge via getRemoteAccessCredentials()

      }).then(api => {
        const remoteCredentials = api.remote.getRemoteAccessCredentials();
        // Store remoteCredentials.tokens
    
        res.redirect(`app.com`)
     })
  4. Use those tokens to do anything you might with the local API via connectWithTokens()

    const remoteBootstrap = hue_api.api.createRemote(CLIENT_ID, CLIENT_SECRET);
    remoteBootstrap.connectWithTokens(ACCESS_VALUE, REFRESH_VALUE, USERNAME)
    .catch(err => {
     // Error stuff
    })
    .then(api => {
    // **This times out** 
    api.lights.getAll()
    .then(allLights => {
      // do something with allLights
    }
    })

    The first three steps are no problem but working with the API in step 4 results in an error every time :/

Anything I'm overlooking? Am I misinterpreting remoteSetup.md?

peter-murray commented 3 years ago

Which version of the library are you using? The details above all look correct.

The example flow in the https://github.com/peter-murray/node-hue-api/blob/main/examples/v3/remote/accessFromScratch.js used to work, but I have not re-tested this recently.

I am taking a look into this under the new TypeScript re-write in the next couple of days, as I have not completed that aspect of the work there yet.

brokyo commented 3 years ago

I'm using 4.0.8

I've reviewed a couple of times with fresh eyes and I can't find any obvious flaw, so maybe something changed? If I can be helpful please let me know and thanks for taking a look.

peter-murray commented 3 years ago

It looks like something has changed somewhere (its been over a year since I last tested this). Now that I know the version I can puts some debugging time into it tomorrow 😄

peter-murray commented 3 years ago

I just ran a test using 4.0.8 tag on the repository and the example remote workflow mentioned above, it generated the URL and once I got the code from that response, happily exchanged it for a new token and provided access.

My bridge on my network is set up and connected to the Hue portal though, which as you highlighted is a requirement in the linked Twitter post.

brokyo commented 3 years ago

Embarrassing! Yes, you're absolutely right and my bridge was not connected to the portal and that was the source of the issue (I changed routers, didn't reconnect, and the site gives unclear messaging 😰) this all works now. Thank you and, oof, apologies.


While reimplementing this I may have found a different bug, however. I'm not convinced passing a custom username to connectWithCode works

To Reproduce

Failed Process After getting auth code connect with:

const username = `foo`
remoteBootstrap.connectWithCode(authCode, username)
.then(api => {
   const remoteCredentials = api.remote.getRemoteAccessCredentials();
   // save username as `customUser`
   // save remoteCredentials.tokens as `tokens`
})

Then connect on an arbitrary API call:

remoteBootsrap.connectWithTokens(tokens.access.value, tokens.refresh.value, customUser)
.then(api => {
   api.lights.getAll()
   .then(lights => {
      // fail to do something with allLights
   })
})

When I do this I get ApiError: unauthorized user

Successful Process Whereas if I do the entire above process without passing in a username things work:

remoteBootstrap.connectWithCode(authCode)
.then(api => {
   const remoteCredentials = api.remote.getRemoteAccessCredentials();
   // save remoteCredentials.username as `defaultUser`
   // save remoteCredentials.tokens as `tokens`
})

remoteBootsrap.connectWithTokens(tokens.access.value, tokens.refresh.value, defaultUser)
.then(api => {
   api.lights.getAll()
   .then(lights => {
      // successfully do something with allLights
   })
})

It's possible I'm missing something here but as I have no reason not to just use a default user haven't dug too deep. Failed on a couple pass throughs so I thought I'd flag it :)

Thank you!