{"record":{"id":"e7c7a25fea3290c6","repo":"siyuan-note/siyuan","slug":"oidc-redirect-url-is-required","errorCode":null,"errorMessage":"OIDC redirect URL is required","messagePattern":"OIDC redirect URL is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/oidc_provider/provider.go","lineNumber":43,"sourceCode":"const (\n\tgoogleIssuer = \"https://accounts.google.com\"\n)\n\ntype Provider struct {\n\tkind         string\n\toauth2Config *oauth2.Config\n\tverifier     *oidc.IDTokenVerifier\n}\n\nfunc New(ctx context.Context, config *conf.OIDC, redirectURL string) (*Provider, error) {\n\tif config == nil {\n\t\treturn nil, errors.New(\"OIDC configuration is missing\")\n\t}\n\tif config.ClientID == \"\" {\n\t\treturn nil, errors.New(\"OIDC client ID is required\")\n\t}\n\tif redirectURL == \"\" {\n\t\treturn nil, errors.New(\"OIDC redirect URL is required\")\n\t}\n\tif config.Provider == conf.OIDCProviderGitHub && config.ClientSecret == \"\" {\n\t\treturn nil, errors.New(\"GitHub OAuth client secret is required\")\n\t}\n\tissuerURL := strings.TrimSpace(config.IssuerURL)\n\tswitch config.Provider {\n\tcase conf.OIDCProviderGoogle:\n\t\tissuerURL = googleIssuer\n\tcase conf.OIDCProviderMicrosoft:\n\t\t// Microsoft 多租户端点的 issuer 会随租户变化，必须使用租户专属 issuer。\n\tcase conf.OIDCProviderCustom:\n\tcase conf.OIDCProviderGitHub:\n\t\treturn newGitHub(config, redirectURL), nil\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unsupported OIDC provider [%s]\", config.Provider)\n\t}\n\tif issuerURL == \"\" {\n\t\treturn nil, errors.New(\"OIDC issuer URL is required\")","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/model/oidc_provider/provider.go#L25-L61","documentation":"Thrown by oidc_provider.New() when the redirectURL argument is an empty string. The redirect URL is the endpoint the provider sends the authorization code back to after user consent; without it the OAuth2 dance cannot complete. This is the third validation guard in the constructor.","triggerScenarios":"Calling New() with an empty redirectURL string. This typically means the caller failed to construct the callback URL from the server's base address, or the server base URL is unset/empty in configuration.","commonSituations":"The SiYuan instance is behind a reverse proxy and the externally-visible base URL was not configured, so the caller computed an empty redirect. The kernel is running in an environment where util.ServerURL or equivalent returns empty. The developer passed a literal empty string during testing.","solutions":["Ensure the server base URL / access address is configured so the OIDC callback URL can be derived.","In the calling code, construct and validate redirectURL = baseUrl + \"/api/oidc/callback\" before invoking New().","If behind a reverse proxy, set the correct X-Forwarded-* headers or explicit base URL so the redirect is not empty."],"exampleFix":"// before\nprovider, err := oidc_provider.New(ctx, config, \"\")\n\n// after\nredirectURL := strings.TrimRight(conf.ServerURL, \"/\") + \"/api/oidc/callback\"\nif redirectURL == \"/api/oidc/callback\" {\n    return nil, errors.New(\"server base URL is not configured\")\n}\nprovider, err := oidc_provider.New(ctx, config, redirectURL)","handlingStrategy":"validation","validationCode":"if redirectURL == \"\" {\n    return nil, errors.New(\"redirect URL could not be derived; configure the server base address\")\n}\nprovider, err := oidc_provider.New(ctx, config, redirectURL)","typeGuard":"func hasRedirectURL(url string) bool {\n    return strings.TrimSpace(url) != \"\"\n}","tryCatchPattern":null,"preventionTips":["Construct the redirect URL from a validated server base URL before calling New().","Ensure the server base address is configured in settings (not empty).","Log the computed redirect URL at startup for verification."],"tags":["oidc","authentication","config","oauth2"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}