Missing Authentication in Adonisjs
How Missing Authentication Manifests in Adonisjs
Missing authentication in Adonisjs applications often appears through subtle misconfigurations that bypass the framework's built-in authentication middleware. The most common manifestation occurs when developers forget to apply authentication guards to controller methods or route groups, leaving sensitive endpoints exposed to unauthenticated access.
A classic Adonisjs pattern that leads to this vulnerability involves using the @middleware decorator incorrectly or omitting it entirely. Consider a user management controller where the updateProfile method lacks proper authentication:
class UserController {
async updateProfile({ auth, request, response }) {
// No authentication check here
const userId = request.input('id');
const user = await User.find(userId);
if (!user) {
return response.status(404).json({ error: 'User not found' });
}
user.merge(request.only(['name', 'email']));
await user.save();
return response.json({ success: true, user });
}
}
This endpoint allows anyone to update any user's profile by simply knowing their ID, creating a severe BOLA (Broken Object Level Authorization) vulnerability.
Another Adonisjs-specific manifestation occurs with route middleware configuration. Developers sometimes define routes without the auth middleware in their start/routes.ts file:
Route.group(() => {
Route.get('/api/users/:id', 'UserController.show');
Route.post('/api/users', 'UserController.store');
Route.put('/api/users/:id', 'UserController.update');
}).middleware([]); // Empty middleware array - no authentication
The absence of authentication middleware here means all user management endpoints are publicly accessible, allowing complete account takeover through IDOR attacks.
Adonisjs's middleware system can also create confusion when using multiple authentication guards. A common mistake involves configuring JWT authentication but forgetting to specify the guard in controller methods:
class AuthController {
async me({ auth }) {
// This uses the default guard, not necessarily JWT
const user = await auth.user;
return user;
}
}
If the default guard is set to 'session' but the application uses JWT for API authentication, this endpoint might not work as intended or could expose user data to unauthorized requests.
Adonisjs-Specific Detection
Detecting missing authentication in Adonisjs requires examining both the codebase structure and runtime behavior. Start by auditing your middleware configuration in start/kernel.ts to ensure authentication guards are properly registered:
const globalMiddleware = [
'Adonis/Core/BodyParser',
'Adonis/Core/Cors',
'App/Middleware/Auth' // Ensure this is present
];
Then examine your route definitions for any groups missing the auth middleware. Adonisjs provides the Route.resource() method which automatically applies middleware to all routes in a resource controller:
Route.resource('users', 'UserController')
.middleware({
'*': ['auth'] // Apply auth to all user routes
});
Missing this configuration leaves all user management routes unprotected.
Code analysis tools can help identify missing authentication patterns. Look for controller methods that access user data or perform sensitive operations without authentication checks:
// Vulnerable pattern - no auth check
async deleteAccount({ request }) {
const userId = request.input('id');
await User.query().where('id', userId).delete();
return response.json({ success: true });
}
middleBrick's black-box scanning approach is particularly effective for detecting missing authentication in Adonisjs applications. The scanner tests endpoints without credentials, attempting to access protected functionality. For Adonisjs applications, middleBrick specifically checks for:
- Unauthenticated access to user management endpoints
- Missing authentication on admin-only routes
- Exposed JWT endpoints without proper token validation
- Database operations accessible without authentication
The scanner's 12 security checks include authentication bypass detection that works across all Adonisjs versions, identifying endpoints that should require authentication but don't.
Adonisjs-Specific Remediation
Remediating missing authentication in Adonisjs involves multiple layers of protection. The first step is ensuring proper middleware configuration. In start/kernel.ts, verify your authentication middleware is correctly set up:
const namedMiddleware = {
auth: 'Adonis/Addons/Auth',
authJwt: 'App/Middleware/AuthJwt', // Custom JWT middleware if needed
admin: 'App/Middleware/Admin' // Role-based middleware
};
Apply authentication at the route level using middleware arrays:
Route.group(() => {
Route.get('/api/users/profile', 'UserController.profile');
Route.put('/api/users/profile', 'UserController.updateProfile');
}).middleware(['auth']);
For controller-level protection, use the @middleware decorator:
import { middleware } from '@adonisjs/core/http'
@middleware(['auth'])
export default class UserController {
async profile({ auth }) {
return auth.user;
}
async updateProfile({ auth, request }) {
const user = auth.user;
user.merge(request.only(['name', 'email']));
await user.save();
return response.json({ success: true, user });
}
}
For API endpoints using JWT, implement a dedicated JWT authentication middleware:
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import { schema } from '@ioc:Adonis/Core/Validator'
import { jwtVerify } from 'crypto'
export class AuthJwtMiddleware {
async handle({ request, auth }: HttpContextContract, next: () => Promise) {
const token = request.header('authorization')?.replace('Bearer ', '');
if (!token) {
return response.unauthorized({ error: 'Missing token' });
}
try {
const payload = await auth.use('jwt').verify(token);
request.auth = { user: payload }; // Attach user to request
} catch (error) {
return response.unauthorized({ error: 'Invalid token' });
}
await next();
}
}
Implement role-based access control for admin functions:
@middleware(['auth', 'admin'])
export default class AdminController {
async deleteUser({ request, response }) {
const userId = request.input('id');
const user = await User.find(userId);
if (!user) {
return response.status(404).json({ error: 'User not found' });
}
await user.delete();
return response.json({ success: true });
}
}
Finally, add authentication checks at the database query level to prevent IDOR attacks:
async updateProfile({ auth, request }) {
const user = await User.query()
.where('id', auth.user.id)
.where('id', request.input('id', auth.user.id))
.first();
if (!user) {
return response.status(404).json({ error: 'User not found or unauthorized' });
}
user.merge(request.only(['name', 'email']));
await user.save();
return response.json({ success: true, user });
}
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 |