feat(auth): add api key authentication
Implement API key authentication by introducing a new auth module. Update configuration and .env.example to support API key setup, and add authorization checks in the server endpoints.
This commit is contained in:
@@ -1,2 +1,3 @@
|
|||||||
PORT=11434
|
PORT=11434
|
||||||
VERBOSE=false
|
VERBOSE=false
|
||||||
|
API_KEY=MY0P3NA1K3Y
|
||||||
38
src/auth.ts
Normal file
38
src/auth.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/**
|
||||||
|
* @fileoverview This file contains the authentication logic for the server.
|
||||||
|
*/
|
||||||
|
import http from 'http';
|
||||||
|
import { config } from './config';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks for API key authentication.
|
||||||
|
* @param req - The HTTP incoming message object.
|
||||||
|
* @param res - The HTTP server response object.
|
||||||
|
* @returns True if the request is authorized, false otherwise.
|
||||||
|
*/
|
||||||
|
export function isAuthorized(
|
||||||
|
req: http.IncomingMessage,
|
||||||
|
res: http.ServerResponse,
|
||||||
|
): boolean {
|
||||||
|
if (!config.API_KEY) {
|
||||||
|
return true; // No key configured, public access.
|
||||||
|
}
|
||||||
|
|
||||||
|
const authHeader = req.headers.authorization;
|
||||||
|
if (!authHeader) {
|
||||||
|
res.writeHead(401, { 'Content-Type': 'application/json' });
|
||||||
|
res.end(
|
||||||
|
JSON.stringify({ error: { message: 'Missing Authorization header' } }),
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const token = authHeader.split(' ')[1];
|
||||||
|
if (token !== config.API_KEY) {
|
||||||
|
res.writeHead(401, { 'Content-Type': 'application/json' });
|
||||||
|
res.end(JSON.stringify({ error: { message: 'Invalid API key' } }));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
@@ -23,4 +23,10 @@ export const config = {
|
|||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
*/
|
*/
|
||||||
VERBOSE: Boolean(process.env.VERBOSE ?? true),
|
VERBOSE: Boolean(process.env.VERBOSE ?? true),
|
||||||
|
/**
|
||||||
|
* The API key for securing the server.
|
||||||
|
* If not set, the server will be public.
|
||||||
|
* @type {string | undefined}
|
||||||
|
*/
|
||||||
|
API_KEY: process.env.API_KEY,
|
||||||
};
|
};
|
||||||
@@ -8,6 +8,7 @@ import { listModels, sendChat, sendChatStream } from './chatwrapper';
|
|||||||
import { mapRequest, mapResponse, mapStreamChunk } from './mapper.js';
|
import { mapRequest, mapResponse, mapStreamChunk } from './mapper.js';
|
||||||
import { RequestBody, GeminiResponse, GeminiStreamChunk, Part } from './types';
|
import { RequestBody, GeminiResponse, GeminiStreamChunk, Part } from './types';
|
||||||
import { config } from './config';
|
import { config } from './config';
|
||||||
|
import { isAuthorized } from './auth';
|
||||||
|
|
||||||
// ==================================================================
|
// ==================================================================
|
||||||
// Server Configuration
|
// Server Configuration
|
||||||
@@ -97,6 +98,10 @@ http
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isAuthorized(req, res)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Route for listing available models.
|
// Route for listing available models.
|
||||||
if (pathname === '/v1/models' || pathname === '/models') {
|
if (pathname === '/v1/models' || pathname === '/models') {
|
||||||
res.writeHead(200, { 'Content-Type': 'application/json' });
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
||||||
|
|||||||
Reference in New Issue
Block a user