Broken Access Control in Adonisjs with Api Keys
Broken Access Control in Adonisjs with Api Keys — how this specific combination creates or exposes the vulnerability
Broken Access Control occurs when API endpoints do not properly enforce authorization checks, allowing one user to access or modify another user’s resources. In AdonisJS, combining Api Keys with route-level authorization can inadvertently create or expose this vulnerability if the key is treated as a substitute for user-level permissions.
Api Keys in AdonisJS are often implemented as application-level tokens that identify an integration or service rather than a specific user. If these keys are used for authentication but the developer omits granular authorization checks (e.g., verifying the resource owner or tenant), an attacker who obtains a valid key can perform actions across all data accessible to that key. For example, an endpoint like GET /api/v1/projects/:id might validate the presence of an Api Key header but fail to ensure that the key’s associated scope or tenant matches the requested project. This mismatch enables BOLA/IDOR (Broken Level of Authorization/Insecure Direct Object Reference), a common form of Broken Access Control.
AdonisJS does not automatically enforce ownership or scope based on Api Keys. Developers must explicitly encode these rules in route handlers or policies. If an Api Key is used in a service to fetch a project record, the query must include a tenant or owner filter derived from the key’s metadata. Without it, the scan may flag a high-severity finding under BOLA/IDOR and Property Authorization, noting that unauthenticated or low-privilege actors can access unauthorized resources by leveraging a valid but overly permissive key.
Real attack patterns include enumeration of IDs (e.g., iterating numeric project IDs) and exploiting weakly scoped keys. For instance, a key provisioned for a partner integration that lacks row-level constraints could allow reading or updating any project record. The presence of Api Keys does not inherently mitigate or introduce Broken Access Control; it is the absence of per-request authorization checks that creates the risk. The scan’s findings will reference OWASP API Top 10 A01:2023 and may map to compliance frameworks such as PCI-DSS and SOC2 when access controls are insufficient.
Api Keys-Specific Remediation in Adonisjs — concrete code fixes
Remediation centers on ensuring that every authorized request validates both the Api Key and the user or tenant context of the target resource. Below are concrete patterns for AdonisJS that combine Api Key validation with strict ownership or scope checks.
Example 1: Api Key validation with tenant scoping
Assume an Api Key is associated with a tenant. The key must be verified, and all data access must be filtered by that tenant.
// start/hooks.ts
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import ApiKey from 'App/Models/ApiKey'
export const validateApiKeyAndTenant = async ({ request, response, auth }: HttpContextContract, next: () => Promise) => {
const apiKey = request.header('X-API-Key')
if (!apiKey) {
return response.unauthorized('Api key missing')
}
const keyRecord = await ApiKey.query()
.where('key', apiKey)
.preload('tenant') // assuming a tenant relationship
.first()
if (!keyRecord || !keyRecord.tenant) {
return response.unauthorized('Invalid Api key')
}
// Attach key and tenant to the request context for downstream use
request.ctx.apiKey = keyRecord
request.ctx.tenant = keyRecord.tenant
await next()
}
// routes.ts
import Route from '@ioc:Adonis/Core/Route'
import validateApiKeyAndTenant from 'App/Hooks/validateApiKeyAndTenant'
Route.group(() => {
Route.get('/projects/:id', 'ProjectsController.show').middleware(['validateApiKeyAndTenant'])
}).prefix('api/v1')
// app/Controllers/Http/ProjectsController.ts
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import Project from 'App/Models/Project'
export default class ProjectsController {
public async show({ params, ctx }: HttpContextContract) {
const project = await Project.query()
.where('id', params.id)
.where('tenant_id', ctx.tenant?.id) // enforce tenant scoping
.preload('members')
.firstOrFail()
return project
}
}
Example 2: Policy-based authorization with Api Key scopes
Define a policy that checks both the Api Key scope and the user (or resource) ownership.
// policies/project_policy.ts
import { schema } from '@ioc:Adonis/Core/Validator'
import type { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
export default class ProjectPolicy {
constructor(protected ctx: HttpContextContract) {}
public async view() {
const apiKey = this.ctx.ctx.apiKey
const project = this.ctx.params.project as ProjectModel
// Ensure the key’s tenant matches the project’s tenant
if (apiKey.tenantId !== project.tenantId) {
throw new Error('Unauthorized: tenant mismatch')
}
// Optionally enforce scope-based rules
if (!apiKey.scopes.includes('projects:read')) {
throw new Error('Forbidden: insufficient scope')
}
return true
}
public async update() {
const apiKey = this.ctx.ctx.apiKey
const project = this.ctx.params.project as ProjectModel
if (apiKey.tenantId !== project.tenantId) {
throw new Error('Unauthorized: tenant mismatch')
}
if (!apiKey.scopes.includes('projects:write')) {
throw new Error('Forbidden: insufficient scope')
}
return true
}
}
// In a controller, apply the policy
import Project from 'App/Models/Project'
import ProjectPolicy from 'Policies/ProjectPolicy'
export async function show({ params, auth, ctx }: HttpContextContract) {
const project = await Project.findOrFail(params.id)
await ctx.authorize('view', project, ProjectPolicy)
return project
}
Key remediation principles
- Never treat an Api Key as a user identity; always map it to a scope, tenant, or integration role.
- Apply row-level filters (e.g.,
where('tenant_id', ...)) on every data access query triggered by an Api Key. - Use AdonisJS policies to centralize authorization logic and explicitly check scopes and ownership.
- Rotate keys regularly and avoid wide-scoped keys for least-privilege access.
These fixes ensure that even when an Api Key is valid, access is constrained by context, directly addressing BOLA/IDOR and Property Authorization risks. The scan’s findings will reflect improved authorization coverage and reduced exposure.
Frequently Asked Questions
Does validating an Api Key alone prevent Broken Access Control in AdonisJS?
How can I verify my remediation is effective against IDOR?
where('tenant_id', tenantId)). Use the CLI (middlebrick scan <url>) to re-evaluate the endpoint; a well-scoped implementation should remove high-severity BOLA/IDOR and Property Authorization findings.