fatedier/frp · error

failed to create OIDC HTTP client: %w

Error message

failed to create OIDC HTTP client: %w

What it means

When any of oidc.trustedCaFile, oidc.insecureSkipVerify, or oidc.proxyURL is configured, frpc calls createOIDCHTTPClient to build an http.Client with the custom TLS/proxy settings. This error wraps any failure inside that constructor: reading or parsing the CA certificate file, or parsing the proxy URL. It is raised at auth-provider construction time (NewOidcAuthProvider), before any connection to frps is attempted.

Source

Thrown at pkg/auth/oidc.go:161

		eps["audience"] = []string{cfg.Audience}
	}

	tokenGenerator := &clientcredentials.Config{
		ClientID:       cfg.ClientID,
		ClientSecret:   cfg.ClientSecret,
		Scopes:         []string{cfg.Scope},
		TokenURL:       cfg.TokenEndpointURL,
		EndpointParams: eps,
	}

	// Build the context that TokenSource will use for all future HTTP requests.
	// context.Background() is appropriate here because the token source is
	// long-lived and outlives any single request.
	ctx := context.Background()
	if cfg.TrustedCaFile != "" || cfg.InsecureSkipVerify || cfg.ProxyURL != "" {
		httpClient, err := createOIDCHTTPClient(cfg.TrustedCaFile, cfg.InsecureSkipVerify, cfg.ProxyURL)
		if err != nil {
			return nil, fmt.Errorf("failed to create OIDC HTTP client: %w", err)
		}
		ctx = context.WithValue(ctx, oauth2.HTTPClient, httpClient)
	}

	// Create a persistent TokenSource that caches the token and refreshes
	// it before expiry. This avoids making a new HTTP request to the OIDC
	// provider on every heartbeat/ping.
	//
	// We wrap it in an oidcTokenSource so that the first Token() call
	// (deferred to SetLogin inside the login retry loop) probes whether the
	// provider returns expires_in.  If not, it switches to a non-caching
	// source.  This avoids an eager network call at construction time, which
	// would prevent loopLoginUntilSuccess from retrying on transient IdP
	// outages.
	cachingSource := tokenGenerator.TokenSource(ctx)

	return &OidcAuthProvider{
		additionalAuthScopes: additionalAuthScopes,

View on GitHub (pinned to 6c8a8d0a97)

Solutions

  1. Check the wrapped error text: it names whether the CA file or the proxy URL is at fault
  2. For CA issues, verify the path exists and contains a valid PEM block: openssl x509 -in ca.pem -noout
  3. Convert DER to PEM if needed: openssl x509 -inform der -in ca.crt -out ca.pem, then point trustedCaFile at ca.pem
  4. For proxy issues, fix the URL as described for 'failed to parse OIDC proxy URL'
  5. Ensure the frpc process has read permission on the CA file (check ownership in containers)

Example fix

# before: file not readable / wrong format
authentication.oidc.trustedCaFile = "/etc/ca/root.crt"   # DER-encoded

# after
openssl x509 -inform der -in /etc/ca/root.crt -out /etc/frp/ca.pem
authentication.oidc.trustedCaFile = "/etc/frp/ca.pem"
Defensive patterns

Strategy: validation

Validate before calling

if cfg.TrustedCaFile != "" {
    pem, err := os.ReadFile(cfg.TrustedCaFile)
    if err != nil { return err }
    if !bytes.Contains(pem, []byte("-----BEGIN CERTIFICATE-----")) {
        return fmt.Errorf("%s is not PEM-encoded", cfg.TrustedCaFile)
    }
}

Prevention

When it happens

Trigger: Calling NewOidcAuthProvider with cfg.TrustedCaFile pointing to a nonexistent or unreadable file, a file that is not valid PEM ('failed to parse OIDC CA certificate from file'), or a ProxyURL that url.Parse rejects (see error 140).

Common situations: Mounting a corporate root CA into a container at the wrong path; the CA file is a DER-encoded or otherwise non-PEM bundle; file permissions deny the frpc process; typo in the proxy URL configured at the same time.

Related errors


AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15). Data as JSON: /api/errors/d03612db8d6afdb0. Report an issue: GitHub.