Auth Bypass in Adonisjs with Api Keys
Auth Bypass in Adonisjs with Api Keys — how this specific combination creates or exposes the vulnerability
AdonisJS does not provide a built-in API key authentication layer; developers typically implement API key validation in application code or via an authentication provider. When API keys are used, an auth bypass can occur if route guards rely on incomplete checks, such as verifying the key’s presence but not its scope, validity, or association with the requested resource. For example, a route may call auth.authenticate() with an API guard but skip additional authorization logic that confirms the key permits access to the specific endpoint or object.
In a black-box scan, middleBrick tests unauthenticated attack surfaces and can detect whether an API key–protected endpoint returns data when it should require scope-specific permissions. If a key intended for read-only analytics can access admin routes because the route does not enforce scope checks, this is an Auth Bypass/BOLA (Broken Access Control Level Authorization) pattern. AdonisJS applications that generate tokens with broad permissions or that fail to validate key bindings to the correct tenant or user can inadvertently expose sensitive operations.
Consider an endpoint that retrieves user data by ID. If the handler loads the user via User.findOrFail(params.id) and then checks only that a valid API key exists, a client can change the ID in the URL to access other users’ data. The API key is accepted, but the application does not verify whether the key’s owner is allowed to view that specific user record. This is a classic IDOR (Insecure Direct Object Reference) enabled by insufficient authorization tied to API key usage. The scan’s Authentication and BOLA/IDOR checks can surface such misconfigurations by probing endpoints with different keys and IDs to see if access control is enforced per request.
Additional risk patterns include endpoints that accept keys via headers or query parameters but do not enforce HTTPS, allowing interception; keys embedded in logs or URLs that leak via referrer or error messages; and keys with excessive privileges due to coarse-grained roles. middleBrick’s Property Authorization and Data Exposure checks evaluate whether responses contain sensitive fields (such as passwords or tokens) and whether encryption is enforced, highlighting weak spots in how API keys are handled within the request lifecycle.
Api Keys-Specific Remediation in Adonisjs — concrete code fixes
Secure API key handling in AdonisJS requires explicit validation of key ownership, scope, and usage context. Always treat API keys as credentials and enforce authorization checks after authentication. Below are concrete, working examples you can apply.
1. Define an API key model and relationship
Create an ApiKey model that references a user or client and includes fields like scope, expiresAt, and allowedRoutes. Define a relationship on the User model.
// app/Models/ApiKey.ts
import { DateTime } from 'luxon'
import { BaseModel, column, belongsTo } from '@ioc:Adonis/Lucid/Orm'
import User from './User'
export default class ApiKey extends BaseModel {
@column({ isPrimary: true })
public id: number
@column()
public keyHash: string
@column()
public scope: 'read' | 'write' | 'admin'
@column.dateTime()
public expiresAt: DateTime
@column()
public allowedRoutes?: string[]
@belongsTo(() => User)
public user: User
}
2. Create a custom auth provider for API key validation
Use AdonisJS provider files to implement lookup and verification without exposing raw keys.
// start/auth.ts
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import ApiKey from 'App/Models/ApiKey'
import { sha256 } from '@ioc:Adonis/Addons/hash'
export default class ApiKeyProvider {
public async authenticate(request: HttpContextContract, providedKey: string): Promise {
const keyHash = sha256.hash(providedKey)
const apiKey = await ApiKey.query()
.where('keyHash', keyHash)
.where('expiresAt', '>', new Date())
.preload('user')
.first()
if (!apiKey) {
return false
}
// Attach key metadata to the request for downstream checks
request.authUser = apiKey.user
request.apiKeyScope = apiKey.scope
request.apiKeyRoutes = apiKey.allowedRoutes
return true
}
}
3. Enforce scope and route checks in handlers
In your controller or middleware, verify that the key’s scope and allowed routes match the incoming request.
// controllers/UsersController.ts
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import User from 'App/Models/User'
export default class UsersController {
public async show({ params, request, response }: HttpContextContract) {
const user = await User.findOrFail(params.id)
// Scope check: ensure key has at least 'read' scope
const scope = request.apiKeyScope
if (!scope || (scope !== 'read' && scope !== 'write' && scope !== 'admin')) {
return response.forbidden({ message: 'Insufficient scope' })
}
// Optional route-specific allowlist
const allowedRoutes = request.apiKeyRoutes
if (allowedRoutes && !allowedRoutes.includes(request.url())) {
return response.forbidden({ message: 'Route not permitted for this key' })
}
// Prevent IDOR: ensure the key owner is allowed to view this user
if (scope === 'read' && request.authUser?.id !== user.id) {
return response.forbidden({ message: 'Access to this resource denied' })
}
return user
}
}
4. Rotate keys and avoid query parameters
Store keys in headers (e.g., X-API-Key) rather than query strings to reduce leakage in logs. Implement key rotation and revocation endpoints, and hash keys before storage using a strong one-way hash.
5. Integrate with middleware
Apply the auth check globally or per route group to centralize enforcement.
// start/routes.ts
import Route from '@ioc:Adonis/Core/Route'
import ApiKey from 'App/Models/ApiKey'
Route.group(() => {
Route.get('/users/:id', 'UsersController.show')
}).middleware('apikey') // ensure middleware triggers the provider above
These steps ensure API keys are validated, scoped, and checked against business rules, reducing the likelihood of auth bypass and IDOR in AdonisJS applications.
Related CWEs: authentication
| CWE ID | Name | Severity |
|---|---|---|
| CWE-287 | Improper Authentication | CRITICAL |
| CWE-306 | Missing Authentication for Critical Function | CRITICAL |
| CWE-307 | Brute Force | HIGH |
| CWE-308 | Single-Factor Authentication | MEDIUM |
| CWE-309 | Use of Password System for Primary Authentication | MEDIUM |
| CWE-347 | Improper Verification of Cryptographic Signature | HIGH |
| CWE-384 | Session Fixation | HIGH |
| CWE-521 | Weak Password Requirements | MEDIUM |
| CWE-613 | Insufficient Session Expiration | MEDIUM |
| CWE-640 | Weak Password Recovery | HIGH |