From f39a0be9f01c2695fa39c1cc146e086c11827485 Mon Sep 17 00:00:00 2001 From: Nathan Lamy Date: Thu, 21 Aug 2025 13:45:17 +0200 Subject: [PATCH] feat: add bearer auth --- .../bearer_token_auth_middleware.ts | 47 +++++++++++++++++++ start/env.ts | 2 + start/kernel.ts | 3 +- start/routes.ts | 9 ++-- 4 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 app/middleware/bearer_token_auth_middleware.ts diff --git a/app/middleware/bearer_token_auth_middleware.ts b/app/middleware/bearer_token_auth_middleware.ts new file mode 100644 index 0000000..5b46c50 --- /dev/null +++ b/app/middleware/bearer_token_auth_middleware.ts @@ -0,0 +1,47 @@ +import env from '#start/env' +import type { HttpContext } from '@adonisjs/core/http' +import type { NextFn } from '@adonisjs/core/types/http' + +export default class BearerTokenAuthMiddleware { + async handle({ response, request }: HttpContext, next: NextFn) { + // Get the authorization header + const authHeader = request.header('authorization') + if (!authHeader) { + return response.status(401).json({ + error: 'Authorization header is required', + }) + } + + // Check if it's a Bearer token + if (!authHeader.startsWith('Bearer ')) { + return response.status(401).json({ + error: 'Authorization header must be a Bearer token', + }) + } + + // Extract the token + const token = authHeader.substring(7) // Remove 'Bearer ' prefix + if (!token) { + return response.status(401).json({ + error: 'Token is required', + }) + } + + // Get the valid token from environment + const validToken = env.get('API_BEARER_TOKEN') + if (!validToken) { + return response.status(500).json({ + error: 'Server configuration error: API token not configured', + }) + } + + // Validate the token + if (token !== validToken) { + return response.status(401).json({ + error: 'Invalid token', + }) + } + + await next() + } +} diff --git a/start/env.ts b/start/env.ts index f428a6b..a87f92f 100644 --- a/start/env.ts +++ b/start/env.ts @@ -71,4 +71,6 @@ export default await Env.create(new URL('../', import.meta.url), { VAPID_DETAILS: Env.schema.string(), VAPID_PUBLIC_KEY: Env.schema.string(), VAPID_PRIVATE_KEY: Env.schema.string(), + + API_BEARER_TOKEN: Env.schema.string(), }) diff --git a/start/kernel.ts b/start/kernel.ts index b9c82ca..67b1ec6 100644 --- a/start/kernel.ts +++ b/start/kernel.ts @@ -36,5 +36,6 @@ router.use([() => import('@adonisjs/core/bodyparser_middleware'), () => import(' */ export const middleware = router.named({ guest: () => import('#middleware/guest_middleware'), - auth: () => import('#middleware/auth_middleware') + auth: () => import('#middleware/auth_middleware'), + internal: () => import('#middleware/bearer_token_auth_middleware'), }) diff --git a/start/routes.ts b/start/routes.ts index abfc8b2..df3e85a 100644 --- a/start/routes.ts +++ b/start/routes.ts @@ -39,9 +39,8 @@ router.get('/subjects', [SubjectsController, 'index']).use(middleware.auth()) const CollesController = () => import('#controllers/colles_controller') router .group(() => { - // TODO: PRIVATE ROUTES - router.post('/', [CollesController, 'create']) - router.post('/upcoming', [CollesController, 'createUpcoming']) + router.post('/', [CollesController, 'create']).use(middleware.internal()) + router.post('/upcoming', [CollesController, 'createUpcoming']).use(middleware.internal()) router.post('/:colleId/refresh', [CollesController, 'refresh']).use(middleware.auth()) router.get('/', [CollesController, 'index']).use(middleware.auth()) router.get('/:colleId', [CollesController, 'show']).use(middleware.auth()) @@ -55,7 +54,7 @@ router router.post('/', [NotificationsController, 'subscribe']) router.post('/:id/unsubscribe', [NotificationsController, 'unsubscribe']) router.post('/:id', [NotificationsController, 'update']) - router.post('/:id/test', [NotificationsController, 'test']).use(middleware.auth()) + router.post('/:id/test', [NotificationsController, 'test']) }) .prefix('/notifications') .use(middleware.auth()) @@ -70,4 +69,4 @@ router router.post('/back-fetch', [InternalsController, 'backFetch']) }) .prefix('/internals') -// TODO: Token authentication + .use(middleware.internal())