galak / span-hacs

MIT License
16 stars 10 forks source link

Need to provide durable authentication #11

Open mbbush opened 1 year ago

mbbush commented 1 year ago

Greetings! I am a home assistant user and software developer who recently started working for Span. The local API is pretty far removed from my official job duties, but it's something I care about and am helping out with as I can find spare time.

Currently, this integration makes unauthenticated api calls, relying on the fact that you can disable auth using a "proof of proximity" bypass involving the door switch. We do not currently have plans to remove the proof of proximity bypass, but we are going to substantially reduce its duration (to something like 15 minutes) so that users don't have to choose between a local integration and a secured api.

Before we roll out an update that would break this and other community-driven integrations, we want to provide an alternative means of authentication, which you can also use on current production firmware. The big picture is:

  1. Disable authentication on the panel using the door switch.
  2. While authentication is disabled, create an authorization token for the integration.
  3. Use that token to authenticate and authorize all subsequent calls, which will no longer require the panel to be in an "unlocked" insecure state.

In more detail, the recommended auth flow which will create a secure, durable, 100% local connection to the panel is as follows:

  1. POST to /api/v1/auth/register with JSON body {"name": "home-assistant-UNIQUEID", "description": "Home Assistant Local Span Integration"}.
    • Use some unique value for UNIQUEID. Six random alphanumeric characters would be one reasonable choice. If the name conflicts with one that's already been created the request will fail.
  2. If the panel is currently "unlocked", you will get a 2xx response containing the "accessToken". If not, then prompt the user to open and close the door of the panel three times, once every two seconds, and then retry.
  3. Store the value from the "accessToken" property of the response object. It will be a long string. This is the token which should be included with all future requests.
  4. Send all future requests with the HTTP header "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c" (this is just a dummy example token)

If you have multiple span panels, you will need to repeat this process for each panel, as tokens are only accepted by the panel that generated them.

jeffkibuule commented 1 year ago

Hey @mbbush, I'm working on integrating your requested changes into a PR on my branch here, hopefully will fix it this week and users won't have to rely on disabling auth to reliably get data.

Note to others: the configure page isn't quite right for displaying the header. I also probably shouldn't be working in my main branch. Oops.

gdgib commented 1 year ago

Hey @jeffkibuule, take a look at https://github.com/gdgib/span-hacs/pull/4. @etmelvin was kind enough to open a PR that appears to have this. Would you mind taking a look at the code compared to yours and see if there are any gaps? I'll do the same, but obviously, I'm not the author on this PR, just the repo maintainer.

gdgib commented 1 year ago

Oh, and those changes are released in https://github.com/gdgib/span-hacs/releases/tag/v0.0.6, installation instructions are here: https://github.com/gdgib/span-hacs#installation

jeffkibuule commented 1 year ago

@gdgib I installed your branch and then got an error about an access token. I don't see a way to input it? That's what I was working on in my branch.

gdgib commented 1 year ago

@jeffkibuule if you haven't already, you may just need a quick reboot. I ran into a non-reproducible issue with this when changing between different distros and branches after testing other upstream repos.

jeffkibuule commented 1 year ago

I've started testing this, but it takes upwards of a week for the previous scheme based on local auth from pressing the door panel button 3 times to fail. I installed it on Saturday, I'll be able to say if it's resilient and maintains its connection then.