What is PROXYACCESSKEY in CCX? Secure Proxy Authentication Explained
PROXYACCESSKEY is the environment variable that acts as the master API key for the CCX proxy layer, authorizing requests via the x-api-key header or Authorization: Bearer token before they reach downstream AI endpoints.
CCX (BenedictKing/ccx) is an open-source AI gateway that routes requests to various language models while centralizing authentication. Unlike complex OAuth flows, CCX uses a single, configurable secret—PROXYACCESSKEY—to protect its public HTTP endpoints. This lightweight mechanism ensures that only clients possessing the correct key can traverse the proxy and access the underlying AI APIs.
Where PROXYACCESSKEY is Defined
In the CCX codebase, the proxy access key is declared in the backend environment configuration files.
- Example configuration file:
backend-go/.env.example - Runtime configuration:
backend-go/.env(created by copying the example)
The variable is read at application startup using Go's os.Getenv() and stored in memory for request validation.
How the Proxy Authentication Middleware Works
The core validation logic resides in backend-go/internal/middleware/auth.go. Here, the ProxyAuthMiddleware() function implements constant-time comparison to prevent timing attacks.
The Middleware Logic
// backend-go/internal/middleware/auth.go
func ProxyAuthMiddleware() gin.HandlerFunc {
// Load the secret from the environment (set in .env or the container)
proxyKey := os.Getenv("PROXYACCESSKEY")
return func(c *gin.Context) {
// Accept the key via header "x-api-key" or Bearer token
incoming := c.GetHeader("x-api-key")
if incoming == "" {
if authHeader := c.GetHeader("Authorization"); strings.HasPrefix(authHeader, "Bearer ") {
incoming = strings.TrimPrefix(authHeader, "Bearer ")
}
}
// Reject if the key is missing or does not match the stored secret
if incoming == "" || subtle.ConstantTimeCompare([]byte(incoming), []byte(proxyKey)) != 1 {
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{
"error": "invalid proxy access key",
})
return
}
// Continue to the next handler when the key is valid
c.Next()
}
}
Key implementation details from the source:
subtle.ConstantTimeCompareensures the comparison takes constant time regardless of where the strings differ, mitigating timing-based key enumeration attacks.- Dual header support: The middleware checks
x-api-keyfirst, then falls back to parsing theAuthorizationheader for Bearer tokens. - 401 Unauthorized: Any request lacking the key or presenting a mismatch is immediately rejected with a JSON error response.
Route Protection Implementation
The ProxyAuthMiddleware() is wired into the Gin router in backend-go/main.go and applied to public-facing handlers. According to the source analysis, protected routes include those defined in:
This means all chat completion and frontend API requests must present the PROXYACCESSKEY before reaching the downstream AI provider logic.
Configuring PROXYACCESSKEY
To enable proxy authentication in your deployment:
-
Copy the example environment file:
cp backend-go/.env.example backend-go/.env -
Generate and set a strong secret in
backend-go/.env:PROXYACCESSKEY=your-very-secret-32-char-tokenUse a cryptographically secure random string (minimum 32 characters recommended).
-
Restart the service to load the new environment variable. In development mode, the hot-reload mechanism will detect the change; in production, restart the container or binary.
Verifying Your Configuration
Test the middleware using curl:
Valid request (returns 200 or downstream response):
curl -H "x-api-key: your-very-secret-32-char-token" \
http://localhost:8080/v1/chat/completions
Invalid request (returns 401 Unauthorized):
curl http://localhost:8080/v1/chat/completions
The second command should return a JSON error: {"error":"invalid proxy access key"}.
Summary
- PROXYACCESSKEY (no underscore) is the canonical environment variable name in the CCX Go backend, despite the common alternate spelling
PROXY_ACCESS_KEY. - It serves as the single source of truth for proxy-layer authentication, replacing complex OAuth with a simple API key.
- The middleware in
backend-go/internal/middleware/auth.govalidates every incoming request using constant-time comparison against this key. - Routes in
backend-go/internal/handlers/frontend.goand conversation handlers are protected by default; requests without the key receive a 401 Unauthorized response.
Frequently Asked Questions
Is PROXYACCESSKEY the same as PROXY_ACCESS_KEY?
No. The CCX source code specifically looks for the environment variable PROXYACCESSKEY without underscores. While documentation or Issue trackers might refer to it as PROXY_ACCESS_KEY colloquially, the actual implementation in backend-go/internal/middleware/auth.go uses os.Getenv("PROXYACCESSKEY"). Always use the non-underscore version in your .env files.
What happens if I leave PROXYACCESSKEY empty or unset?
If the variable is undefined or empty, the ProxyAuthMiddleware() will compare incoming requests against an empty string. Consequently, only requests with an empty x-api-key header would pass (which is functionally useless), or more likely, all requests will fail validation and return 401 Unauthorized. Always define a non-empty value before exposing the service to the internet.
How should I generate a secure PROXYACCESSKEY?
Generate a cryptographically secure random string of at least 32 characters. You can use OpenSSL:
openssl rand -hex 32
Treat this key like a password: store it in a secrets manager, avoid committing it to version control, and rotate it if you suspect compromise.
Can I rotate PROXYACCESSKEY without downtime?
Rotation requires restarting the CCX backend service because the value is read once at startup and held in memory. To rotate without downtime, deploy a new instance with the new key, update your client configurations, then decommission the old instance. There is no hot-reload mechanism for this specific secret in the current codebase.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →