GuardAPI Logo
GuardAPI
GuardAPI Logo GuardAPI

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 Audit

Verified 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.