{"record":{"id":"73cbc975f293b0ee","repo":"siyuan-note/siyuan","slug":"oidc-redirect-url-must-end-with-api-system-oidc-c","errorCode":null,"errorMessage":"OIDC redirect URL must end with /api/system/oidc/callback","messagePattern":"OIDC redirect URL must end with /api/system/oidc/callback","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/oidc.go","lineNumber":579,"sourceCode":"\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}\n\tparsed, err := url.Parse(redirectURL)\n\tif err != nil || parsed.Scheme == \"\" || parsed.Host == \"\" || parsed.Path != \"/api/system/oidc/callback\" ||\n\t\tparsed.User != nil || parsed.RawQuery != \"\" || parsed.Fragment != \"\" {\n\t\treturn \"\", errors.New(\"OIDC redirect URL must end with /api/system/oidc/callback\")\n\t}\n\tif parsed.Scheme != \"https\" {\n\t\treturn \"\", errors.New(\"Public OIDC redirect URL must use HTTPS\")\n\t}\n\treturn parsed.String(), nil\n}\n\nfunc getOIDCProvider(ctx context.Context, redirectURL string) (*oidc_provider.Provider, error) {\n\tversion := oidcConfigurationVersion(Conf.GetOIDC())\n\tkey := version + \"\\x00\" + redirectURL\n\toidcProviders.Lock()\n\tif oidcProviders.version != version {\n\t\toidcProviders.version = version\n\t\toidcProviders.items = map[string]*oidc_provider.Provider{}\n\t}\n\tif provider := oidcProviders.items[key]; provider != nil {\n\t\toidcProviders.Unlock()\n\t\treturn provider, nil","sourceCodeStart":561,"sourceCodeEnd":597,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/model/oidc.go#L561-L597","documentation":"The public OIDC redirect URL must parse to an absolute http(s) URL whose path is exactly /api/system/oidc/callback, with no userinfo, query, or fragment; anything else cannot be matched against the fixed callback endpoint, so validatePublicOIDCRedirectURL rejects it.","triggerScenarios":"url.Parse fails, or parsed.Scheme/Host empty, parsed.Path != \"/api/system/oidc/callback\", or parsed.User/RawQuery/Fragment non-empty — for any configured RedirectURL passed via ValidateOIDCProviderConfiguration, ValidateOIDCConfigurationChange, oidcValidationRedirectURL, or effectiveOIDCRedirectURL.","commonSituations":"Entering only the domain or a trailing-slash path (e.g. https://x.com/oidc) instead of the full callback path; appending ?tenant=... parameters; forgetting https:// so Host parses as Path; copying a provider's own redirect format.","solutions":["Use the exact path /api/system/oidc/callback: https://<host>/api/system/oidc/callback","Remove any query string, fragment, or userinfo from the URL","Ensure the URL includes scheme and host (https://your-domain/...), not just a path"],"exampleFix":"// before\nRedirectURL: \"https://siyuan.example.com/oidc?brand=siyuan\"\n// after\nRedirectURL: \"https://siyuan.example.com/api/system/oidc/callback\"","handlingStrategy":"validation","validationCode":"function validPublicRedirect(u) {\n  try {\n    const p = new URL(u);\n    return p.protocol === 'https:' && p.pathname === '/api/system/oidc/callback' && !p.search && !p.hash && !p.username && !p.password;\n  } catch { return false; }\n}","typeGuard":null,"tryCatchPattern":"if err := validatePublicOIDCRedirectURL(cfg.RedirectURL); err != nil {\n    // correct to https://<host>/api/system/oidc/callback and retry\n}","preventionTips":["Always append /api/system/oidc/callback to your public base URL","No query strings, fragments, or credentials in the redirect URL","Validate the URL client-side with URL parsing before saving"],"tags":["oidc","redirect","url","validation"],"backgroundTag":"invalid-url-format","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"}