add API auth (#150 #151): MUZICK_API_KEY + MUZICK_ADMIN_KEY via Bearer token

This commit is contained in:
kami
2026-07-14 15:03:06 +04:00
parent ef7fe9e712
commit 5ed8d9e723
3 changed files with 25 additions and 1 deletions
+4
View File
@@ -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
+19 -1
View File
@@ -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 = {
+2
View File
@@ -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