feat(auth): add session login page, API key guard, and remove orphan SQL migrations
- Add session-based authentication for web-UI (Login.vue, AuthController) - Add AuthSessionMiddleware: redirects unauthenticated users to /login - Add ApiKeyMiddleware: validates X-Api-Key header on all /api/v1 routes - Add BasicAuthMiddleware: registered for future M2M use - Use timingSafeEqual for all credential comparisons (timing attack prevention) - Regenerate session ID on login (session fixation prevention) - Validate redirect target after login (open redirect prevention) - Require WEBUI_USERNAME, WEBUI_PASSWORD, API_KEY as mandatory env vars - Share auth.username/authenticated via Inertia shared props - Add user dropdown in navbar (avatar icon + username + logout) - Add login i18n keys in fr.json and en.json - Remove orphan SQL migrations (users, auth_access_tokens) and @adonisjs/lucid
This commit is contained in:
1 parent
198f15ec9b
commit
991173aa05
18 files changed
+477
-482
No files matched your search
@@ -0,0 +1,36 @@
|
||||
import { timingSafeEqual } from 'node:crypto'
|
||||
import type { HttpContext } from '@adonisjs/core/http'
|
||||
import type { NextFn } from '@adonisjs/core/types/http'
|
||||
import env from '#start/env'
|
||||
|
||||
/**
|
||||
* ApiKeyMiddleware
|
||||
*
|
||||
* Protects REST API routes by validating a fixed API key provided in the
|
||||
* X-Api-Key request header. The expected key is configured via:
|
||||
* API_KEY (required env variable)
|
||||
*
|
||||
* Security:
|
||||
* - Constant-time comparison (timingSafeEqual) to prevent timing attacks
|
||||
*
|
||||
* Responds with 401 if the header is missing or the key does not match.
|
||||
*/
|
||||
export default class ApiKeyMiddleware {
|
||||
async handle({ request, response }: HttpContext, next: NextFn) {
|
||||
const apiKey = request.header('x-api-key') ?? ''
|
||||
const expectedKey = env.get('API_KEY')!
|
||||
|
||||
const provided = Buffer.from(apiKey)
|
||||
const expected = Buffer.from(expectedKey)
|
||||
|
||||
// Lengths must match and content must match in constant time
|
||||
const valid =
|
||||
provided.length === expected.length && timingSafeEqual(provided, expected)
|
||||
|
||||
if (!valid) {
|
||||
return response.status(401).send('Unauthorized: invalid or missing X-Api-Key header')
|
||||
}
|
||||
|
||||
return next()
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user