Skip to content

OpenAI SDK v5 ignores NODE_EXTRA_CA_CERTS — custom CA certificates not working in enterprise environments #1758

@diallo-bocar

Description

@diallo-bocar

Confirm this is a feature request for the Node library and not the underlying OpenAI API.

  • This is a feature request for the Node library

Describe the feature or improvement you're requesting

Describe the issue

The OpenAI SDK v5 uses undici internally for HTTP requests. undici's fetch() does not respect NODE_EXTRA_CA_CERTS (nodejs/undici#2200), which means enterprise users behind corporate TLS inspection proxies or connecting to endpoints with private CA certificates cannot establish connections.

Setting NODE_TLS_REJECT_UNAUTHORIZED=0 works (confirming the endpoint is reachable), but this disables all TLS verification and is not acceptable for production.

Environment

  • openai SDK version: 5.20.2
  • Node.js version: 22.x
  • Framework: Next.js 14.x (server-side)
  • OS: Linux (also reproduced on Windows/WSL2)

Steps to reproduce

  1. Set NODE_EXTRA_CA_CERTS=/path/to/corporate-ca-chain.pem
  2. Create an OpenAI client pointing to an endpoint with a certificate signed by the corporate CA:
const openai = new OpenAI({
  apiKey: "...",
  baseURL: "https://internal-llm-endpoint.example.com/v1/",
});

await openai.chat.completions.create({ ... });
  1. The request fails with:
Error: Connection error.
  cause: Error: unable to verify the first certificate
  code: UNABLE_TO_VERIFY_LEAF_SIGNATURE
  1. Setting NODE_TLS_REJECT_UNAUTHORIZED=0 makes it work, confirming the issue is with CA certificate loading, not connectivity.

Root cause

The OpenAI SDK v5 uses undici for HTTP, and undici's fetch() does not honor NODE_EXTRA_CA_CERTS (see nodejs/undici#2200). The SDK's fetchOptions: { dispatcher } option also doesn't work in Next.js environments because Next.js patches globalThis.fetch, silently dropping the undici dispatcher option.

Workaround

The solution is to pass an explicit fetch function using undici.fetch directly (bypassing the patched global fetch) with a singleton dispatcher carrying the custom CA certificates:

import { OpenAI } from "openai";
import * as fs from "fs";
import * as tls from "tls";

// Load custom CA and combine with Node.js root certificates
const customCaPath = process.env.NODE_EXTRA_CA_CERTS;
const customCa = customCaPath ? fs.readFileSync(customCaPath) : undefined;
const combinedCa = customCa ? [...tls.rootCertificates, customCa] : undefined;

// Lazy-load undici to avoid "File is not defined" during Next.js build on Node.js 18
let _dispatcher: any;
let _fetch: any;
let _initialized = false;

function ensureUndici() {
  if (_initialized) return;
  _initialized = true;
  if (!combinedCa) return;
  const undici = require("undici");
  _dispatcher = new undici.Agent({ connect: { ca: combinedCa } });
  _fetch = undici.fetch;
}

// When creating the client:
ensureUndici();

const openai = new OpenAI({
  apiKey: "...",
  baseURL: "https://internal-llm-endpoint.example.com/v1/",
  fetch: _dispatcher
    ? async (url, init) => {
        return _fetch(url, { ...init, dispatcher: _dispatcher });
      }
    : undefined,
});

Key details for the workaround

  1. Combine CAs: When providing ca to undici's Agent, it replaces the default trust store. You must combine your custom CA with tls.rootCertificates or public HTTPS endpoints will break.

  2. Singleton dispatcher: Create the undici.Agent once and reuse it. Creating a new one per request defeats connection pooling.

  3. Explicit undici fetch: Passing fetchOptions: { dispatcher } does NOT work in Next.js because Next.js replaces globalThis.fetch. You must pass a custom fetch function that calls undici.fetch directly.

  4. Lazy-load undici: undici v7 references File at the module level, which doesn't exist in Node.js 18. Use require() inside a function instead of a top-level import to avoid build failures.

  5. Full CA chain: The PEM file must contain the full CA chain (intermediate + root CAs), not the server's leaf certificate.

Suggestion

It would be helpful if the OpenAI SDK could:

  1. Respect NODE_EXTRA_CA_CERTS natively by reading the env var and configuring its internal undici dispatcher automatically
  2. Document the workaround for enterprise users who need custom CA certificates
  3. Ensure fetchOptions: { dispatcher } works reliably regardless of framework-level fetch patching (e.g., by using undici's fetch internally rather than globalThis.fetch)

Related issues

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions