{"record":{"id":"c3678203d7009b7e","repo":"siyuan-note/siyuan","slug":"oidc-client-id-is-required","errorCode":null,"errorMessage":"OIDC client ID is required","messagePattern":"OIDC client ID is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/oidc.go","lineNumber":516,"sourceCode":"\t\treturn\n\t}\n\tworkspaceSession := util.GetWorkspaceSession(util.GetSession(c))\n\tif !cancelOIDCValidation(input.PollToken, workspaceSession.OIDCBinding) {\n\t\tret.Code = -1\n\t\tret.Msg = oidcLanguage(369, \"Invalid OIDC configuration\")\n\t}\n}\n\nfunc validateOIDCConfiguration() error {\n\treturn ValidateOIDCConfiguration(Conf.GetOIDC())\n}\n\nfunc ValidateOIDCConfiguration(config *conf.OIDC) error {\n\tif config == nil || !config.Enabled {\n\t\treturn errors.New(\"OIDC login is not enabled\")\n\t}\n\tif config.ClientID == \"\" {\n\t\treturn errors.New(\"OIDC client ID is required\")\n\t}\n\tif config.Provider == conf.OIDCProviderGitHub && config.ClientSecret == \"\" {\n\t\treturn errors.New(\"GitHub OAuth client secret is required\")\n\t}\n\tif (config.Provider == conf.OIDCProviderCustom || config.Provider == conf.OIDCProviderMicrosoft) && config.IssuerURL == \"\" {\n\t\treturn errors.New(\"OIDC issuer URL is required\")\n\t}\n\tif (config.Provider == conf.OIDCProviderCustom || config.Provider == conf.OIDCProviderMicrosoft) && config.IssuerURL != \"\" {\n\t\tissuer, err := url.Parse(config.IssuerURL)\n\t\tif err != nil || issuer.Host == \"\" || issuer.User != nil || issuer.RawQuery != \"\" || issuer.Fragment != \"\" ||\n\t\t\t(issuer.Scheme != \"https\" && !util.IsLocalHostname(issuer.Hostname())) {\n\t\t\treturn errors.New(\"OIDC issuer URL must use HTTPS unless it is a loopback address\")\n\t\t}\n\t}\n\tif config.Provider != conf.OIDCProviderCustom && config.Provider != conf.OIDCProviderGoogle &&\n\t\tconfig.Provider != conf.OIDCProviderMicrosoft && config.Provider != conf.OIDCProviderGitHub {\n\t\treturn errors.New(\"Unsupported OIDC provider\")\n\t}","sourceCodeStart":498,"sourceCodeEnd":534,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/model/oidc.go#L498-L534","documentation":"Second check in ValidateOIDCConfiguration (kernel/model/oidc.go:516): OIDC is enabled but ClientID is empty. Every OIDC provider requires a client identifier registered at the IdP, so an empty ClientID is rejected before provider-specific checks run.","triggerScenarios":"Saving OIDC config with Enabled=true but leaving the Client ID field blank, or a config migration that dropped the ClientID value.","commonSituations":"Admin enabled OIDC to test and forgot to paste the IdP-issued client ID; frontend form submitted before the field was filled.","solutions":["Obtain the Client ID from the OIDC provider's app registration console and paste it into settings.","Re-save the full OIDC config (ClientID + ClientSecret + Provider + IssuerURL) together.","If migrating configs, verify the JSON carried ClientID across versions."],"exampleFix":"// before\ncfg := &conf.OIDC{Enabled: true, Provider: conf.OIDCProviderGitHub, ClientSecret: \"x\"}\n// after\ncfg := &conf.OIDC{Enabled: true, Provider: conf.OIDCProviderGitHub,\n    ClientID: os.Getenv(\"SIYUAN_OIDC_CLIENT_ID\"),\n    ClientSecret: os.Getenv(\"SIYUAN_OIDC_CLIENT_SECRET\")}","handlingStrategy":"validation","validationCode":"if cfg.Enabled && cfg.ClientID == \"\" {\n    return errors.New(\"OIDC ClientID missing\")\n}\nreturn ValidateOIDCConfiguration(cfg)","typeGuard":"func hasClientID(c *conf.OIDC) bool { return c != nil && c.ClientID != \"\" }","tryCatchPattern":null,"preventionTips":["Front-end forms should require Client ID before enabling OIDC.","Store OIDC secrets in environment variables or a secrets manager, not in tracked config files."],"tags":["oidc","auth","config","validation"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}