Skip to main content

What's public, and what needs signing in

The app is at /, each of its pages at its own address (/stats, /applications/2), and its data under /api: those need signing in. The rest needs nobody: signing in (/login), the health check (/healthz), the scripts, styles, fonts and logo, and a shared calendar's link. Addresses from when the app lived under /app (/app/companies/3) lead to the same page without it, and the website's pages hunt once served (/docs, /privacy, /terms, /data-deletion, /screenshots, and /ar/…) lead to them on the website (HUNT_SITE_URL, below).

There are three ways to sign in.

A password, for one person​

HUNT_PASSWORD='a long passphrase' hunt serve
docker run -e HUNT_PASSWORD='a long passphrase' -p 4848:4848 -v hunt-data:/data ghcr.io/arabesquelabs/hunt
  • The app and its data ask for it, at /login, and remember you for 30 days. The sidebar has Log out.
  • The CLI sends its own HUNT_PASSWORD: set it where you run hunt.
  • Changing it signs everyone out. It needs 8 characters or more; a wrong one costs a second.
  • Over the internet, put hunt behind HTTPS (a reverse proxy such as Caddy, which does it on its own): the cookie is marked secure when the proxy says the visit was over HTTPS (X-Forwarded-Proto).

A sign-in proxy, for several people​

If you already sign people in at a proxy (Authelia, Authentik, oauth2-proxy, Tailscale), it can tell hunt who's asking, in a header:

hunt serve --tenants --admins you@example.com \
--auth-header Remote-Email --trusted-proxies 172.18.0.0/16
# or HUNT_TENANTS=1 HUNT_ADMINS=… HUNT_AUTH_HEADER=… HUNT_TRUSTED_PROXIES=…
ProxyIts header
AutheliaRemote-Email
AuthentikX-authentik-email
oauth2-proxyX-Auth-Request-Email (with --set-xauthrequest)
Tailscale (tailscale serve)Tailscale-User-Login
  • --trusted-proxies (or HUNT_TRUSTED_PROXIES) lists the addresses, or ranges, the proxy's requests come from: this machine (127.0.0.1, ::1) unless said, and in Docker, the proxy's network (172.18.0.0/16, say). The header counts from those alone, so nobody reaching hunt another way can claim to be anyone. Keep hunt's own port off the internet all the same.
  • The proxy has to set the header itself, replacing any a visitor sent: Authelia's and oauth2-proxy's usual setups do.
  • People then join and are let in as with Cloudflare Access: see "Several people", below.
  • The CLI, from a trusted address (on hunt's own machine, say), says who's asking itself: set HUNT_AUTH_HEADER (the same header) and HUNT_USER (your email) where you run it.

With Caddy and Authelia, for instance:

hunt.example.com {
forward_auth authelia:9091 {
uri /api/authz/forward-auth
copy_headers Remote-User Remote-Groups Remote-Email Remote-Name
}
reverse_proxy hunt:4848
}

One person's hunt behind a sign-in proxy needs nothing from hunt: the proxy keeps everyone else out.

Cloudflare Access​

Protect the whole hostname (hunt.example.com). Kubernetes' probes reach /healthz inside the cluster, not through Access; a calendar app subscribing to a shared calendar's link needs a bypass for /api/calendar/. In a shared hunt, hunt also checks Access's signed token on every request for data, so a mistake in Access's setup doesn't open anyone's data.

Behind Cloudflare Access, the sidebar has Log out (ending the Access session), and the admin centre's Debugging info has the identity Access holds for you and the Zero Trust dashboard, with hunt's own health check, calendar feed, backup, source and image builds. The CLI uses a service token: set HUNT_ACCESS_CLIENT_ID and HUNT_ACCESS_CLIENT_SECRET to its id and secret, and HUNT_URL to the public address. The "Send to hunt" bookmarklet opens hunt in a tab, so it signs in like any other visit.