breakfix: ERROR_REPLACEMENT when using environment variable in placeholder
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.
same issue
@oluceps , you will need to troubleshoot the replacers. It could be environment variable propagation or Caddyfile syntax.
@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....