From 5ed8d9e72381a59470e3287bf5aa5e83516a733e Mon Sep 17 00:00:00 2001 From: kami Date: Tue, 14 Jul 2026 15:03:06 +0400 Subject: [PATCH] add API auth (#150 #151): MUZICK_API_KEY + MUZICK_ADMIN_KEY via Bearer token --- .env.example | 4 ++++ backend/src/app.ts | 20 +++++++++++++++++++- docker-compose.yml | 2 ++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/.env.example b/.env.example index c6d9483..dae4163 100644 --- a/.env.example +++ b/.env.example @@ -4,6 +4,10 @@ DB_PASSWORD=change-me # Shared redis (infra stack) REDIS_PASSWORD=change-me +# API auth (optional — uncomment to require Bearer token) +# MUZICK_API_KEY=mz-change-me +# MUZICK_ADMIN_KEY=mz-admin-change-me + # Typesense search TYPESENSE_API_KEY=change-me diff --git a/backend/src/app.ts b/backend/src/app.ts index 9159485..fcf19f5 100644 --- a/backend/src/app.ts +++ b/backend/src/app.ts @@ -91,7 +91,25 @@ export async function buildApp(config: AppConfig) { // the first search request doesn't hit a 404. await searchService.ensureCollection(); - // Health check route + // Auth: optional MUZICK_API_KEY / MUZICK_ADMIN_KEY + const apiKey = process.env.MUZICK_API_KEY; + const adminKey = process.env.MUZICK_ADMIN_KEY; + fastify.addHook('onRequest', async (request, reply) => { + if (!apiKey && !adminKey) return; + const path = request.url; + if (path === '/api/health') return; + const auth = request.headers.authorization || ''; + const token = auth.startsWith('Bearer ') ? auth.slice(7) : ''; + if (!token) return reply.code(401).send({ error: 'Unauthorized' }); + // admin routes require admin key specifically + if (path.startsWith('/api/admin/') && adminKey) { + if (token !== adminKey) return reply.code(403).send({ error: 'Admin access denied' }); + return; + } + // regular routes accept either key + if (token === apiKey || (adminKey && token === adminKey)) return; + reply.code(401).send({ error: 'Unauthorized' }); + }); fastify.get('/api/health', async (request, reply) => { const status = { diff --git a/docker-compose.yml b/docker-compose.yml index f340d1c..5120232 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -29,6 +29,8 @@ services: DATABASE_URL: postgresql://user:${DB_PASSWORD}@db:5432/muzick REDIS_URL: redis://:${REDIS_PASSWORD}@redis:6379 TYPESENSE_API_KEY: ${TYPESENSE_API_KEY} + MUZICK_API_KEY: ${MUZICK_API_KEY} + MUZICK_ADMIN_KEY: ${MUZICK_ADMIN_KEY} MUSIC_DIR: /music volumes: - /mnt/hdd1/media/Music:/music:ro