Connecting LibreChat
Point LibreChat at this service and get the two sides agreeing on authentication.
LibreChat talks to this service over plain HTTP. There are exactly two things to get right: the base URL, and the authentication settings matching on both sides.
The base URL
Point LibreChat at the API component, which listens on port 3112 and
serves everything under the /v1 prefix. Set LIBRECHAT_CODE_BASEURL to that
base URL including the /v1 suffix:
LIBRECHAT_CODE_BASEURL=http://codeapi-host:3112/v1Use the internal service name when LibreChat and this service share a Docker network or Kubernetes namespace:
LIBRECHAT_CODE_BASEURL=http://api:3112/v1Forgetting the /v1 is the single most common setup mistake. Without it every
request 404s.
Authentication
Pick one of two modes. The service decides which via CODEAPI_AUTH_PROVIDER.
The legacy X-API-Key header is no longer accepted. Outside local mode the API
requires a Bearer JWT.
The default Compose files run with LOCAL_MODE=true, which bypasses
authentication entirely. LibreChat needs only the base URL; leave its
CODEAPI_JWT_* variables unset. Nothing else is required on either side.
LIBRECHAT_CODE_BASEURL=http://localhost:3112/v1If you run with LOCAL_MODE=false but still want no authentication, say so
explicitly on the service:
LOCAL_MODE=false
CODEAPI_AUTH_PROVIDER=none
CODEAPI_ALLOW_AUTH_PROVIDER_NONE=trueWith CODEAPI_AUTH_PROVIDER=none the user id comes from the User-Id header,
falling back to the body's user_id, then anonymous. The service refuses to
start in this mode unless CODEAPI_ALLOW_AUTH_PROVIDER_NONE=true is also set.
Unauthenticated mode lets any caller execute arbitrary code. Never expose it on a public network or a shared host. Use it only on loopback or a trusted private network.
What must match on both sides
| Setting | Signer (LibreChat) | Verifier (this service) |
|---|---|---|
| Algorithm | CODEAPI_JWT_ALGORITHM=EdDSA | CODEAPI_JWT_ALLOWED_ALGS=EdDSA |
| Key id | CODEAPI_JWT_KID | CODEAPI_JWT_KID |
| Issuer | CODEAPI_JWT_ISSUER | CODEAPI_JWT_ISSUER (default librechat) |
| Audience | CODEAPI_JWT_AUDIENCE | CODEAPI_JWT_AUDIENCE (default codeapi) |
A token whose kid the verifier does not know is rejected outright. Tokens are
capped at a 300-second lifetime (CODEAPI_JWT_MAX_TTL_SECONDS) with 30 seconds
of clock skew tolerance.
Because LOCAL_MODE=true bypasses authentication entirely, JWT mode requires
LOCAL_MODE=false. Setting up JWTs while leaving local mode on gets you
unauthenticated access with extra steps.
Key rotation
Instead of a single CODEAPI_JWT_PUBLIC_KEY + CODEAPI_JWT_KID, the verifier
also accepts:
CODEAPI_JWT_JWKS_JSON(an inline JWKS documentCODEAPI_JWT_PUBLIC_KEYS_DIR) a directory of PEM files named bykid
Both let you serve several verifier keys at once, so you can introduce a new signing key before retiring the old one.
Enabling the languages you need
CODEAPI_LANGUAGES selects which runtimes get pre-installed. Installing all of
them takes a while and a fair amount of disk; if LibreChat only needs Python,
say so:
CODEAPI_LANGUAGES=pythonVerifying the connection
From the LibreChat host:
curl -s http://codeapi-host:3112/v1/healthThen a real execution. In JWT mode, mint a token the way LibreChat does and:
curl -sX POST http://codeapi-host:3112/v1/exec \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"lang":"py","code":"print(\"connected\")"}' | jqIf that returns stdout: "connected\n", both sides agree. If it returns 401,
work through the matching table: issuer,
audience, kid, and algorithm all have to line up exactly.
See Troubleshooting for specific failure modes.