Reverse Proxy SSO Authentication using Caddy/caddy-security with a jwt cookie

Hi,

I wanted to reverse proxy a few of my internally reachable services and make them available through my publicly accessible HomeAssistant installation.
After looking at the available solutions I was not satisfied with any of them, here’s some of the solutions I evaluated and why I disliked them.

  • BasicAuth using user:password in the url
    :x: Doesn’t work in the Android/iOS App
    :x: Makes the login details available in cleartext in the url

  • Authelia
    :x: User Management Separate from HomeAssistant
    :x: No SSO
    :x: Doesn’t work in the Android/iOS App?

  • LDAP+Authelia+HomeAssistant LDAP+Some LDAP GUI
    :x: Very Complex
    :x: No True SSO (You’ll have to log in to Home Assistant AND Authelia separately)
    :x: Doesn’t work in the Android/iOS App?

  • Various other similar combination of solutions like Authentik/Keycloak/… all suffer from the same fundamental problems as Authelia

So I decided to create a custom_component which creates a jwt cookie on login and combine it with a reverse proxy supporting jwt auth. This ticks all of my requirements:

  • :white_check_mark: Works everywhere (including the iOS/Android apps)
  • :white_check_mark: True SSO
  • :white_check_mark: Users are managed in HomeAssistant
  • :white_check_mark: No cleartext login/passwords
  • :white_check_mark: Is easily extensible to new services
  • :white_check_mark: Reasonably safe

I’ve been running this setup for a few weeks now and haven’t had any hiccups.
“It just works”

Link to the compoment: GitHub - BigBoot/hass-jwt_cookie: Create JWT Cookies every time you log in to your HomeAssistant instance

So here’s the guide:

Set Up SSO using Caddy and jwt_cookie

Note: In the following guide my.home.assistant will be used for demonstrative purposes, replace this with your own domain.

What you will end up after following this guide

  • HomeAssistant reachable on my.home.assistant with automatic HTTPS certificates managed by Caddy
  • Internal services reachable on svc1.my.home.assistant etc.
  • Seamless SSO for HomeAssistant and services

Assumptions & Requirements

This guide assumes the following:

  • You do have access to manage the DNS entries for my.home.assistant (i.e. you own the domain)
  • You are using HassOS or Supervised (to install the caddy addon)
  • You already set up your DNS so my.home.assistants points to your HomeAssitant instance
  • You already set up your DNS so *.my.home.assistants points to your HomeAssitant instance
  • Your HomeAssistant is publicly reachable on Port 80 & 443
  • You already have HACS running

Note that none of those are hard requirements but for the sake of simplicity this is the only setup we will be looking at.

1. Install jwt_cookie:

  • Add the jwt_cookie HACS repository: https://github.com/BigBoot/hass-jwt_cookie
  • Install the jwt_cookie intergration in HACS

2. Install Caddy2

  • Add the Caddy2 addon repository: https://github.com/einschmidt/hassio-addons
  • Install the Caddy2 addon
  • Enable AutoStart & Watchdog for the Caddy2 addon
  • Configure the Caddy2 addon:
    set config_path to /config/Caddyfile
    set custom_binary_path to /config/caddy
  • Download Caddy with the caddy-security plugin and save it as /config/caddy

3. Configure Caddy, and HomeAssistant

  • Create the file /config/Caddyfile with the following content:
{
	security {
        # Set up a policy called homeassistant
		authorization policy homeassistant {
			set token sources cookie
			crypto key verify from file /config/jwt_cookie.pem
			set auth url https://my.home.assistant/auth/jwt_cookie
			crypto key token name jwt_access_token
			allow roles user
		}
	}
}

# reverse proxy to home assistant without authentication
my.home.assistant {
	reverse_proxy localhost:8123
}

# reverse proxy svc1 with enabled authentication
svc1.my.home.assistant {
	route {
		authorize with homeassistant
		reverse_proxy <your_local_service_ip/domain:port>
	}
}
  • Create or edit your /config/configuration.yaml:
http:
  use_x_forwarded_for: true
  trusted_proxies:
    - 127.0.0.1
    - ::1
  cors_allowed_origins:
    - https://my.home.assistant

jwt_cookie:
  domain: ".my.home.assistant"
  private_key_file: /config/jwt_cookie.key

4. Restart HomeAssistant

That’s it, everything should be working now, if something is not working as expected check your HomeAssistant and Caddy2 logs.

7 Likes