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
- Check the wrapped error text: it names whether the CA file or the proxy URL is at fault
- For CA issues, verify the path exists and contains a valid PEM block: openssl x509 -in ca.pem -noout
- Convert DER to PEM if needed: openssl x509 -inform der -in ca.crt -out ca.pem, then point trustedCaFile at ca.pem
- For proxy issues, fix the URL as described for 'failed to parse OIDC proxy URL'
- 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
- Run openssl x509 -in <cafile> -noout in deployment scripts before starting frp
- Mount CA files read-only at fixed paths in containers
- Validate the proxy URL up front (see error 140)
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
- failed to read OIDC CA certificate file %q: %w
- failed to parse OIDC CA certificate from file %q
- failed to parse OIDC proxy URL %q: %w
- couldn't generate OIDC token for login: %v
- couldn't acquire OIDC token for login: %v
AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15).
Data as JSON: /api/errors/d03612db8d6afdb0.
Report an issue: GitHub.