Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SUPERVISOR_TOKEN for addon websocket connection isn't working #5028

Open
dneprojects opened this issue Apr 19, 2024 · 10 comments
Open

SUPERVISOR_TOKEN for addon websocket connection isn't working #5028

dneprojects opened this issue Apr 19, 2024 · 10 comments
Labels

Comments

@dneprojects
Copy link

Describe the issue you are experiencing

I have an addon written in Python code, which opens a websocket connection to HA in order to call a service.
In the addon I get the token by the command 'os.getenv("SUPERVISOR_TOKEN")'.
With that token I connect: 'websockets.connect("ws://supervisor/core/websocket",extra_headers={"Authorization": f"Bearer {bearer_token}"}' .
In the next strep, the server sends a message '{"type":"auth_required","ha_version":"2024.4.3"}',
my addon responds with '{"type": "auth", "access_token": "788dba363765f...184e6f8c21acc2415dc43"}' with the SUPERVISOR_TOKEN.
The server replys '{"type":"auth_invalid","message":"Invalid access"}' and closes the connection.

I think, the procedure is OK, but the token is wrong. There are more strange things:

  1. If I run exactly that code in an addon which has been generated internally from the local folder /addons/<slug_name>, it runs fine.
  2. I have two Raspis, a Raspi 4B and a Raspi 5. On the 4B the code runs, if I pick the SUPERVISOR_TOKEN from the terminal addon with a 'printenv SUPERVISOR_TOKEN' and use that instead of the environment variable got inside of the addon.
    On the Pi 5 this workaround does not help.

It seems as if the internal handling of the tokens is out of order...

What type of installation are you running?

Home Assistant OS

Which operating system are you running on?

Home Assistant Operating System

Steps to reproduce the issue

  1. In the addon:
    'supervisor_token = os.getenv("SUPERVISOR_TOKEN")'
  2. 'websockets.connect("ws://supervisor/core/websocket",extra_headers={"Authorization": f"Bearer {supervisor_token }"}'
  3. 'self.websck.send(json.dumps({"type": "auth", "access_token": supervisor_token}))
    ...

Anything in the Supervisor logs that might be useful for us?

2024-04-19 12:35:25.626 INFO (MainThread) [supervisor.api.proxy] Home Assistant WebSocket API request initialize
2024-04-19 12:35:25.630 WARNING (MainThread) [supervisor.api.proxy] Unauthorized WebSocket access!

System Health information

This is taken from my addon logs:
2024-04-19 12:38:52 DEBUG websockets.client: = connection is CONNECTING
2024-04-19 12:38:52 DEBUG websockets.client: > GET /core/websocket HTTP/1.1
2024-04-19 12:38:52 DEBUG websockets.client: > Host: supervisor
2024-04-19 12:38:52 DEBUG websockets.client: > Upgrade: websocket
2024-04-19 12:38:52 DEBUG websockets.client: > Connection: Upgrade
2024-04-19 12:38:52 DEBUG websockets.client: > Sec-WebSocket-Key: 6mWZuuqIfqnVlzrBMRem3Q==
2024-04-19 12:38:52 DEBUG websockets.client: > Sec-WebSocket-Version: 13
2024-04-19 12:38:52 DEBUG websockets.client: > Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
2024-04-19 12:38:52 DEBUG websockets.client: > Authorization: Bearer 80b41982adf8b6d08d983120a4445d11bec099e5e6f0d3c1e4789d6808eea627daf952ad03789680e1fa24faf77abcadf62191922a3bff5a
2024-04-19 12:38:52 DEBUG websockets.client: > User-Agent: Python/3.11 websockets/12.0
2024-04-19 12:38:52 DEBUG websockets.client: < HTTP/1.1 101 Switching Protocols
2024-04-19 12:38:52 DEBUG websockets.client: < Upgrade: websocket
2024-04-19 12:38:52 DEBUG websockets.client: < Connection: upgrade
2024-04-19 12:38:52 DEBUG websockets.client: < Sec-WebSocket-Accept: +F5BKQQ50hTwu+2j0ImYx4iKQ+M=
2024-04-19 12:38:52 DEBUG websockets.client: < Sec-WebSocket-Extensions: permessage-deflate
2024-04-19 12:38:52 DEBUG websockets.client: < Date: Fri, 19 Apr 2024 10:38:52 GMT
2024-04-19 12:38:52 DEBUG websockets.client: < Server: Python/3.12 aiohttp/3.9.3
2024-04-19 12:38:52 DEBUG websockets.client: = connection is OPEN
2024-04-19 12:38:52 DEBUG websockets.client: < TEXT '{"type":"auth_required","ha_version":"2024.4.3"}' [48 bytes]
2024-04-19 12:38:52 DEBUG websockets.client: > TEXT '{"type": "auth", "access_token": "80b41982adf8b...abcadf62191922a3bff5a"}' [148 bytes]
2024-04-19 12:38:52 DEBUG websockets.client: < TEXT '{"type":"auth_invalid","message":"Invalid access"}' [50 bytes]
2024-04-19 12:38:52 DEBUG websockets.client: < CLOSE 1000 (OK) [2 bytes]
2024-04-19 12:38:52 DEBUG websockets.client: = connection is CLOSING
2024-04-19 12:38:52 DEBUG websockets.client: > CLOSE 1000 (OK) [2 bytes]
2024-04-19 12:38:52 DEBUG websockets.client: = connection is CLOSED

Supervisor diagnostics

config_entry-hassio-393b944bf81b49e9dbad4d65c5ee4e8f.json

Additional information

HA Core 2024.4.3, HA Supervisor 2024.04.0, HAOS 12.2

@dneprojects
Copy link
Author

I found the reason for my "strange things no 2": On the Pi5 I used the "Terminal and SSH" addon, on the Pi4 the "Advanced SSH and Web Terminal" addon. I switched to the latter on my Pi5 and got the working token typing 'printenv SUPERVISOR_TOKEN'.

However, the behavior is weird. Under which circumstance supervisor tokens are generated?

@dneprojects dneprojects changed the title SUPERVISOR_TOKEN for addon websocket connection SUPERVISOR_TOKEN for addon websocket connection isn't working Apr 19, 2024
@SilverBrother
Copy link

I can't seem to replicate your error, how exactly have you implemented the method for websocket connections?

@dneprojects
Copy link
Author

dneprojects commented Apr 23, 2024 via email

@dneprojects
Copy link
Author

dneprojects commented Apr 23, 2024 via email

@grahamj
Copy link

grahamj commented May 5, 2024

I'm seeing this too:

config.yaml:

name: blah
version: 0.0.12
slug: blah
description: blah
arch:
- amd64
url: blah
map:
- config:rw
init: false
homeassistant_api: true

Dockerfile:

ARG BUILD_FROM
FROM $BUILD_FROM
WORKDIR /opt/addon/
COPY run.sh ./
CMD ["./run.sh"]

run.sh:

echo "Token: $SUPERVISOR_TOKEN"

Log:

System: Home Assistant OS 12.2  (amd64 / qemux86-64)
 Home Assistant Core: 2024.4.4
 Home Assistant Supervisor: 2024.04.4
-----------------------------------------------------------
 Please, share the above information when looking for help
 or support in, e.g., GitHub, forums or the Discord chat.
-----------------------------------------------------------
s6-rc: info: service base-addon-banner successfully started
s6-rc: info: service fix-attrs: starting
s6-rc: info: service base-addon-log-level: starting
s6-rc: info: service fix-attrs successfully started
s6-rc: info: service base-addon-log-level successfully started
s6-rc: info: service legacy-cont-init: starting
s6-rc: info: service legacy-cont-init successfully started
s6-rc: info: service legacy-services: starting
s6-rc: info: service legacy-services successfully started
Token: 

@grahamj
Copy link

grahamj commented May 6, 2024

I've spent the better part of today trying to get this working. 31 tries in and still no dice. I've tried every relevant config.yaml option, older base images, rebooting, you name it. No matter what I do I never see this env var in my container.

I have the ssh addon and I can echo the token there so other addons seem to get it, I just can't figure out why I don't. The main difference is mine is local in /addons but not sure why that would matter. It shows up in the UI, updating version in config.yaml and looking for updates in the UI shows it, it installs and runs fine, everything seems normal. But no token.

Interestingly, when I grab the token from the ssh addon and use it in my code to connect to websockets I get an auth_invalid response. Had to resort to using a long-lived as a workaround for now.

/sad panda

@dneprojects
Copy link
Author

dneprojects commented May 6, 2024 via email

@grahamj
Copy link

grahamj commented May 8, 2024

Hi First, you need to add the line hassio_api: true to your config.yaml. I'm not sure whether this is needed in your case. In order to get access to the token inside the container, the first line in the shell script should be #!/usr/bin/with-contenv sh I hope this helps... Best wishes, Dietmar

OMG the shebang worked, thank you so much! I had it in there at one point before but something else must have been wrong.

Wow the docs really need to make more clear how critical that is!

@dneprojects
Copy link
Author

You are right, the documentation is really bad!

I faced another problem after I solved that one you had. The code seems to be very sensitive to timings:

self.websck = await websockets.connect(
    self._uri,
    extra_headers={"Authorization": f"Bearer {auth_token}"},
    open_timeout=4,
)

await asyncio.sleep(1)  # needed, otherwise the following auth fails
resp = await self.websck.recv()

if json.loads(resp)["type"] == "auth_required":
  await self.websck.send(json.dumps({"type": "auth", "access_token": auth_token}))

I don't understand, why, but if I used the supervisor_token from the "Advanced SSH & Web terminal"-addon, the code worked without the delay and also with a timeout of 1s. The timeout value was also dependent on the type of Raspi I was using: on a Pi4 I succeeded with 2s, on a Pi5 I needed 3s.

This is why I feel, the code must be buggy!

@grahamj
Copy link

grahamj commented May 8, 2024

yeah you should not need to sleep for sure. My Python is pretty rusty (my addon is actually a shim to write automations in nodejs!) but I can tell you that in Node I don't have any issues connecting to websockets 🤷‍♂️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants