{"record":{"id":"d9c7777458403453","repo":"Tencent/WeKnora","slug":"cannot-verify-oidc-id-token-client-id-is-not-conf","errorCode":null,"errorMessage":"cannot verify OIDC id_token: client_id is not configured","messagePattern":"cannot verify OIDC id_token: client_id is not configured","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/application/service/user.go","lineNumber":1948,"sourceCode":"\treturn &jwks, nil\n}\n\nconst oidcIDTokenLeeway = 2 * time.Minute\n\n// verifyOIDCIDToken cryptographically verifies an OIDC id_token: it checks the\n// RSA signature against the provider's JWKS (matched by kid) and validates the\n// issuer, audience (client_id), expiry and subject. It returns the verified claims.\nfunc (s *userService) verifyOIDCIDToken(\n\tctx context.Context, cfg *config.OIDCAuthConfig, idToken string,\n) (map[string]interface{}, error) {\n\tif strings.TrimSpace(cfg.JwksURI) == \"\" {\n\t\treturn nil, errors.New(\"cannot verify OIDC id_token: no jwks_uri configured\")\n\t}\n\tif strings.TrimSpace(cfg.IssuerURL) == \"\" {\n\t\treturn nil, errors.New(\"cannot verify OIDC id_token: issuer is not configured\")\n\t}\n\tif strings.TrimSpace(cfg.ClientID) == \"\" {\n\t\treturn nil, errors.New(\"cannot verify OIDC id_token: client_id is not configured\")\n\t}\n\n\tjwks, err := s.fetchOIDCJWKS(ctx, cfg.JwksURI)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tkeyFunc := func(token *jwt.Token) (interface{}, error) {\n\t\tif _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {\n\t\t\treturn nil, fmt.Errorf(\"unexpected id_token signing method: %v\", token.Header[\"alg\"])\n\t\t}\n\t\tkid, _ := token.Header[\"kid\"].(string)\n\t\treturn jwks.rsaKeyForKid(kid)\n\t}\n\n\tclaims := jwt.MapClaims{}\n\tif _, err := jwt.NewParser(\n\t\tjwt.WithValidMethods([]string{\"RS256\", \"RS384\", \"RS512\"}),","sourceCodeStart":1930,"sourceCodeEnd":1966,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/application/service/user.go#L1930-L1966","documentation":"id_token audience validation requires cfg.ClientID: the service checks the token's aud claim against the configured client_id. Without it, tokens cannot be confirmed as intended for this application, so verification fails immediately.","triggerScenarios":"OIDCAuthConfig reaching verifyOIDCIDToken has empty/whitespace ClientID; LoginWithOIDC called with a partially filled config (JwksURI/IssuerURL set but client_id missing).","commonSituations":"Client secret configured but client_id left blank (or vice versa); renamed env vars not mapped to the client_id field; new OIDC provider onboarded with an incomplete config; secret-manager injected only the secret.","solutions":["Set ClientID in the OIDC config to the client identifier registered with the provider.","Verify the env/config key mapping (e.g. OIDC_CLIENT_ID) is populated in the deployment environment.","Cross-check the provider's client registration so client_id matches the one minting the tokens.","Add startup validation that fails fast when required OIDC config fields are empty."],"exampleFix":"// before\nclient_id: \"\"\n// after\nclient_id: \"my-app-client\"","handlingStrategy":"validation","validationCode":"if strings.TrimSpace(cfg.ClientID) == \"\" {\n    return errors.New(\"oidc client_id is required for audience validation\")\n}","typeGuard":"func clientIDConfigured(c config.OIDCAuthConfig) bool {\n    return strings.TrimSpace(c.ClientID) != \"\"\n}","tryCatchPattern":null,"preventionTips":["Verify OIDC_CLIENT_ID (or equivalent env key) is present in every deployment environment.","Fail fast at startup if client_id is blank.","Keep client_id and client secret paired in the same config source so one is never set without the other."],"tags":["oidc","configuration","client-id","audience"],"backgroundTag":"missing-config-value","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}