Tencent/WeKnora · error

cannot verify OIDC id_token: client_id is not configured

Error message

cannot verify OIDC id_token: client_id is not configured

What it means

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.

Solutions

  1. Set ClientID in the OIDC config to the client identifier registered with the provider.
  2. Verify the env/config key mapping (e.g. OIDC_CLIENT_ID) is populated in the deployment environment.
  3. Cross-check the provider's client registration so client_id matches the one minting the tokens.
  4. Add startup validation that fails fast when required OIDC config fields are empty.

Example fix

// before
client_id: ""
// after
client_id: "my-app-client"
Defensive patterns

Strategy: validation

Validate before calling

if strings.TrimSpace(cfg.ClientID) == "" {
    return errors.New("oidc client_id is required for audience validation")
}

Type guard

func clientIDConfigured(c config.OIDCAuthConfig) bool {
    return strings.TrimSpace(c.ClientID) != ""
}

Prevention

When it happens

Trigger: OIDCAuthConfig reaching verifyOIDCIDToken has empty/whitespace ClientID; LoginWithOIDC called with a partially filled config (JwksURI/IssuerURL set but client_id missing).

Common situations: 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.

Understand the failure class

Background: "missing required config value" errors: why libraries refuse to start when a configuration key is empty, unset, or blank — this error's family across 48 libraries.

Related errors


AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02). Data as JSON: /api/errors/d9c7777458403453. Report an issue: GitHub.

Appendix: source

Thrown at internal/application/service/user.go:1948

	return &jwks, nil
}

const oidcIDTokenLeeway = 2 * time.Minute

// verifyOIDCIDToken cryptographically verifies an OIDC id_token: it checks the
// RSA signature against the provider's JWKS (matched by kid) and validates the
// issuer, audience (client_id), expiry and subject. It returns the verified claims.
func (s *userService) verifyOIDCIDToken(
	ctx context.Context, cfg *config.OIDCAuthConfig, idToken string,
) (map[string]interface{}, error) {
	if strings.TrimSpace(cfg.JwksURI) == "" {
		return nil, errors.New("cannot verify OIDC id_token: no jwks_uri configured")
	}
	if strings.TrimSpace(cfg.IssuerURL) == "" {
		return nil, errors.New("cannot verify OIDC id_token: issuer is not configured")
	}
	if strings.TrimSpace(cfg.ClientID) == "" {
		return nil, errors.New("cannot verify OIDC id_token: client_id is not configured")
	}

	jwks, err := s.fetchOIDCJWKS(ctx, cfg.JwksURI)
	if err != nil {
		return nil, err
	}

	keyFunc := func(token *jwt.Token) (interface{}, error) {
		if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
			return nil, fmt.Errorf("unexpected id_token signing method: %v", token.Header["alg"])
		}
		kid, _ := token.Header["kid"].(string)
		return jwks.rsaKeyForKid(kid)
	}

	claims := jwt.MapClaims{}
	if _, err := jwt.NewParser(
		jwt.WithValidMethods([]string{"RS256", "RS384", "RS512"}),

View on GitHub (pinned to 988cbb0330)