Insufficient Logging in Adonisjs with Api Keys
Insufficient Logging in Adonisjs with Api Keys — how this combination creates or exposes the vulnerability
In AdonisJS applications that rely on API keys for authentication, insufficient logging creates a blind spot that weakens both detection and forensic readiness. When requests are authenticated via keys, each key represents a distinct actor (service, client, or integration). If the framework does not consistently log key usage alongside request context, security teams cannot reliably trace which key was used, when it was used, and what operations it performed.
Consider an AdonisJS route that authenticates via an API key header and then delegates authorization to policies or scopes:
// start/routes.ts
Route.get('/reports/:id', async (ctx) => {
const key = ctx.request.header('x-api-key')
const report = await Report.findOrFail(ctx.params.id)
ctx.response.send(report)
})
If the route handler does not explicitly validate the key against a store and log the outcome, an attacker with a valid key can read sensitive reports without leaving a traceable event. Insufficient logging is especially problematic when key validation is implicit (e.g., via middleware that silently accepts or rejects keys) because there is no record of rejection or of the requester’s identity. Without structured logs that include the key identifier (masked), user context, endpoint, HTTP method, and outcome, you cannot reliably detect abuse such as credential sharing, replay, or lateral movement across services.
The LLM/AI Security checks in middleBrick highlight risks where key-bearing requests reach endpoints that expose system prompts or training artifacts. In such scenarios, missing logs mean you cannot reconstruct whether an AI-related payload was attempted with a particular key, limiting your ability to respond to prompt injection or data exfiltration attempts. Effective logging in AdonisJS should capture at minimum: timestamp, masked API key, route, method, response status, and authorization decision. This enables correlation with threat intelligence and supports incident investigation.
Compliance mappings further illustrate the impact. Under OWASP API Top 10 (2023), insufficient logging and monitoring is listed as API1:2023. Controls like audit trails are expected to record authentication events tied to an identifier. PCI-DSS also requires logs for access to cardholder data endpoints, which API keys often protect. When API keys are used without robust logging, you lose the ability to demonstrate due diligence during audits for SOC2, HIPAA, or GDPR, because you cannot prove who accessed what and when.
Api Keys-Specific Remediation in Adonisjs — concrete code fixes
To remediate insufficient logging when using API keys in AdonisJS, combine structured logging with explicit validation and consistent middleware behavior. Below are concrete, syntactically correct examples that demonstrate how to implement auditable authentication and logging.
1) Explicit key validation with logging in a route handler:
// start/routes.ts
import { DateTime } from 'luxon'
import ApiKey from 'App/Models/ApiKey'
import Logger from '@ioc:Adonis/Core/Logger'
Route.get('/reports/:id', async (ctx) => {
const rawKey = ctx.request.header('x-api-key')
const key = await ApiKey.query().where('key_hash', hashApiKey(rawKey)).first()
if (!key || key.isRevoked) {
Logger.info('api_key_auth_failed', {
timestamp: DateTime.now().toISO(),
maskedKey: maskKey(rawKey),
route: ctx.request.url(),
method: ctx.request.method(),
ip: ctx.request.ip()
})
ctx.response.status(401).send({ error: 'invalid_key' })
return
}
Logger.info('api_key_auth_success', {
timestamp: DateTime.now().toISO(),
maskedKey: maskKey(rawKey),
keyId: key.id,
route: ctx.request.url(),
method: ctx.request.method(),
scope: key.scope
})
const report = await Report.findOrFail(ctx.params.id)
ctx.response.send(report)
})
function hashApiKey(key: string): string {
return require('hash-sum')(key)
}
function maskKey(key: string): string {
if (!key) return 'none'
const visible = 4
return key.slice(0, visible) + '*'.repeat(key.length - visible)
}
This approach ensures each authentication attempt is recorded with masked key material, scope, and outcome. Note that key hashing should use a one-way transform; avoid storing raw keys.
2) Centralized middleware for uniform logging and rejection:
// start/kernel.ts
import { ExceptionHandler } from '@ioc:Adonis/Core/ExceptionHandler'
import Logger from '@ioc:Adonis/Core/Logger'
import ApiKey from 'App/Models/ApiKey'
class ApiKeyMiddleware {
public async handle({ request, response, proceed }, next: () => Promise) {
const rawKey = request.header('x-api-key')
const key = await ApiKey.query().where('key_hash', hashApiKey(rawKey)).first()
if (!key || key.isRevoked) {
Logger.warn('api_key_middleware_reject', {
maskedKey: maskKey(rawKey),
route: request.url(),
method: request.method(),
ip: request.ip()
})
response.unauthorized({ error: 'authentication_required' })
return
}
request.authKey = key // attach for downstream handlers
Logger.debug('api_key_middleware_pass', {
maskedKey: maskKey(rawKey),
keyId: key.id,
route: request.url()
})
await next()
}
}
3) Structured logger configuration (pino) to ensure machine-readable logs:
// start/app.ts
import { logger } from '@poemjs/providers-pino'
export const providers = [
logger({
level: 'info',
formatters: {
level(label) {
return { level: label }
}
}
})
]
With these changes, every key-based request is logged with sufficient detail to support detection of anomalies, such as a single key accessing many endpoints in a short window, or repeated failures followed by success. middleBrick’s API Security checks can validate that your endpoints require authentication and that logging captures key usage, helping you close the gap between detection and remediation.