mealie, actualbudget: add native "Sign in with Authelia" (OIDC)
Researched which of the "has built-in auth" services actually support native OIDC before wiring anything in (checked live docs, not assumed) — two services turned out to contradict general assumption: Portainer's OAuth/OIDC is Business Edition only (this repo installs portainer-ce, which doesn't have it), and ntfy has no auth-oauth2-* support at all despite it seeming like the kind of thing a modern self-hosted tool would have added by now. Full findings recorded in CLAUDE.md so this doesn't need re-researching. Two real, verified wins wired up, both entirely env-var driven — no manual config file editing, matching this repo's "no manual wizard" philosophy and reusing the exact _authelia_provision_oidc_client / _authelia_scope_access machinery already built for Gitea: - mealie: OIDC_AUTH_ENABLED/OIDC_CLIENT_ID/OIDC_CLIENT_SECRET/ OIDC_CONFIGURATION_URL appended to the existing .env (env_file: .env is already how mealie.sh's compose reads it). Also adds a --forwarded-allow-ips entrypoint override when Caddy-fronted — confirmed against Mealie's own issue tracker that without it, the generated OIDC redirect URI comes out http:// even when actually served over https://, which providers reject as a scheme mismatch. - actualbudget: ACTUAL_OPENID_DISCOVERY_URL/CLIENT_ID/CLIENT_SECRET/ SERVER_HOSTNAME, same pattern. Redirect path (/openid/callback) matches the preset already used by authelia.sh's own "Register an app" menu for this same service. Both offered on fresh installs and Update reruns, default no, and both call _authelia_scope_access() afterward so access can be restricted to specific users instead of every Authelia user, same as Gitea. Immich has real OIDC + a system-config API but needs one more verification pass on the exact request payload before automating — not guessing that part. Jellyfin and Home Assistant only have third-party plugin/HACS-based OIDC, a bigger lift than an env-var toggle — noted but not attempted this pass. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YEQNc4NfBST1m9NtCZVYa8
This commit is contained in:
@@ -198,6 +198,73 @@ fi
|
||||
|
||||
register_service actualbudget utilities "Open-source personal finance & budgeting (Actual Budget)" 5006
|
||||
|
||||
# Offers to add "Sign in with Authelia" (OpenID Connect) to Actual Budget's
|
||||
# own login page — same additive pattern as services/gitea.sh's
|
||||
# _gitea_offer_authelia_sso, entirely environment-variable driven like
|
||||
# services/mealie.sh's equivalent. Confirmed against Actual Budget's own
|
||||
# OIDC docs: ACTUAL_OPENID_DISCOVERY_URL, ACTUAL_OPENID_CLIENT_ID,
|
||||
# ACTUAL_OPENID_CLIENT_SECRET, ACTUAL_OPENID_SERVER_HOSTNAME, appended
|
||||
# into the .env file this installer already writes and reads via
|
||||
# `env_file: .env`. Redirect path (/openid/callback) matches the preset
|
||||
# already used by services/authelia.sh's own "Register an app" menu for
|
||||
# this same app, so both stay consistent with each other.
|
||||
#
|
||||
# No stored BASE_URL to read back here (unlike Mealie) — Actual Budget's
|
||||
# compose/.env never records the public URL, so this asks for the domain
|
||||
# directly instead, same as services/gitea.sh's SSO offer does.
|
||||
#
|
||||
# Args: DIR
|
||||
_actualbudget_offer_authelia_oidc() {
|
||||
local DIR="$1"
|
||||
|
||||
[ -d "$DOCKER_DIR/authelia" ] || return 0
|
||||
declare -F _authelia_provision_oidc_client >/dev/null 2>&1 || return 0
|
||||
grep -q '^ACTUAL_OPENID_DISCOVERY_URL=' "$DIR/.env" 2>/dev/null && return 0
|
||||
|
||||
echo ""
|
||||
local USE_SSO=""
|
||||
prompt_yn " Add \"Sign in with Authelia\" (OpenID Connect) to Actual Budget's login page? (y/n):" "n" USE_SSO
|
||||
[[ "$USE_SSO" =~ ^[Yy]$ ]] || return 0
|
||||
|
||||
local _default_domain=""
|
||||
[ -n "${SITE_DOMAIN:-}" ] && [ "$SITE_DOMAIN" != "example.com" ] && _default_domain="budget.${SITE_DOMAIN}"
|
||||
local AB_OIDC_DOMAIN=""
|
||||
prompt_text " Domain Actual Budget is reachable at [${_default_domain:-required}]:" "$_default_domain" AB_OIDC_DOMAIN
|
||||
if [ -z "$AB_OIDC_DOMAIN" ]; then
|
||||
log_warning "No domain entered — skipping Authelia SSO for Actual Budget."
|
||||
return 0
|
||||
fi
|
||||
|
||||
local _2fa="" AUTH_POLICY="two_factor"
|
||||
prompt_yn " Require two-factor for Actual Budget logins via Authelia too? (y/n):" "y" _2fa
|
||||
[[ "$_2fa" =~ ^[Yy]$ ]] || AUTH_POLICY="one_factor"
|
||||
|
||||
if ! _authelia_provision_oidc_client "ActualBudget" "actualbudget" "$AUTH_POLICY" "y" \
|
||||
"https://${AB_OIDC_DOMAIN}/openid/callback"; then
|
||||
log_warning "Couldn't register Actual Budget as an OIDC client in Authelia — skipping SSO setup."
|
||||
return 0
|
||||
fi
|
||||
|
||||
local _discovery_url="https://auth.${OIDC_AUTHELIA_DOMAIN}/.well-known/openid-configuration"
|
||||
cat >> "$DIR/.env" << ENV
|
||||
|
||||
# Written by services/actualbudget.sh's Authelia SSO step. The first OIDC
|
||||
# login becomes the Actual Budget server owner if no owner is set yet —
|
||||
# that's Actual Budget's own behavior, not something this script controls.
|
||||
ACTUAL_OPENID_DISCOVERY_URL=$_discovery_url
|
||||
ACTUAL_OPENID_CLIENT_ID=actualbudget
|
||||
ACTUAL_OPENID_CLIENT_SECRET=$OIDC_CLIENT_SECRET_PLAIN
|
||||
ACTUAL_OPENID_SERVER_HOSTNAME=https://${AB_OIDC_DOMAIN}
|
||||
ENV
|
||||
chown "$ACTUAL_USER:$ACTUAL_USER" "$DIR/.env" 2>/dev/null || true
|
||||
|
||||
(cd "$DIR" && docker compose up -d) \
|
||||
&& log_success "\"Sign in with Authelia\" added to Actual Budget — local login still works too." \
|
||||
|| log_warning "Restart failed — check: docker compose -f $DIR/docker-compose.yml logs"
|
||||
|
||||
declare -F _authelia_scope_access >/dev/null 2>&1 && _authelia_scope_access "actualbudget" "$AB_OIDC_DOMAIN"
|
||||
}
|
||||
|
||||
install_actualbudget() {
|
||||
require_docker || return 1
|
||||
|
||||
@@ -216,6 +283,7 @@ install_actualbudget() {
|
||||
echo " - Create \$DOCKER_DIR/actualbudget(-<name>) with docker-compose.yml (data/)"
|
||||
echo " - Auto-scan for a free host port if this is an additional instance"
|
||||
echo " - Offer a Caddy reverse proxy and to start the container"
|
||||
echo " - Offer \"Sign in with Authelia\" (OIDC) if Authelia is installed"
|
||||
return 0
|
||||
fi
|
||||
|
||||
@@ -258,6 +326,7 @@ install_actualbudget() {
|
||||
( cd "$AB_DIR" && docker compose pull && docker compose up -d ) \
|
||||
&& log_success "Actual Budget image refreshed" \
|
||||
|| log_warning "Refresh failed — check: docker compose -f $AB_DIR/docker-compose.yml logs"
|
||||
declare -F _actualbudget_offer_authelia_oidc >/dev/null 2>&1 && _actualbudget_offer_authelia_oidc "$AB_DIR"
|
||||
return 0
|
||||
;;
|
||||
cancel)
|
||||
@@ -333,6 +402,8 @@ AB_ENV
|
||||
|
||||
configure_caddy_for_service "ActualBudget${INSTANCE_SUFFIX:+ ($INSTANCE_SUFFIX)}" "${CONTAINER}:5006" "budget${INSTANCE_SUFFIX:+-$INSTANCE_SUFFIX}"
|
||||
|
||||
declare -F _actualbudget_offer_authelia_oidc >/dev/null 2>&1 && _actualbudget_offer_authelia_oidc "$AB_DIR"
|
||||
|
||||
write_readme "$AB_DIR" << MD
|
||||
# Actual Budget${INSTANCE_SUFFIX:+ — $INSTANCE_SUFFIX}
|
||||
|
||||
|
||||
@@ -198,6 +198,83 @@ fi
|
||||
|
||||
register_service mealie utilities "Recipe manager & meal planner (Mealie)" 9925
|
||||
|
||||
# Offers to add "Sign in with Authelia" (OpenID Connect) to Mealie's own
|
||||
# login page — same additive pattern as services/gitea.sh's
|
||||
# _gitea_offer_authelia_sso (local login keeps working unchanged), but
|
||||
# Mealie's OIDC support is entirely environment-variable driven — no CLI
|
||||
# equivalent to Gitea's `admin auth add-oauth` needed. Confirmed against
|
||||
# Mealie's own OIDC docs: OIDC_AUTH_ENABLED, OIDC_CLIENT_ID,
|
||||
# OIDC_CLIENT_SECRET, OIDC_CONFIGURATION_URL, OIDC_SIGNUP_ENABLED, appended
|
||||
# straight into the .env file this installer already writes and reads via
|
||||
# `env_file: .env` — no docker-compose.yml regeneration needed for that part.
|
||||
#
|
||||
# Reads BASE_URL back from the existing .env rather than taking it as an
|
||||
# arg, so this works identically whether called right after a fresh
|
||||
# install (where the URL was just computed) or from an Update rerun
|
||||
# (where it wasn't recomputed this run, but is already on disk).
|
||||
#
|
||||
# Args: DIR CONTAINER
|
||||
_mealie_offer_authelia_oidc() {
|
||||
local DIR="$1" CONTAINER="$2"
|
||||
|
||||
[ -d "$DOCKER_DIR/authelia" ] || return 0
|
||||
declare -F _authelia_provision_oidc_client >/dev/null 2>&1 || return 0
|
||||
grep -q '^OIDC_AUTH_ENABLED=' "$DIR/.env" 2>/dev/null && return 0
|
||||
|
||||
local BASE_URL
|
||||
BASE_URL="$(grep '^BASE_URL=' "$DIR/.env" 2>/dev/null | cut -d= -f2-)"
|
||||
if [ -z "$BASE_URL" ]; then
|
||||
log_warning "Couldn't find BASE_URL in $DIR/.env — skipping Authelia SSO offer for Mealie."
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo ""
|
||||
local USE_SSO=""
|
||||
prompt_yn " Add \"Sign in with Authelia\" (OpenID Connect) to Mealie's login page? (y/n):" "n" USE_SSO
|
||||
[[ "$USE_SSO" =~ ^[Yy]$ ]] || return 0
|
||||
|
||||
local _2fa="" AUTH_POLICY="two_factor"
|
||||
prompt_yn " Require two-factor for Mealie logins via Authelia too? (y/n):" "y" _2fa
|
||||
[[ "$_2fa" =~ ^[Yy]$ ]] || AUTH_POLICY="one_factor"
|
||||
|
||||
if ! _authelia_provision_oidc_client "Mealie" "mealie" "$AUTH_POLICY" "y" "${BASE_URL}/login"; then
|
||||
log_warning "Couldn't register Mealie as an OIDC client in Authelia — skipping SSO setup."
|
||||
return 0
|
||||
fi
|
||||
|
||||
local _discovery_url="https://auth.${OIDC_AUTHELIA_DOMAIN}/.well-known/openid-configuration"
|
||||
cat >> "$DIR/.env" << ENV
|
||||
|
||||
# Written by services/mealie.sh's Authelia SSO step — adds "Sign in with
|
||||
# Authelia" alongside local login; local accounts keep working unchanged.
|
||||
OIDC_AUTH_ENABLED=true
|
||||
OIDC_SIGNUP_ENABLED=true
|
||||
OIDC_CLIENT_ID=mealie
|
||||
OIDC_CLIENT_SECRET=$OIDC_CLIENT_SECRET_PLAIN
|
||||
OIDC_CONFIGURATION_URL=$_discovery_url
|
||||
OIDC_PROVIDER_NAME=Authelia
|
||||
ENV
|
||||
chown "$ACTUAL_USER:$ACTUAL_USER" "$DIR/.env" 2>/dev/null || true
|
||||
|
||||
# Mealie's OIDC redirect URI generation trusts X-Forwarded-* only from
|
||||
# explicitly allowed IPs — without this, a Caddy-fronted instance
|
||||
# generates an http:// redirect URI even when actually served over
|
||||
# https://, which Authelia/any OIDC provider rejects as a scheme
|
||||
# mismatch. Confirmed against Mealie's own reverse-proxy docs/issue
|
||||
# tracker. Only needed (and only added) when Caddy is actually
|
||||
# fronting this instance — BASE_URL itself tells us that (it's only
|
||||
# ever https:// when a real domain + Caddy were configured).
|
||||
if [[ "$BASE_URL" == https://* ]] && ! grep -q '^ entrypoint:' "$DIR/docker-compose.yml"; then
|
||||
sed -i "/container_name: ${CONTAINER}\$/a\\ entrypoint: [\"uvicorn\", \"mealie.app:app\", \"--host\", \"0.0.0.0\", \"--port\", \"9000\", \"--forwarded-allow-ips=*\"]" "$DIR/docker-compose.yml"
|
||||
fi
|
||||
|
||||
(cd "$DIR" && docker compose up -d) \
|
||||
&& log_success "\"Sign in with Authelia\" added to Mealie — local login still works too." \
|
||||
|| log_warning "Restart failed — check: docker compose -f $DIR/docker-compose.yml logs"
|
||||
|
||||
declare -F _authelia_scope_access >/dev/null 2>&1 && _authelia_scope_access "mealie" "${BASE_URL#*://}"
|
||||
}
|
||||
|
||||
install_mealie() {
|
||||
require_docker || return 1
|
||||
|
||||
@@ -217,6 +294,7 @@ install_mealie() {
|
||||
echo " - Auto-scan for a free host port if this is an additional instance"
|
||||
echo " - Default login: changeme@email.com / MyPassword (change immediately)"
|
||||
echo " - Offer a Caddy reverse proxy and to start the container"
|
||||
echo " - Offer \"Sign in with Authelia\" (OIDC) if Authelia is installed"
|
||||
return 0
|
||||
fi
|
||||
|
||||
@@ -259,6 +337,7 @@ install_mealie() {
|
||||
( cd "$MEALIE_DIR" && docker compose pull && docker compose up -d ) \
|
||||
&& log_success "Mealie image refreshed" \
|
||||
|| log_warning "Refresh failed — check: docker compose -f $MEALIE_DIR/docker-compose.yml logs"
|
||||
declare -F _mealie_offer_authelia_oidc >/dev/null 2>&1 && _mealie_offer_authelia_oidc "$MEALIE_DIR" "$CONTAINER"
|
||||
return 0
|
||||
;;
|
||||
cancel)
|
||||
@@ -352,6 +431,8 @@ MEALIE_ENV
|
||||
|
||||
configure_caddy_for_service "Mealie${INSTANCE_SUFFIX:+ ($INSTANCE_SUFFIX)}" "${CONTAINER}:9000" "recipes${INSTANCE_SUFFIX:+-$INSTANCE_SUFFIX}"
|
||||
|
||||
declare -F _mealie_offer_authelia_oidc >/dev/null 2>&1 && _mealie_offer_authelia_oidc "$MEALIE_DIR" "$CONTAINER"
|
||||
|
||||
write_readme "$MEALIE_DIR" << MD
|
||||
# Mealie${INSTANCE_SUFFIX:+ — $INSTANCE_SUFFIX}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user