Fixes Zulip OIDC authentication where redirect_uri used internal IP (192.168.68.19) instead of public domain (chat.sysloggh.net) after server restart. Monkey-patches social_core.strategy.BaseStrategy to use ROOT_DOMAIN_URI for all redirect URI construction.
3.4 KiB
3.4 KiB
kind, name, status, description, agent, triggers
| kind | name | status | description | agent | triggers | |||
|---|---|---|---|---|---|---|---|---|
| responsibility | zulip-oidc-redirect-fix | active | Fixes Zulip OIDC authentication when the redirect_uri sent to Authentik uses the internal IP (192.168.68.19) instead of the public domain (chat.sysloggh.net). Applied via monkey-patch in ZULIP_CUSTOM_SETTINGS. Survives container restarts through compose.override.yaml. | abiba |
|
Maintains
- zulip-oidc: { redirect_uri: "https://chat.sysloggh.net/complete/oidc/", scheme: "https", host: "chat.sysloggh.net" }
- authentik-acceptance: { status: "accepted" | "rejected" }
- patched-strategy: { module: "social_core.strategy.BaseStrategy", method: "absolute_uri", root: "ROOT_DOMAIN_URI" }
Detection
Rule 1: Wrong redirect_uri host
- Detect:
curl -sk -L "https://chat.sysloggh.net/accounts/login/social/oidc/authentik" 2>&1 | grep "redirect_uri=https://192.168.68.19" - Status: CRITICAL — Authentik will reject
- Trigger fix → Execute self-heal
Rule 2: OIDC flow broken
- Detect:
curl -sk -o /dev/null -w "%{http_code}" "https://chat.sysloggh.net/accounts/login/social/oidc/authentik"→ chain ends at Authentik 400 - Diagnose: Check redirect_uri in the 302 Location header chain
Fix (Self-Heal)
Two layers applied:
Layer 1: Live patch (inside container, immediate)
# Add to /home/zulip/deployments/current/zproject/computed_settings.py:
SOCIAL_AUTH_REDIRECT_IS_HTTPS = True
import urllib.parse
from social_core.strategy import BaseStrategy
_original_absolute_uri = BaseStrategy.absolute_uri
def _patched_absolute_uri(self, path=None):
from django.conf import settings
root = getattr(settings, "ROOT_DOMAIN_URI", "https://chat.sysloggh.net")
if path is not None:
return urllib.parse.urljoin(root, path)
return root
BaseStrategy.absolute_uri = _patched_absolute_uri
# Restart Django
supervisorctl restart zulip-django
Layer 2: Persistent fix (compose.override.yaml)
The patch is baked into the ZULIP_CUSTOM_SETTINGS env var in
/opt/zulip/compose.override.yaml. Survives Docker container restarts.
Verification
STEP1=$(curl -sk -w "%{redirect_url}" \
"https://chat.sysloggh.net/accounts/login/social/oidc/authentik" -o /dev/null)
curl -sk -D- "$STEP1" -o /dev/null 2>&1 | grep "redirect_uri="
# Expected: redirect_uri=https://chat.sysloggh.net/complete/oidc/
# Wrong: redirect_uri=https://192.168.68.19/complete/oidc/
Rollback
Remove the patch block from compose.override.yaml and restart the container:
docker compose -f /opt/zulip/compose.yaml -f /opt/zulip/compose.override.yaml up -d zulip
Root Cause
After Zulip restart, social-auth-core computes the OIDC redirect_uri via
Django's request.build_absolute_uri() → request.get_host(). The upstream
Netbird/Traefik proxy (72.61.0.17) forwards Host: 192.168.68.19 instead of
Host: chat.sysloggh.net, and without HTTP_HOST in nginx's uwsgi_params,
Django falls back to the server's IP.
The monkey-patch overrides BaseStrategy.absolute_uri() to always use
ROOT_DOMAIN_URI (https://chat.sysloggh.net) regardless of the request's
Host header.
Related Contracts
zulip-health.prose.md— General Zulip health monitoringzulip-self-heal.prose.md— RETIRED (pi extension removed)