Fix Broken User Authentication in AdonisJS
Broken authentication in AdonisJS typically manifests through unprotected login routes vulnerable to credential stuffing and brute-force attacks. While the framework provides robust defaults, developers often fail to implement rate limiting or leak account existence through timing attacks and verbose error messages. In this guide, we harden the authentication flow using the AdonisJS Limiter and secure credential handling.
The Vulnerable Pattern
public async login({ request, auth, response }: HttpContext) {
const { email, password } = request.all()
try {
// VULNERABILITY: No rate limiting. Attacker can spray passwords indefinitely.
// VULNERABILITY: request.all() can lead to parameter pollution.
const token = await auth.use('api').attempt(email, password)
return token
} catch {
return response.unauthorized('Invalid credentials')
}
}
The Secure Implementation
The secure implementation mitigates brute-force attacks by integrating the @adonisjs/limiter package. It tracks failed login attempts per IP address and enforces a cooldown period once a threshold is reached. Additionally, we use request.input() instead of request.all() to strictly control data ingestion. We also ensure that the error response is generic ('Invalid credentials') to prevent user enumeration, and we reset the limiter state only upon a successful cryptographic challenge. For production, ensure config/auth.ts uses Argon2id for password hashing and config/session.ts has 'httpOnly' and 'secure' flags set to true.
import { HttpContext } from '@adonisjs/core/http' import limiter from '@adonisjs/limiter/services/main'export default class AuthController { public async login({ request, auth, response }: HttpContext) { const email = request.input(‘email’) const password = request.input(‘password’) const throttleKey =
login_attempts_${request.ip()}// Check if the IP is currently throttled if (await limiter.isExceeded(throttleKey)) { return response.tooManyRequests('Too many attempts. Please wait 15 minutes.') } try { const token = await auth.use('api').attempt(email, password) // Reset throttle on successful login await limiter.delete(throttleKey) return token } catch (error) { // Increment failure count on invalid credentials await limiter.increment(throttleKey) return response.unauthorized('Invalid credentials') }
} }
Protect your AdonisJS API
Don't rely on manual checks. GuardAPI's Gemini 3 Pro engine detects Broken User Authentication and logic flaws in seconds.
Run Automated AuditVerified by Ghost Labs Security Team
This content is continuously validated by our automated security engine and reviewed by our research team. Ghost Labs analyzes over 500+ vulnerability patterns across 40+ frameworks to provide up-to-date remediation strategies.