{"record":{"id":"d2d0f29b94909fa4","repo":"siyuan-note/siyuan","slug":"oidc-client-id-is-required-d2d0f2","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_provider/provider.go","lineNumber":40,"sourceCode":"\t\"golang.org/x/oauth2\"\n)\n\nconst (\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)","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/model/oidc_provider/provider.go#L22-L58","documentation":"Thrown by oidc_provider.New() when config.ClientID is an empty string. The OAuth2 flow requires a client ID registered with the identity provider; without it, the authorization URL and token exchange are meaningless. This is the second validation guard after the nil-config check.","triggerScenarios":"Calling New() with a *conf.OIDC whose ClientID field is empty. The config struct exists but the admin never entered the client ID obtained from Google/Microsoft/GitHub/Custom provider registration.","commonSituations":"The admin configured the issuer URL and provider type but forgot to paste the client ID from the provider's developer console. A config import or sync brought over a partial OIDC config. The frontend form submitted without the client ID field but the backend did not reject it.","solutions":["Register an OAuth application with the chosen provider and copy the Client ID into SiYuan's OIDC settings.","Validate the ClientID field in the API handler before calling New() and return a 400 with a clear message.","Check the frontend form for required-field enforcement on the client ID input."],"exampleFix":"// before\nprovider, err := oidc_provider.New(ctx, config, redirectURL)\n\n// after\nif config.ClientID == \"\" {\n    return nil, fmt.Errorf(\"OIDC client ID must be set in settings\")\n}\nprovider, err := oidc_provider.New(ctx, config, redirectURL)","handlingStrategy":"validation","validationCode":"if config.ClientID == \"\" {\n    return nil, errors.New(\"OIDC client ID is required; register an OAuth app with the provider\")\n}\nprovider, err := oidc_provider.New(ctx, config, redirectURL)","typeGuard":"func hasOIDCClientID(c *conf.OIDC) bool {\n    return c != nil && c.ClientID != \"\"\n}","tryCatchPattern":null,"preventionTips":["Validate the ClientID field in the frontend settings form before submission.","In the API handler, check config.ClientID != \"\" before calling New().","Store the client ID only after verifying it is non-empty in the config save handler."],"tags":["oidc","authentication","config","validation"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}