caddy-security icon indicating copy to clipboard operation
caddy-security copied to clipboard

breakfix: ERROR_REPLACEMENT when using environment variable in placeholder

Open yonran opened this issue 4 months ago • 3 comments

Describe the issue

{file.{$ENV}} does not work in caddy-security.

In other plugins, you can use environment variables inside placeholders. Example:

# Caddyfile:

    tls {
      dns cloudflare {file.{$CLOUDFLARE_API_TOKEN_FILE}}
    }

# systemd config /etc/systemctl/caddy.service.d/overrides.conf:
LoadCredentialEncrypted=cloudflare_token:/etc/secrets/cloudflare_token
Environment=CLOUDFLARE_API_TOKEN_FILE=%d/cloudflare_token

However, when I tried doing the same thing with caddy-security:

# Caddyfile
security {
  oauth identity provider google {file.{$GOOGLE_CLIENT_ID_FILE}} {file.{$GOOGLE_CLIENT_SECRET_FILE}}
}

then it silently fails and is replaced with ERROR_REPLACEMENT:

curl localhost:2019/config/ | jq
{
  "apps": {
    …,
    "security": {
      …,
      "config": {
        …,
        "identity_providers": [
          {
            "kind": "oauth",
            "name": "google",
            "params": {
              "client_id": "ERROR_REPLACEMENT",
              "client_secret": "ERROR_REPLACEMENT",
              "driver": "google",
              "realm": "google"
            }
          }
        ]
      }
    }
  }
}

Configuration

Paste full Caddyfile below:

{
	admin localhost:2025
	debug
	# Ensure plugin directives order well
	order authenticate before respond
	order authorize before reverse_proxy

	auto_https off
	servers :8085 {
	}

	# Configure caddy-security app: Google OIDC portal and policy
	security {
		# Define Google OAuth2 IdP using shortcut (client_id client_secret)
		# TODO: caddy-security doesn't support {file.{$VAR}} syntax due to early parsing
		# Should be: 
		oauth identity provider google {file.{$GOOGLE_CLIENT_ID_FILE}} {file.{$GOOGLE_CLIENT_SECRET_FILE}}

		# Authentication portal issues/validates tokens; requires a signing key
		authentication portal myportal {
			crypto key sign-verify {file.{$AUTH_SIGN_KEY_FILE}}
			enable identity provider google
		}

		# Authorization policy: verify same key and set login URL
		authorization policy mypolicy {
			set auth url /auth/
			set redirect query parameter redirect_url
			# TODO: caddy-security doesn't support {file.{$VAR}} syntax due to early parsing
			# Should be: 
			crypto key verify {file.{$AUTH_SIGN_KEY_FILE}}
			allow email [email protected]
		}
	}

	log {
		level ERROR
	}
}

http://*:8085 {
	reverse_proxy localhost:9090
}

command:

touch /tmp/a
GOOGLE_CLIENT_ID_FILE=/tmp/a GOOGLE_CLIENT_SECRET_FILE=/tmp/a AUTH_SIGN_KEY_FILE=/tmp/a caddy run --config /tmp/caddy_config --adapter caddyfile &
curl localhost:2025/config/

Version Information

Provide output of caddy list-modules --versions | grep -E "(auth|security)" below:

http.authentication.hashes.bcrypt v2.10.0
http.authentication.providers.http_basic v2.10.0
http.handlers.authentication v2.10.0
tls.client_auth.verifier.leaf v2.10.0
http.authentication.providers.authorizer v1.1.31
http.handlers.authenticator v1.1.31
security v1.1.31

Expected behavior

No ERROR_REPLACEMENT

Additional context

Add any other context about the problem here.

yonran avatar Sep 09 '25 23:09 yonran

same issue

oluceps avatar Oct 17 '25 17:10 oluceps

@oluceps , you will need to troubleshoot the replacers. It could be environment variable propagation or Caddyfile syntax.

greenpau avatar Oct 18 '25 01:10 greenpau

@oluceps , you will need to troubleshoot the replacers. It could be environment variable propagation or Caddyfile syntax.

@greenpau I am using Caddy's JSON configuration format directly, with syntax {env.THE_ENV}, not the Caddyfile. Therefore, Caddyfile syntax issues are likely not the cause here.

The {env.*} placeholders do work correctly in other parts of my Caddy JSON configuration, even within other plugins. This suggests the environment variables themselves are accessible to the Caddy process. The problem only occurs for fields within the caddy-security app's configuration in my case, specifically under config.identity_providers[].params, such as client_id and client_secret.

If I hardcode the actual client_id and client_secret values directly into the JSON, the authentication flow works perfectly. When using placeholders like {env.MY_CLIENT_ID}, Caddy starts without error (indicating the field isn't seen as empty during initial validation), but the placeholder itself (e.g., {env.MY_CLIENT_ID}) is passed literally into the runtime configuration, resulting in incorrect authentication URLs like ...?client_id=%7Benv.MY_CLIENT_ID%7D....

oluceps avatar Oct 21 '25 06:10 oluceps