From 0b8a253ff3f3cbbe38013e5d80615dacbfa6646a Mon Sep 17 00:00:00 2001 From: Vigneshraj Sekar Babu Date: Thu, 21 Aug 2025 10:42:24 -0700 Subject: [PATCH 1/3] flag to disable auth for api - default requireAuth value is false - figure out how to handle auth on client side components --- src/pages/api/v1/admin/api-keys/index.ts | 25 ++++++++++++++--------- src/server/lib/auth/validate.ts | 12 +++++++---- src/server/services/auth.ts | 1 + src/server/services/types/globalConfig.ts | 1 + 4 files changed, 25 insertions(+), 14 deletions(-) diff --git a/src/pages/api/v1/admin/api-keys/index.ts b/src/pages/api/v1/admin/api-keys/index.ts index 30d48507..46f33794 100644 --- a/src/pages/api/v1/admin/api-keys/index.ts +++ b/src/pages/api/v1/admin/api-keys/index.ts @@ -264,18 +264,23 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) // Bootstrap mode: Allow first API key creation with bootstrap token if (req.method === 'POST') { - const hasKeys = await authService.hasApiKeys(); + const config = await authService.getApiConfig(); - if (!hasKeys) { - const providedToken = req.headers['x-bootstrap-token'] as string; - const bootstrapToken = process.env.APP_BOOTSTRAP_TOKEN; + // Skip bootstrap check if auth is disabled globally + if (config.requireAuth) { + const hasKeys = await authService.hasApiKeys(); - if (bootstrapToken && providedToken === bootstrapToken) { - logger.info('Bootstrap mode: Creating first API key with bootstrap token'); - return await handleCreateApiKey(req, res, authService); - } else { - logger.warn('Bootstrap mode: Invalid or missing bootstrap token'); - return res.status(401).json({ error: 'Unauthorized' }); + if (!hasKeys) { + const providedToken = req.headers['x-bootstrap-token'] as string; + const bootstrapToken = process.env.APP_BOOTSTRAP_TOKEN; + + if (bootstrapToken && providedToken === bootstrapToken) { + logger.info('Bootstrap mode: Creating first API key with bootstrap token'); + return await handleCreateApiKey(req, res, authService); + } else { + logger.warn('Bootstrap mode: Invalid or missing bootstrap token'); + return res.status(401).json({ error: 'Unauthorized' }); + } } } } diff --git a/src/server/lib/auth/validate.ts b/src/server/lib/auth/validate.ts index 6cd71a51..9fdf9eaf 100644 --- a/src/server/lib/auth/validate.ts +++ b/src/server/lib/auth/validate.ts @@ -34,6 +34,14 @@ export async function validateAuth( res: NextApiResponse ): Promise<{ valid: boolean; apiKey?: ApiKey }> { try { + const authService = new AuthService(); + const config = await authService.getApiConfig(); + + // Skip all authentication and rate limiting if requireAuth is false + if (!config.requireAuth) { + return { valid: true }; + } + const authHeader = req.headers.authorization as string; if (!authHeader || !authHeader.startsWith('Bearer ')) { logger.error('Missing or invalid Authorization header'); @@ -43,10 +51,6 @@ export async function validateAuth( const apiKeyString = authHeader.substring(7); // Remove 'Bearer ' prefix - const authService = new AuthService(); - - const config = await authService.getApiConfig(); - const apiKey = await authService.validateApiKey(apiKeyString); if (!apiKey) { diff --git a/src/server/services/auth.ts b/src/server/services/auth.ts index 0c6031db..3197a82c 100644 --- a/src/server/services/auth.ts +++ b/src/server/services/auth.ts @@ -29,6 +29,7 @@ const DEFAULT_API_CONFIG: ApiConfig = { rate_limit: 1000, rate_limit_window: 600, bcrypt_rounds: 12, + requireAuth: false, }; export interface CreateApiKeyOptions { diff --git a/src/server/services/types/globalConfig.ts b/src/server/services/types/globalConfig.ts index 46e77d85..d069baa4 100644 --- a/src/server/services/types/globalConfig.ts +++ b/src/server/services/types/globalConfig.ts @@ -151,4 +151,5 @@ export type ApiConfig = { rate_limit: number; rate_limit_window: number; bcrypt_rounds: number; + requireAuth: boolean; }; From 51d40b3194e2f4e5fb569c60f0d94e70282f0445 Mon Sep 17 00:00:00 2001 From: Vigneshraj Sekar Babu Date: Thu, 21 Aug 2025 10:58:34 -0700 Subject: [PATCH 2/3] update middleware --- src/middleware.ts | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/src/middleware.ts b/src/middleware.ts index b28706cc..71488828 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -38,9 +38,6 @@ function isPublicApiRoute(pathname: string): boolean { return PUBLIC_API_ROUTES.some((route) => pathname.startsWith(route)); } -/** - * Extract API key from request headers - */ function extractApiKey(request: NextRequest): string | null { const authHeader = request.headers.get('authorization'); @@ -48,7 +45,6 @@ function extractApiKey(request: NextRequest): string | null { return null; } - // Check for Bearer token format const bearerMatch = authHeader.match(/^Bearer\s+(.+)$/i); if (bearerMatch) { return bearerMatch[1]; @@ -60,30 +56,24 @@ function extractApiKey(request: NextRequest): string | null { export async function middleware(request: NextRequest) { const { pathname } = request.nextUrl; - // Only process API routes if (!pathname.startsWith('/api/')) { return NextResponse.next(); } - // Allow public API routes without authentication if (isPublicApiRoute(pathname)) { return NextResponse.next(); } - // do some basic API key validation + // Api key format validation before we send request to api const apiKey = extractApiKey(request); - if (!apiKey) { - return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); - } - - const match = apiKey.match(API_KEY_REGEX); - - if (!match) { - return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); + if (apiKey) { + const match = apiKey.match(API_KEY_REGEX); + if (!match) { + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); + } } - // Pass the request through - API routes will handle full validation return NextResponse.next(); } From 5ab76c5f2c18c20066dbd8f326c757ec7555b66d Mon Sep 17 00:00:00 2001 From: Vigneshraj Sekar Babu Date: Thu, 21 Aug 2025 11:05:44 -0700 Subject: [PATCH 3/3] default to true --- src/server/services/auth.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/services/auth.ts b/src/server/services/auth.ts index 3197a82c..56060b48 100644 --- a/src/server/services/auth.ts +++ b/src/server/services/auth.ts @@ -29,7 +29,7 @@ const DEFAULT_API_CONFIG: ApiConfig = { rate_limit: 1000, rate_limit_window: 600, bcrypt_rounds: 12, - requireAuth: false, + requireAuth: true, }; export interface CreateApiKeyOptions {