{"record":{"id":"b8a839c852f17ca9","repo":"siyuan-note/siyuan","slug":"a-loopback-oidc-redirect-url-is-required-for-local","errorCode":null,"errorMessage":"A loopback OIDC redirect URL is required for local access","messagePattern":"A loopback OIDC redirect URL is required for local access","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/oidc.go","lineNumber":557,"sourceCode":"}\n\nfunc effectiveOIDCRedirectURL(c *gin.Context, flow string) (string, error) {\n\tif flow == oidcFlowMobile {\n\t\treturn oidcMobileRedirectURL, nil\n\t}\n\tif flow == oidcFlowWeb && !IsLocalRequest(c) {\n\t\treturn validatePublicOIDCRedirectURL(Conf.GetOIDC().RedirectURL)\n\t}\n\tif !IsLocalRequest(c) {\n\t\treturn \"\", errors.New(\"Desktop OIDC login requires a loopback listener\")\n\t}\n\tscheme := \"http\"\n\tif c.Request.TLS != nil || c.GetHeader(\"X-Forwarded-Proto\") == \"https\" {\n\t\tscheme = \"https\"\n\t}\n\thost := c.Request.Host\n\tif !util.IsLocalHost(host) {\n\t\treturn \"\", errors.New(\"A loopback OIDC redirect URL is required for local access\")\n\t}\n\treturn scheme + \"://\" + host + \"/api/system/oidc/callback\", nil\n}\n\nfunc oidcValidationRedirectURL(c *gin.Context, config *conf.OIDC, mobile bool) (string, error) {\n\tif mobile {\n\t\treturn oidcMobileRedirectURL, nil\n\t}\n\tif config.RedirectURL != \"\" {\n\t\treturn validatePublicOIDCRedirectURL(config.RedirectURL)\n\t}\n\treturn effectiveOIDCRedirectURL(c, oidcFlowDesktop)\n}\n\nfunc validatePublicOIDCRedirectURL(redirectURL string) (string, error) {\n\tif redirectURL == \"\" {\n\t\treturn \"\", errors.New(\"A public HTTPS OIDC redirect URL is required for remote access\")\n\t}","sourceCodeStart":539,"sourceCodeEnd":575,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/model/oidc.go#L539-L575","documentation":"When building the desktop loopback redirect URL, effectiveOIDCRedirectURL double-checks that the request's Host is a local address via util.IsLocalHost; a non-loopback Host (e.g. a LAN IP or domain) is rejected because desktop login must redirect back to the same machine.","triggerScenarios":"effectiveOIDCRedirectURL on the desktop flow with a request whose Host header is not local (util.IsLocalHost(host) == false) even if the remote-IP check passed; called from OIDCStart and oidcValidationRedirectURL.","commonSituations":"Reaching the kernel through a hostname, docker container name, or LAN IP while still being treated as an intra-LAN client; proxy rewriting the Host header away from 127.0.0.1.","solutions":["Open SiYuan using http://127.0.0.1:<port> (or localhost) before starting desktop OIDC login","Fix reverse-proxy Host header preservation (proxy_set_header Host 127.0.0.1 or original local host)","For non-local access, switch to the web/mobile flow with a validated public redirect URL"],"exampleFix":"// before\nHost: 192.168.1.10:6806\n// after\nHost: 127.0.0.1:6806","handlingStrategy":"validation","validationCode":"const hostOk = /^(localhost|127\\.0\\.0\\.1|\\[::1\\])(:\\d+)?$/.test(location.host);\nif (!hostOk) console.warn('use http://127.0.0.1:<port> for desktop OIDC login');","typeGuard":null,"tryCatchPattern":"if !util.IsLocalHost(c.Request.Host) {\n    // surface guidance: open via http://127.0.0.1:<port> before OIDC login\n}","preventionTips":["Bookmark the loopback URL and use it for admin/login actions","Keep reverse proxies from rewriting the Host header to a non-local value","For remote setups, always use the web flow instead of desktop"],"tags":["oidc","redirect","loopback"],"backgroundTag":"invalid-url","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}