CognxSafeTrack commited on
Commit Β·
9595ade
1
Parent(s): 7cf001f
fix(auth): inline onRequest hook in guardedRoutes scope to properly protect private routes
Browse files- apps/api/src/index.ts +25 -7
apps/api/src/index.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
| 1 |
import Fastify from 'fastify';
|
| 2 |
import cors from '@fastify/cors';
|
| 3 |
import rateLimit from '@fastify/rate-limit';
|
| 4 |
-
import authPlugin from './plugins/auth';
|
| 5 |
import { whatsappRoutes } from './routes/whatsapp';
|
| 6 |
import { adminRoutes } from './routes/admin';
|
| 7 |
import { aiRoutes } from './routes/ai';
|
|
@@ -26,12 +25,31 @@ server.register(rateLimit, {
|
|
| 26 |
server.register(whatsappRoutes, { prefix: '/v1/whatsapp' });
|
| 27 |
|
| 28 |
// ββ Private Routes (require ADMIN_API_KEY) βββββββββββββββββββββββββββββββββββββ
|
| 29 |
-
//
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 35 |
});
|
| 36 |
|
| 37 |
// ββ Health Routes (public) βββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
|
|
| 1 |
import Fastify from 'fastify';
|
| 2 |
import cors from '@fastify/cors';
|
| 3 |
import rateLimit from '@fastify/rate-limit';
|
|
|
|
| 4 |
import { whatsappRoutes } from './routes/whatsapp';
|
| 5 |
import { adminRoutes } from './routes/admin';
|
| 6 |
import { aiRoutes } from './routes/ai';
|
|
|
|
| 25 |
server.register(whatsappRoutes, { prefix: '/v1/whatsapp' });
|
| 26 |
|
| 27 |
// ββ Private Routes (require ADMIN_API_KEY) βββββββββββββββββββββββββββββββββββββ
|
| 28 |
+
// Inline addHook on an isolated scope guarantees the auth check fires BEFORE
|
| 29 |
+
// any child route handler, properly encapsulated in Fastify v4.
|
| 30 |
+
server.register(async function guardedRoutes(scope) {
|
| 31 |
+
scope.addHook('onRequest', async (request, reply) => {
|
| 32 |
+
const apiKey = process.env.ADMIN_API_KEY;
|
| 33 |
+
|
| 34 |
+
if (!apiKey) {
|
| 35 |
+
request.log.error('ADMIN_API_KEY is not configured!');
|
| 36 |
+
return reply.code(503).send({ error: 'Service misconfigured' });
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
const authHeader = request.headers['authorization'];
|
| 40 |
+
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
| 41 |
+
return reply.code(401).send({ error: 'Unauthorized', message: 'Missing Authorization header' });
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
const token = authHeader.slice(7);
|
| 45 |
+
if (token !== apiKey) {
|
| 46 |
+
return reply.code(401).send({ error: 'Unauthorized', message: 'Invalid API key' });
|
| 47 |
+
}
|
| 48 |
+
});
|
| 49 |
+
|
| 50 |
+
scope.register(adminRoutes, { prefix: '/v1/admin' });
|
| 51 |
+
scope.register(aiRoutes, { prefix: '/v1/ai' });
|
| 52 |
+
scope.register(paymentRoutes, { prefix: '/v1/payments' });
|
| 53 |
});
|
| 54 |
|
| 55 |
// ββ Health Routes (public) βββββββββββββββββββββββββββββββββββββββββββββββββββββ
|