HIGH broken authenticationadonisjsjwt tokens

Broken Authentication in Adonisjs with Jwt Tokens

Broken Authentication in Adonisjs with Jwt Tokens

Broken Authentication occurs when application functions related to authentication and session management are not properly implemented, allowing attackers to compromise passwords, keys, or session tokens. In AdonisJS, using JWT tokens for authentication can introduce specific vulnerabilities if token generation, validation, and storage are not handled securely.

AdonisJS applications often rely on the jwt provider from @adonisjs/auth to issue and verify JSON Web Tokens. A common misconfiguration is using a weak or default secret for signing tokens. If the secret is predictable or shared across environments, an attacker who obtains the secret can forge valid JWTs and impersonate any user. For example, initializing the JWT provider with a static string in start/app.js is risky:

import { Application } from '@adonisjs/core/types'
export default class AppProvider {
  constructor(protected app: Application) {}
  register() {
    this.app.container.singleton('auth', async () => {
      const { JwtProvider } = await import('@adonisjs/auth/providers/jwt')
      return new JwtProvider(this.app, {
        secret: 'my-insecure-secret', // Weak, static secret
        expiresIn: '7d'
      })
    })
  }
}

Another vulnerability arises from insufficient token validation. If an API endpoint only checks for the presence of a token and does not validate its signature or claims (such as iss, aud, or exp), an attacker can modify token payloads (e.g., changing role claims to escalate privileges). AdonisJS middleware can inadvertently allow this if custom guards do not enforce strict validation.

Additionally, storing JWTs insecurely on the client side—such as in localStorage—can lead to token theft via cross-site scripting (XSS). An attacker who injects malicious JavaScript can exfiltrate tokens and use them until expiration. In AdonisJS, failing to set the HttpOnly flag on cookies when using cookie-based storage (or not using secure, same-site attributes) further exposes tokens to client-side scripts.

Finally, lack of token revocation mechanisms can sustain unauthorized access. JWTs are designed to be stateless and self-contained, so once issued, they remain valid until expiration. If an application does not provide a way to revoke tokens (e.g., via a denylist or short-lived tokens with refresh mechanisms), a compromised token can be used for an extended period. This is especially critical in scenarios where user passwords are changed or roles are updated, yet existing JWTs remain valid.

Jwt Tokens-Specific Remediation in Adonisjs — concrete code fixes

To remediate Broken Authentication in AdonisJS when using JWT tokens, enforce strong secret management, strict validation, secure storage, and token lifecycle controls.

  1. Use environment variables for secrets: Never hardcode secrets. Load them from .env and reference them in your JWT provider configuration:
import { Application } from '@adonisjs/core/types'
export default class AppProvider {
  constructor(protected app: Application) {}
  register() {
    this.app.container.singleton('auth', async () => {
      const { JwtProvider } = await import('@adonisjs/auth/providers/jwt')
      return new JwtProvider(this.app, {
        secret: this.app.config.get('app.jwtSecret'), // Load from .env
        expiresIn: '1h' // Short-lived access tokens
      })
    })
  }
}
// In .env: APP_JWT_SECRET=your_32_byte_secure_random_string_here
  1. Validate all token claims: Ensure your authentication guard verifies standard JWT claims. When implementing custom logic, explicitly check issuer (iss), audience (aud), and expiration (exp):
import { HttpContextContract } from '@adonisjs/core/http'
import { schema } from '@ioc:Adonis/Core/Validator'

export default class AuthController {
  public async login({ request, auth, response }: HttpContextContract) {
    const email = request.input('email')
    const password = request.input('password')
    const user = await User.findBy('email', email)
    if (!user || !(await user.verifyPassword(password))) {
      return response.unauthorized()
    }
    const token = await auth.use('jwt').generate(user, {
      expiresIn: '1h',
      // Explicit claims for validation
      issuer: 'my-app',
      audience: 'my-app-users'
    })
    return response.json({ token: token.serialize() })
  }

  public async protected({ auth, request }: HttpContextContract) {
    const tokenString = request.header('authorization')?.replace('Bearer ', '')
    if (!tokenString) {
      throw new Error('Unauthorized')
    }
    const token = await auth.use('jwt').verify(tokenString, {
      issuer: 'my-app',
      audience: 'my-app-users'
    })
    const user = await User.find(token.payload.get('sub'))
    return user
  }
}
  1. Use secure cookie storage with HttpOnly and SameSite: When storing tokens in cookies, set httpOnly: true, secure: true (in production), and sameSite: 'lax' or 'strict' to mitigate XSS and CSRF:
// In start/hooks.ts or middleware
response.cookie('auth_token', token, {
  httpOnly: true,
  secure: process.env.NODE_ENV === 'production',
  sameSite: 'lax',
  path: '/',
  maxAge: 3600000 // 1 hour
})
  1. Implement token revocation: Use short-lived access tokens (e.g., 15–60 minutes) and refresh tokens stored securely in an HTTP-only cookie. Maintain a lightweight denylist (e.g., in Redis) for revoked tokens and check it during validation. Alternatively, use a versioned token claim (e.g., tokenVersion) that increments on password change:
// Example token version check in middleware
const user = await User.find(tokenPayload.sub)
if (user.tokenVersion !== tokenPayload.tokenVersion) {
  throw new Error('Token revoked')
}

Related CWEs: authentication

CWE IDNameSeverity
CWE-287Improper Authentication CRITICAL
CWE-306Missing Authentication for Critical Function CRITICAL
CWE-307Brute Force HIGH
CWE-308Single-Factor Authentication MEDIUM
CWE-309Use of Password System for Primary Authentication MEDIUM
CWE-347Improper Verification of Cryptographic Signature HIGH
CWE-384Session Fixation HIGH
CWE-521Weak Password Requirements MEDIUM
CWE-613Insufficient Session Expiration MEDIUM
CWE-640Weak Password Recovery HIGH

Frequently Asked Questions

How does middleBrick detect Broken Authentication with JWT in AdonisJS?
middleBrick scans API endpoints unauthenticated and tests JWT handling: it checks for weak secrets, missing claim validation, insecure cookie attributes, and missing revocation mechanisms, reporting findings with severity and remediation.
Can middleBrick scan AdonisJS JWT configurations automatically?
Yes. By submitting your AdonisJS API endpoint URL to the middleBrick Web Dashboard, CLI, or GitHub Action, scans run against the unauthenticated surface and map findings to frameworks like OWASP API Top 10.