Jwt Misconfiguration in Adonisjs with Mutual Tls
Jwt Misconfiguration in Adonisjs with Mutual Tls — how this specific combination creates or exposes the vulnerability
JWT misconfiguration in AdonisJS when Mutual TLS (mTLS) is used can create a scenario where authentication is bypassed or improperly enforced. AdonisJS typically relies on the jwt provider from @adonisjs/auth to validate tokens. When mTLS is enabled, the server verifies the client certificate during the TLS handshake, which may lead developers to assume the request is already authenticated. This assumption can result in weak or missing JWT validation logic, such as skipping token checks when a client certificate is present.
For example, if a route uses mTLS for transport-layer identity but does not independently verify the JWT, an attacker who obtains a valid client certificate could access endpoints that require a valid JWT. This misconfiguration violates the principle of defense-in-depth by conflating transport identity with application identity. The JWT may still be required for authorization, but if the middleware is not explicitly configured to enforce it, the endpoint becomes vulnerable.
Another specific risk arises when AdonisJS is configured to accept JWTs from a trusted issuer, but the mTLS setup does not enforce strict client certificate validation. An attacker could present a valid but low-privilege certificate and exploit weak JWT validation to escalate privileges. This is particularly relevant when JWT claims are not cross-checked against the certificate subject or when the application trusts the presence of a certificate instead of validating the token itself.
Real-world attack patterns include scenarios where an unauthenticated attacker connects to an mTLS-enabled endpoint that incorrectly assumes the client certificate maps to a user identity without verifying JWT claims. This can lead to unauthorized access to admin functions or data exposure. The vulnerability is not in mTLS itself but in how it is integrated with JWT-based authentication in AdonisJS.
Compliant with OWASP API Security Top 10, this issue maps to Broken Object Level Authorization (BOLA) and Security Misconfiguration. Even when using mTLS, JWT validation must remain mandatory and independent. middleBrick detects such misconfigurations by cross-referencing OpenAPI specs with runtime behavior, flagging endpoints where JWT requirements are missing despite mTLS being advertised.
Mutual Tls-Specific Remediation in Adonisjs — concrete code fixes
To remediate JWT misconfiguration in AdonisJS with mTLS, ensure that JWT validation is explicitly enforced on every endpoint that requires it, regardless of the presence of a client certificate. Below are concrete code examples for configuring mTLS and JWT validation in AdonisJS.
1. Configure mTLS in AdonisJS
AdonisJS uses the underlying HTTPS server. You can enable mTLS by configuring the server options in start/server.js:
const { defineConfig } = require('@adonisjs/core/app')
const fs = require('fs')
module.exports = defineConfig({
https: {
key: fs.readFileSync('path/to/server.key'),
cert: fs.readFileSync('path/to/server.crt'),
ca: fs.readFileSync('path/to/ca.crt'),
requestCert: true,
rejectUnauthorized: true,
},
})
In this configuration:
requestCert: trueasks the client to present a certificate.rejectUnauthorized: trueensures only certificates signed by the trusted CA are accepted.
2. Enforce JWT validation independently
Do not rely on mTLS to authenticate users. Use AdonisJS guards to enforce JWT validation. For example, in a controller:
const { auth } = require('@adonisjs/core/services')
class UserController {
async showProfile({ request, auth }) {
await auth.use('jwt').authenticate()
const user = auth.getUser()
return { user: user.serialize() }
}
}
Alternatively, use route-level middleware to enforce JWT validation:
const Route = use('Route')
Route.get('/profile', 'UserController.showProfile')
.middleware(['jwt'])
Ensure the JWT provider is correctly configured in config/auth.js:
module.exports = {
guards: {
web: {
driver: 'session',
provider: 'users',
},
api: {
driver: 'jwt',
provider: 'users',
},
},
providers: {
users: {
driver: 'lucid',
model: 'App/Models/User',
},
},
}
3. Validate JWT claims against mTLS identity (optional but recommended)
For additional security, cross-check the JWT claims with the certificate subject. This ensures the authenticated identity is consistent across both layers:
const { auth } = require('@adonisjs/core/services')
class UserController {
async showProfile({ request, auth }) {
await auth.use('jwt').authenticate()
const user = auth.getUser()
const certSubject = request.socket.getPeerCertificate().subject
if (user.username !== certSubject.CN) {
throw new Error('JWT subject does not match certificate subject')
}
return { user: user.serialize() }
}
}
These steps ensure that mTLS and JWT work together without creating a false sense of security. middleBrick’s scans can verify that JWT validation is enforced and that mTLS is not mistakenly treated as sufficient authentication.
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 |