API/URL to check valid authentication token

Hello everyone,

I was looking at the documentation to find some more information about how the authentication mechanism works.
To me it seems it is purely JavaScript based which is a little sad. I was hoping to find a URI somewhere which people can directly access after authenticating and where the authentication bearer will automatically be sent to. That URI should then respond with the respective HTTP code 2xx or 4xx.

The use case I have in mind to re-use existing authentication together with NGINX reverse proxy and it’s auth_request option for conditional forwarding to backend servers.

Can somebody say if such URI exists already somewhere in HASS or whether this might be considered for implementation as a feature request?

Many thanks,
Julian

1 Like

Cant verify atm but i believe /api/info wont respond without valid token.

Any solution on this topic? I’m trying to run without supervised install and trying to add some more features as iframe panels that run on behind nginx proxy on sub-path. But I would like to reuse authentication from home assistant using exactly this subrequest nginx feature.

1 Like

I’m also interested in using nginx’s auth_request module for implementing internal webservices in has using iframe panels.
Is there a subpage which responds with http 200 if a user is authenticated or with 4xx if the user is unauthenticated?

thank you!

1 Like

Eventually I found https://github.com/vouch/vouch-proxy that’s supposed to have support for Home Assistant auth and serve as auth_request provider for nginx. Once I get the config right I’m posting updates.

Just to understand this. So let’s say I have a docker install of HA, will I be able to display the UI of another docker component - say zigbee just like what supervised does with add-ons?

exactly!
if webview has the ability to pass user‘s current bearer token, nginx would be able to pass this token to ha’s rest api using auth module to check validity of these tokens.
I can also provide a nginx example config if nessecary.

@oeiber Yes please, that will be great. This will be great so that we could experience Supervised like frontend in Docker without the complexity

Here you are :wink:
Hope it helps:

      location / {
                set $bearer $arg_access_token; # has delivers a valid token within the url (?access_token=xxxxxxxxx), this can also be done using a request header
                auth_request /auth; # redirects authentication request to internal page
                proxy_pass http://webserver:80; #passes request to backend if authenticated
        }
        location /auth {
                proxy_pass http://homeassistant:8123/api/; #has api which delivers a http status: 200: authenticated, 40x: forbidden
                proxy_pass_request_body off; #nginx doesn‘t take care about the request body, because only the http status is nessecary
                proxy_set_header Content-Length "";
                proxy_set_header Authorization "Bearer $bearer";  #delivers the access_token from above to has api as described in api documentation
                internal; #page can only be accessd inernaly from nginx
        }

Sounds really good - I’ll give it a try!

Does that work for you? I’m getting Failed login attempt from Home Assistant Log and I don’t see any access token in URL.
I’ve added it this way:

server {
    server_name nuc.local;
    listen 80 default_server;

    location /esphome/ {
      set $bearer $arg_access_token; # has delivers a valid token within the url (?access_token=xxxxxxxxx), this can also be done using a request header
      auth_request /auth-check; # redirects authentication request to internal page
      
      proxy_pass http://localhost:6052;
      rewrite ^/esphome/(.*)$ /$1 break;

      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
    }

    location /auth-check {
      proxy_pass http://localhost:8123/api/; #has api which delivers a http status: 200: authenticated, 40x: forbidden
      proxy_pass_request_body off; #nginx doesn‘t take care about the request body, because only the http status is nessecary
      proxy_set_header Content-Length "";
      proxy_set_header Authorization "Bearer $bearer";  #delivers the access_token from above to has api as described in api documentation
      internal; #page can only be accessd inernaly from nginx
    }

    location / {
      proxy_pass http://localhost:8123;
      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
    }
  }

jepp, it‘s working. did you also provide a longe lived acces token in the url? e.g https://my.page.tld/?access_token=xxxxxxxx

Here’s a new NGINX config which works very well for my purposes:

proxy_cache_path /var/cache/nginx/homeassistant_ingress keys_zone=homeassistant_ingress:1m max_size=2m; # cache for access tokens

map $http_upgrade $connection_upgrade { # handles websocket request to has backend
        default upgrade;
        '' close;
}

server {
	include snippets/server.conf;
    include snippets/ssl.conf;

	listen 443 ssl http2;
        server_name myhass.domain.tld;

        set $homeassistant 'http://homeassistant:8123'; # homeassistant backend

        location  ~ '^/ingress/app1/(?<bearer>[^/]+)' { # Adds a subdir in the format https://myhass.domain.tld/ingress/app1/longlivedaccesstoken-from-has/ and extracts the access token to variable bearer
                set $ingress 'http://192.168.1.14:80'; # Proxy backend
                proxy_set_header Authorization "Basic xxxxxxxxxxxxxxxxxx"; # Adds basic auth to proxy backend, if needed
                rewrite ^/ingress/[^/]+/[^/]+(/.*)$ $1 break; # rewrites /ingress/app1/token to /
                auth_request /ingress/authorize; # validate has access token
                proxy_pass $ingress; # proxy pass to backend
        }
 
        location  ~ '^/ingress/zwave/(?<bearer>[^/]+)' { # Adds a subdir in the format https://myhass.domain.tld/ingress/zwave/longlivedaccesstoken-from-has/ and extracts the access token to variable bearer
                set $ingress 'http://zwave:8091'; # zwave2mqtt backend
                proxy_set_header X-External-Path $request_uri; # required for zwave2mqtt - see manual on github
                rewrite ^/ingress/[^/]+/[^/]+(/.*)$ $1 break; # rewrites /ingress/zwave/token to /
                auth_request /ingress/authorize; # validate has access token
                proxy_pass $ingress; # proxy pass to backend
        }

        location ~ '^/ingress/authorize$' { # checks access token using has api
                proxy_pass_request_body off; # disable body, because not needed
                proxy_set_header Content-Length "";
                proxy_set_header Authorization "Bearer $bearer"; # adds bearer token from above (has long lived access token) to the request
                proxy_cache homeassistant_ingress; # name of proxy cache (1st line)
                proxy_cache_key $bearer; # item to cache
                proxy_cache_valid 200 60s; # caches successful checked tokens for 1 minute. so we dont't have to call has api for every request
                proxy_ignore_headers Cache-Control Expires Set-Cookie; # ignores cache header. required for caching the token
                internal; # makes site not accessable form external
                proxy_pass $homeassistant/api/; # proxy pass to hass api
        }

        location ~ '^/' { # location for has webinterface
                include snippets/proxy.conf;
                proxy_pass $homeassistant;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection $connection_upgrade;
        }

So after you got a long lived access token from has, you can add a iframe panel to lovelace ui with the following url: /ingress/zwave/39q48pzm59t8qg34938434pq83z3485 mz239453485435/
asuming your token is 39q48pzm59t8qg34938434pq83z3485 mz239453485435
Please notice the slash after the access token.

for futher questions feel free to ask me :wink:

1 Like

Hi! Trying to adjust your example in my HA environment. What kind of configuration are in the snippets/proxy.conf file?

Hi!
Here’s the content of proxy.conf file:

proxy_http_version 1.1;
proxy_buffering off;
proxy_intercept_errors on;
proxy_connect_timeout 1h;
proxy_send_timeout 1h;
proxy_read_timeout 1h;

proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Scheme $scheme;

Thanks. But unfortunately I have only white empty page within iframe. I have no idea how to get it to work. Nginx logs shows the follofing (url and token are changed):

192.168.20.128 - - [24/Jul/2021:21:16:55 +0300] "GET /ingress/frigate/EyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1Nij9.eyJpc3MiOiIyZGNiNWUyOWM0YzU0NGYzYmQ5Y2QwNzQ5ZmJhNWVmNCIsImlhdCI6MTYyNTM0NDAyNiwiZXhwIjoxOTQwNzA0MDI2fQ.9Y6anAL7PL-HduLMsgmxPWFQ3reSfuh0m1J96-NOLDH/ HTTP/2.0" 200 1087 "https://hassio.my.host.org:1444/frigate"
192.168.20.128 - - [24/Jul/2021:21:16:55 +0300] "GET /ingress/frigate/EyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1Nij9.eyJpc3MiOiIyZGNiNWUyOWM0YzU0NGYzYmQ5Y2QwNzQ5ZmJhNWVmNCIsImlhdCI6MTYyNTM0NDAyNiwiZXhwIjoxOTQwNzA0MDI2fQ.9Y6anAL7PL-HduLMsgmxPWFQ3reSfuh0m1J96-NOLDH/extjs.html HTTP/2.0" 200 1087 "https://hassio.my.host.org:1444/frigate"
192.168.20.128 - - [24/Jul/2021:21:16:55 +0300] "GET /ingress/frigate/EyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1Nij9.eyJpc3MiOiIyZGNiNWUyOWM0YzU0NGYzYmQ5Y2QwNzQ5ZmJhNWVmNCIsImlhdCI6MTYyNTM0NDAyNiwiZXhwIjoxOTQwNzA0MDI2fQ.9Y6anAL7PL-HduLMsgmxPWFQ3reSfuh0m1J96-NOLDH/redir/theme.css HTTP/2.0" 404 599 "https://hassio.my.host.org:1444/ingress/frigate/EyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1Nij9.eyJpc3MiOiIyZGNiNWUyOWM0YzU0NGYzYmQ5Y2QwNzQ5ZmJhNWVmNCIsImlhdCI6MTYyNTM0NDAyNiwiZXhwIjoxOTQwNzA0MDI2fQ.9Y6anAL7PL-HduLMsgmxPWFQ3reSfuh0m1J96-NOLDH/extjs.html"
192.168.20.128 - - [24/Jul/2021:21:16:55 +0300] "GET /ingress/frigate/EyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1Nij9.eyJpc3MiOiIyZGNiNWUyOWM0YzU0NGYzYmQ5Y2QwNzQ5ZmJhNWVmNCIsImlhdCI6MTYyNTM0NDAyNiwiZXhwIjoxOTQwNzA0MDI2fQ.9Y6anAL7PL-HduLMsgmxPWFQ3reSfuh0m1J96-NOLDH/redir/locale.js HTTP/2.0" 404 599 "https://hassio.my.host.org:1444/ingress/frigate/EyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1Nij9.eyJpc3MiOiIyZGNiNWUyOWM0YzU0NGYzYmQ5Y2QwNzQ5ZmJhNWVmNCIsImlhdCI6MTYyNTM0NDAyNiwiZXhwIjoxOTQwNzA0MDI2fQ.9Y6anAL7PL-HduLMsgmxPWFQ3reSfuh0m1J96-NOLDH/extjs.html"
192.168.20.128 - - [24/Jul/2021:21:16:55 +0300] "GET /static/tvh.blue.css.gz HTTP/2.0" 404 14 "https://hassio.my.host.org:1444/ingress/frigate/EyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1Nij9.eyJpc3MiOiIyZGNiNWUyOWM0YzU0NGYzYmQ5Y2QwNzQ5ZmJhNWVmNCIsImlhdCI6MTYyNTM0NDAyNiwiZXhwIjoxOTQwNzA0MDI2fQ.9Y6anAL7PL-HduLMsgmxPWFQ3reSfuh0m1J96-NOLDH/redir/theme.css"
192.168.20.128 - - [24/Jul/2021:21:16:57 +0300] "GET /service_worker.js HTTP/2.0" 304 0 "https://hassio.my.host.org:1444/service_worker.js"

It would be great to allow to check current users access_token instead of having to create long lived ones, so cancelling user would not pose a rick of user being aware of those long living authenticated URLs :frowning: