Skip to content

feat: add proxy API key authentication with usage tracking#1

Draft
lmichaelwar wants to merge 9 commits intoTylerx404:mainfrom
lmichaelwar:main
Draft

feat: add proxy API key authentication with usage tracking#1
lmichaelwar wants to merge 9 commits intoTylerx404:mainfrom
lmichaelwar:main

Conversation

@lmichaelwar
Copy link

Summary

Adds a proxy authentication layer that separates client access from the upstream Z.ai API token. This allows the proxy to be shared across teams/services without exposing the actual Z.ai credential.

Motivation (The Problem)

Previously, the proxy either:

  • Ran completely open (anyone could use it), or
  • Required sharing the real Z.ai API token with every client

This created two issues:

  1. Security - The Z.ai token had to be distributed to anyone using the proxy
  2. Accountability - No way to track which team/service was using the API

Solution (What This Does)

This PR adds an independent authentication system with its own API keys that are completely separate from the Z.ai token.

  ┌─────────────┐     Proxy API Key     ┌──────────────┐     Z.ai Token     ┌─────────┐
  │   Client    │ ─────────────────────▶│   This Proxy │ ──────────────────▶│  Z.ai   │
  │             │   (your own control)  │              │   (server-side)    │  API    │
  └─────────────┘                      └──────────────┘                    └─────────┘

What's Added

  • middleware/auth.go - Validates proxy API keys on every request (except /health)
  • handlers/usage.go - Admin endpoint showing request counts per key
  • PROXY_API_KEYS env var - Configure keys in key:name format

Configuration

.env or docker-compose.yml

PROXY_API_KEYS=sk-dev-team:Development Team,sk-prod-service:Production Service

Client Usage

Before: anyone could access

curl https://proxy.example.com/v1/models

After: requires a proxy key

curl -H "Authorization: Bearer sk-dev-team" \
  https://proxy.example.com/v1/models

Usage Tracking

See request counts per key

  curl -H "Authorization: Bearer sk-dev-team" \
    https://proxy.example.com/admin/usage

Response:

  {
    "total_keys": 2,
    "keys": {
      "Development Team": {"total_requests": 1423, "last_used": "2025-01-15T12:34:56Z"},
      "Production Service": {"total_requests": 856, "last_used": "2025-01-15T12:30:00Z"}
    }
  }
  Behavior

  | Scenario             | Behavior                                               |
  |----------------------|--------------------------------------------------------|
  | PROXY_API_KEYS set   | Requires authentication; rejects invalid keys with 401 |
  | PROXY_API_KEYS empty | Open access (backward compatible)                      |
  | /health endpoint     | Always accessible, no auth required                    |

Use Cases

  • Team sharing - Give each team their own key; revoke individually
  • Service isolation - Track usage per application/service
  • Internal deployments - Deploy behind Tailscale with controlled access
  • Audit logging - See which keys are hitting which endpoints

Copilot AI and others added 9 commits December 25, 2025 02:42
Co-authored-by: lmichaelwar <20604470+lmichaelwar@users.noreply.github.com>
Co-authored-by: lmichaelwar <20604470+lmichaelwar@users.noreply.github.com>
Co-authored-by: lmichaelwar <20604470+lmichaelwar@users.noreply.github.com>
Co-authored-by: lmichaelwar <20604470+lmichaelwar@users.noreply.github.com>
Co-authored-by: lmichaelwar <20604470+lmichaelwar@users.noreply.github.com>
Co-authored-by: lmichaelwar <20604470+lmichaelwar@users.noreply.github.com>
…e-key

Add Tailscale sidecar with ephemeral auth key support
Add a separate authentication layer for proxy access, keeping the
Z.ai token server-side. Clients now use independent proxy API keys
that can be tracked and managed separately.

Features:
- Proxy API key authentication middleware
- Usage tracking per key (request count, last used)
- Admin endpoint at /admin/usage for stats
- Configurable via PROXY_API_KEYS env var (key:name format)
- Graceful fallback to open access if no keys configured

Security benefits:
- Z.ai token never exposed to clients
- Revocable per-service credentials
- Audit trail for usage per team/service

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings January 15, 2026 21:09
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a proxy authentication layer with API key management and usage tracking, alongside comprehensive Tailscale integration for secure private networking. The authentication system separates client-facing API keys from the upstream Z.ai token, enabling multi-tenant access control and usage monitoring.

Changes:

  • Introduces proxy API key authentication middleware with concurrent-safe usage tracking
  • Adds admin endpoint for viewing per-key usage statistics
  • Integrates Tailscale VPN with Docker sidecar pattern and ephemeral auth keys
  • Provides multiple deployment configurations (local, Tailscale, override patterns)

Reviewed changes

Copilot reviewed 13 out of 14 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
middleware/auth.go New authentication middleware with singleton pattern, API key validation, and usage tracking
handlers/usage.go New admin endpoint for retrieving usage statistics per API key
main.go Integrates auth middleware into request pipeline and adds startup logging
config/config.go Adds proxy key parsing from environment variable in key:name format
docker/tailscale-entrypoint.sh Tailscale initialization script with validation and monitoring
docker-compose.yml Main compose file with Tailscale sidecar and network sharing
docker-compose.local.yml Local development compose without Tailscale
docker-compose.override.yml.example Example override for exposing ports or disabling Tailscale
Dockerfile.tailscale Tailscale sidecar container image
.env.example Updated with proxy keys and Tailscale configuration examples
README.md Added Tailscale setup and configuration documentation
TAILSCALE.md Comprehensive Tailscale integration guide
QUICKSTART.md Quick start guide for Tailscale deployment
.gitignore Excludes docker-compose.override.yml

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

network_mode: "service:tailscale"
environment:
- TOKEN=
- TOKEN=125a583265464446be50412ef8701d72.tBGGNJmAQMvOhvXO
Copy link

Copilot AI Jan 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A production Z.ai API token is hardcoded in the docker-compose.yml file. This is a security risk as it exposes the actual API credential in version control. The token should be removed and referenced from environment variables instead (e.g., - TOKEN=${TOKEN} or - TOKEN=).

Suggested change
- TOKEN=125a583265464446be50412ef8701d72.tBGGNJmAQMvOhvXO
- TOKEN=${TOKEN}

Copilot uses AI. Check for mistakes.
ports:
- "8080:8080"
environment:
- TOKEN=125a583265464446be50412ef8701d72.tBGGNJmAQMvOhvXO
Copy link

Copilot AI Jan 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A production Z.ai API token is hardcoded in the docker-compose.local.yml file. This should be removed and replaced with an environment variable reference (e.g., - TOKEN=${TOKEN} or - TOKEN=) to prevent credential exposure.

Suggested change
- TOKEN=125a583265464446be50412ef8701d72.tBGGNJmAQMvOhvXO
- TOKEN=${TOKEN}

Copilot uses AI. Check for mistakes.
environment:
- TOKEN=
- TOKEN=125a583265464446be50412ef8701d72.tBGGNJmAQMvOhvXO
- PROXY_API_KEYS=sk-internal-dev:Internal Dev Team,sk-prod-service:Production Service
Copy link

Copilot AI Jan 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Example proxy API keys are hardcoded in the docker-compose.yml file. While these appear to be examples, they should be removed or replaced with environment variable references (e.g., - PROXY_API_KEYS=${PROXY_API_KEYS}) to avoid accidentally committing real keys and to encourage proper configuration practices.

Suggested change
- PROXY_API_KEYS=sk-internal-dev:Internal Dev Team,sk-prod-service:Production Service
- PROXY_API_KEYS=${PROXY_API_KEYS}

Copilot uses AI. Check for mistakes.
- "8080:8080"
environment:
- TOKEN=125a583265464446be50412ef8701d72.tBGGNJmAQMvOhvXO
- PROXY_API_KEYS=sk-internal-dev:Internal Dev Team,sk-prod-service:Production Service
Copy link

Copilot AI Jan 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Example proxy API keys are hardcoded in docker-compose.local.yml. Replace with environment variable reference (e.g., - PROXY_API_KEYS=${PROXY_API_KEYS}) to avoid accidentally using example keys in production or committing real keys.

Suggested change
- PROXY_API_KEYS=sk-internal-dev:Internal Dev Team,sk-prod-service:Production Service
- PROXY_API_KEYS=${PROXY_API_KEYS}

Copilot uses AI. Check for mistakes.
)

// UsageHandler returns usage statistics for proxy API keys
func UsageHandler(w http.ResponseWriter, r *http.Request) {
Copy link

Copilot AI Jan 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The UsageHandler does not validate the HTTP method. It should only accept GET requests for retrieving usage statistics. Add method validation at the beginning: if r.Method != http.MethodGet { w.WriteHeader(http.StatusMethodNotAllowed); return }

Suggested change
func UsageHandler(w http.ResponseWriter, r *http.Request) {
func UsageHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
w.WriteHeader(http.StatusMethodNotAllowed)
return
}

Copilot uses AI. Check for mistakes.
# - Optional =value with safe characters (alphanumeric, hyphen, underscore, comma, dot, colon, slash)
# - Flags separated by spaces
# This strict pattern prevents injection while allowing legitimate Tailscale flags
if ! echo "${TS_EXTRA_ARGS}" | grep -qE '^[[:space:]]*(--[a-zA-Z0-9_-]+(=[a-zA-Z0-9._,:/\\-]+)?[[:space:]]*)+$'; then
Copy link

Copilot AI Jan 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The regex pattern allows backslash in the character class [a-zA-Z0-9._,:/\\-], but the backslash escaping may not work as intended in this context. The pattern should either use [a-zA-Z0-9._,:/-] (without backslash support) or properly escape it. Additionally, the comment on line 51 mentions allowing slash but the actual use case for backslash in Tailscale flags is unclear.

Suggested change
if ! echo "${TS_EXTRA_ARGS}" | grep -qE '^[[:space:]]*(--[a-zA-Z0-9_-]+(=[a-zA-Z0-9._,:/\\-]+)?[[:space:]]*)+$'; then
if ! echo "${TS_EXTRA_ARGS}" | grep -qE '^[[:space:]]*(--[a-zA-Z0-9_-]+(=[a-zA-Z0-9._,:/-]+)?[[:space:]]*)+$'; then

Copilot uses AI. Check for mistakes.
func (am *AuthMiddleware) AuthHandler(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Skip auth for health endpoint
if r.URL.Path == "/health" {
Copy link

Copilot AI Jan 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The health endpoint path is hardcoded as a string literal. Consider defining it as a constant (e.g., const HealthEndpoint = \"/health\") for better maintainability and consistency across the codebase.

Copilot uses AI. Check for mistakes.
@lmichaelwar lmichaelwar marked this pull request as draft January 15, 2026 23:06
@lmichaelwar
Copy link
Author

@copilot Can you review my fork of the zai proxy and check if it's suitable for this upstream PR?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants