My question essentially boils down to this - is it possible to make oauth2 via a Google login work with Home Assistant please?
I would like to access my HA environment from the internet, but would prefer extra levels of authentication security. I don’t want to just expose the native login screen by itself, be it either HA (using the latest auth system in 0.77.3) or any other web-based app I have running on my internal network.
To accomplish this I have been using Bitly’s OAuth2_proxy as a Docker container, which essentially lets me use my Google Account to securely log in using two-factor authentication before then being passed to internal web app logins.
This works great for all my other web-based apps running in docker containers, only Home Assistant (and Portainer) won’t work with oauth2_proxy.
Does anyone know why please? Has anyone with a similar config managed to get this to work?
The detail behind my setup is as follows:
I have a docker container that runs Traefik as a reverse proxy for all my internal web apps (docker and non-docker) instead of using nginx. The beauty of Traefik is that it automatically handles the Let’s Encrypt https certification and automatic redirection to any new containers you set up. See here for setting up docker, and here for adding traefik.
I then wanted to add extra login security by using Oauth2, and found this guide useful for explaining how to integrate it with Traefik. However it wasn’t all that clear how to set up Google’s OAuth with a single Client ID, so my post here should help clarify things.
As you can see on that thread, the author suggests it’s a websocket issue, but based on this blog here it looks like we should be able to pass a custom header to HA via the proxy because it essentially says HA should work behind a proxy. If however it is ultimately down to websockets, is there any way around this? Are the devs aware of this? Is there any other way of using OAuth via Google for extra security?
As seen in the docker-compose code below, I have attempted to pass a custom header using traefik labels with no luck. If anyone can offer any insights or ideas to help make this work, I would be very much grateful.
docker-compose.yml
version: "3.6"
services:
traefik:
hostname: traefik
image: traefik:latest
container_name: traefik
restart: always
domainname: ${DOMAINNAME}
networks:
- default
- traefik_proxy
ports:
- "80:80"
- "443:443"
- "9011:8080"
environment:
- CLOUDFLARE_EMAIL=${CLOUDFLARE_EMAIL}
- CLOUDFLARE_API_KEY=${CLOUDFLARE_API_KEY}
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ${USERDIR}/docker/traefik:/etc/traefik
- ${USERDIR}/docker/shared:/shared
hass_proxy:
image: a5huynh/oauth2_proxy
env_file: ${USERDIR}/docker/env/master.env
hostname: hass_proxy
container_name: hass_proxy
restart: always
networks:
- traefik_proxy
labels:
- traefik.enable=true
- traefik.backend=hass_proxy
- traefik.frontend.rule=Host:hass.${DOMAINNAME}
- traefik.docker.network=traefik_proxy
- traefik.port=4180
- traefik.frontend.headers.SSLRedirect=true
- traefik.frontend.headers.STSSeconds=315360000
- traefik.frontend.headers.browserXSSFilter=true
- traefik.frontend.headers.contentTypeNosniff=true
- traefik.frontend.headers.forceSTSHeader=true
- traefik.frontend.headers.SSLHost=${DOMAINNAME}
- traefik.frontend.headers.STSIncludeSubdomains=true
- traefik.frontend.headers.STSPreload=true
- traefik.frontend.headers.frameDeny=true
- traefik.frontend.headers.customrequestheaders=x-ha-access:my_api_pass
volumes:
- ${USERDIR}/docker/oauth_proxy/authenticated-emails.txt:/authenticated-emails.txt
command: |
-cookie-secure=false
-upstream=http://my_internal_HA_ip:8123
-redirect-url=https://hass.${DOMAINNAME}
-http-address=http://0.0.0.0:4180
-provider=google
-authenticated-emails-file=/authenticated-emails.txt
-pass-host-header=true
-pass-user-headers=true
If anyone would still like to access HA behind a Traefik reverse proxy without Oauth, the following rules.toml file will redirect to wherever you have HA installed (see here)
rules.toml
[backends]
[backends.hass]
[backends.hass.servers.server2]
url = "http://my_internal_ha_ip:8123"
[frontends]
[frontends.hass]
backend = "hass"
passHostHeader = true
[frontends.hass.routes.routes1]
rule = "Host:hass.example.com"
Hope all that makes sense - reading those guides will help…