feat: add API key authentication for /v1/* endpoints
This commit is contained in:
@@ -332,6 +332,7 @@ While most users can use the default settings, you can tune the proxy behavior v
|
|||||||
|
|
||||||
### Configurable Options
|
### 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.
|
- **WebUI Password**: Secure your dashboard with `WEBUI_PASSWORD` env var or in config.
|
||||||
- **Custom Port**: Change the default `8080` port.
|
- **Custom Port**: Change the default `8080` port.
|
||||||
- **Retry Logic**: Configure `maxRetries`, `retryBaseMs`, and `retryMaxMs`.
|
- **Retry Logic**: Configure `maxRetries`, `retryBaseMs`, and `retryMaxMs`.
|
||||||
|
|||||||
@@ -11,6 +11,9 @@
|
|||||||
"Restart server after making changes"
|
"Restart server after making changes"
|
||||||
],
|
],
|
||||||
|
|
||||||
|
"apiKey": "",
|
||||||
|
"_apiKey_comment": "Optional API key to protect /v1/* endpoints. Can also use API_KEY env var.",
|
||||||
|
|
||||||
"webuiPassword": "",
|
"webuiPassword": "",
|
||||||
"_webuiPassword_comment": "Optional password to protect WebUI. Can also use WEBUI_PASSWORD env var.",
|
"_webuiPassword_comment": "Optional password to protect WebUI. Can also use WEBUI_PASSWORD env var.",
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { logger } from './utils/logger.js';
|
|||||||
|
|
||||||
// Default config
|
// Default config
|
||||||
const DEFAULT_CONFIG = {
|
const DEFAULT_CONFIG = {
|
||||||
|
apiKey: '',
|
||||||
webuiPassword: '',
|
webuiPassword: '',
|
||||||
debug: false,
|
debug: false,
|
||||||
logLevel: 'info',
|
logLevel: 'info',
|
||||||
@@ -54,6 +55,7 @@ function loadConfig() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Environment overrides
|
// 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.WEBUI_PASSWORD) config.webuiPassword = process.env.WEBUI_PASSWORD;
|
||||||
if (process.env.DEBUG === 'true') config.debug = true;
|
if (process.env.DEBUG === 'true') config.debug = true;
|
||||||
|
|
||||||
|
|||||||
@@ -65,6 +65,37 @@ async function ensureInitialized() {
|
|||||||
app.use(cors());
|
app.use(cors());
|
||||||
app.use(express.json({ limit: REQUEST_BODY_LIMIT }));
|
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
|
// Setup usage statistics middleware
|
||||||
usageStats.setupMiddleware(app);
|
usageStats.setupMiddleware(app);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user