siyuan-note/siyuan · error

A loopback OIDC redirect URL is required for local access

Error message

A loopback OIDC redirect URL is required for local access

What it means

Returned by effectiveOIDCRedirectURL (kernel/model/oidc.go:613) for the desktop flow when the request IS local (IsLocalRequest passed earlier) but c.Request.Host, after parsing via util.IsLocalHost, is not a loopback host. This catches proxied or Host-header-rewritten requests that look local to the connection but carry a non-loopback Host.

Source

Thrown at kernel/model/oidc.go:613

}

func effectiveOIDCRedirectURL(c *gin.Context, flow string) (string, error) {
	if flow == oidcFlowMobile {
		return oidcMobileRedirectURL, nil
	}
	if flow == oidcFlowWeb && !IsLocalRequest(c) {
		return validatePublicOIDCRedirectURL(Conf.GetOIDC().RedirectURL)
	}
	if !IsLocalRequest(c) {
		return "", errors.New("Desktop OIDC login requires a loopback listener")
	}
	scheme := "http"
	if c.Request.TLS != nil || c.GetHeader("X-Forwarded-Proto") == "https" {
		scheme = "https"
	}
	host := c.Request.Host
	if !util.IsLocalHost(host) {
		return "", errors.New("A loopback OIDC redirect URL is required for local access")
	}
	return scheme + "://" + host + "/api/system/oidc/callback", nil
}

func oidcValidationRedirectURL(c *gin.Context, config *conf.OIDC, mobile bool) (string, error) {
	if mobile {
		return oidcMobileRedirectURL, nil
	}
	if config.RedirectURL != "" {
		return validatePublicOIDCRedirectURL(config.RedirectURL)
	}
	return effectiveOIDCRedirectURL(c, oidcFlowDesktop)
}

func validatePublicOIDCRedirectURL(redirectURL string) (string, error) {
	if redirectURL == "" {
		return "", errors.New("A public HTTPS OIDC redirect URL is required for remote access")
	}

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Access SiYuan directly via 127.0.0.1:6806 or localhost:6806 for the desktop OIDC flow so Host is loopback.
  2. Configure the proxy to pass Host as 127.0.0.1:6806 for desktop login, or use the web flow with a public redirect URL.
  3. Avoid /etc/hosts tricks with non-localhost names for desktop OIDC.

Example fix

# before — proxy sets external Host
proxy_set_header Host siyuan.corp;
# after — for local desktop flow, access directly
open http://127.0.0.1:6806  # Host: 127.0.0.1:6806 -> ok
Defensive patterns

Strategy: validation

Validate before calling

if !util.IsLocalHost(c.Request.Host) {
    return errors.New("request Host is not loopback; use 127.0.0.1")
}

Type guard

func hostIsLoopback(host string) bool { return util.IsLocalHost(host) }

Prevention

When it happens

Trigger: A reverse proxy on the same machine forwards to SiYuan with a non-loopback Host header; a browser uses a custom Host mapping (e.g. via /etc/hosts to a non-localhost name) that still routes to 127.0.0.1.

Common situations: Local reverse proxy (Caddy/Nginx) in front of SiYuan preserving an external hostname; debugging with a custom domain that resolves to loopback.

Related errors


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/b8a839c852f17ca9. Report an issue: GitHub.