From 6172f5ef10ae81b9ba1f50b5c3cebccd4e9b355e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=91=A3=E9=A3=9E=E7=A5=A5?= Date: Tue, 13 Jan 2026 16:46:31 +0800 Subject: [PATCH] feat: add API key authentication for /v1/* endpoints --- README.md | 1 + config.example.json | 3 +++ src/config.js | 2 ++ src/server.js | 31 +++++++++++++++++++++++++++++++ 4 files changed, 37 insertions(+) diff --git a/README.md b/README.md index 4e79bf5..6778fdf 100644 --- a/README.md +++ b/README.md @@ -332,6 +332,7 @@ While most users can use the default settings, you can tune the proxy behavior v ### Configurable Options +- **API Key Authentication**: Protect `/v1/*` API endpoints with `API_KEY` env var or `apiKey` in config. - **WebUI Password**: Secure your dashboard with `WEBUI_PASSWORD` env var or in config. - **Custom Port**: Change the default `8080` port. - **Retry Logic**: Configure `maxRetries`, `retryBaseMs`, and `retryMaxMs`. diff --git a/config.example.json b/config.example.json index e49cc73..e507015 100644 --- a/config.example.json +++ b/config.example.json @@ -11,6 +11,9 @@ "Restart server after making changes" ], + "apiKey": "", + "_apiKey_comment": "Optional API key to protect /v1/* endpoints. Can also use API_KEY env var.", + "webuiPassword": "", "_webuiPassword_comment": "Optional password to protect WebUI. Can also use WEBUI_PASSWORD env var.", diff --git a/src/config.js b/src/config.js index 42ef525..6c81c32 100644 --- a/src/config.js +++ b/src/config.js @@ -5,6 +5,7 @@ import { logger } from './utils/logger.js'; // Default config const DEFAULT_CONFIG = { + apiKey: '', webuiPassword: '', debug: false, logLevel: 'info', @@ -54,6 +55,7 @@ function loadConfig() { } // Environment overrides + if (process.env.API_KEY) config.apiKey = process.env.API_KEY; if (process.env.WEBUI_PASSWORD) config.webuiPassword = process.env.WEBUI_PASSWORD; if (process.env.DEBUG === 'true') config.debug = true; diff --git a/src/server.js b/src/server.js index 0178d7d..be2c3af 100644 --- a/src/server.js +++ b/src/server.js @@ -65,6 +65,37 @@ async function ensureInitialized() { app.use(cors()); app.use(express.json({ limit: REQUEST_BODY_LIMIT })); +// API Key authentication middleware for /v1/* endpoints +app.use('/v1', (req, res, next) => { + // Skip validation if apiKey is not configured + if (!config.apiKey) { + return next(); + } + + const authHeader = req.headers['authorization']; + const xApiKey = req.headers['x-api-key']; + + let providedKey = ''; + if (authHeader && authHeader.startsWith('Bearer ')) { + providedKey = authHeader.substring(7); + } else if (xApiKey) { + providedKey = xApiKey; + } + + if (!providedKey || providedKey !== config.apiKey) { + logger.warn(`[API] Unauthorized request from ${req.ip}, invalid API key`); + return res.status(401).json({ + type: 'error', + error: { + type: 'authentication_error', + message: 'Invalid or missing API key' + } + }); + } + + next(); +}); + // Setup usage statistics middleware usageStats.setupMiddleware(app);