HIGH api key exposureadonisjsjwt tokens

Api Key Exposure in Adonisjs with Jwt Tokens

Api Key Exposure in Adonisjs with Jwt Tokens — how this specific combination creates or exposes the vulnerability

When an AdonisJS application uses JSON Web Tokens (JWT) for authentication but also relies on API keys for service-to-service or third-party integrations, improper handling can lead to Api Key Exposure. This occurs when API keys are embedded in JWT payloads or stored alongside token configuration in a way that they can be extracted by an attacker who gains access to token data. Because JWTs are often transmitted in HTTP headers (e.g., Authorization: Bearer <token>), if these tokens are logged, stored in browser local storage, or transmitted over non-TLS connections, any embedded or related API keys can be leaked.

In AdonisJS, developers sometimes place API keys inside the JWT payload to propagate credentials to downstream services. If the token is not properly protected (e.g., missing token encryption, using weak signing algorithms, or failing to validate token audiences), an attacker who steals the JWT can extract the API key and misuse it. Additionally, if AdonisJS middleware or route handlers log the full JWT or include it in error messages, the API key can be inadvertently exposed through logs or client-side JavaScript. This is particularly risky when tokens have long lifetimes or when refresh tokens are stored insecurely, allowing an attacker to repeatedly use a captured token to harvest embedded keys.

The risk is compounded when JWT secrets or public keys are not properly rotated or when environment variables holding signing keys are exposed through misconfigured .env files or insecure CI/CD pipelines. AdonisJS applications that generate JWTs without setting appropriate token expiration (exp), not validating issuers (iss), or failing to verify scopes can inadvertently expose API keys that were included as custom claims. Attackers can then use these keys to access external services, escalate privileges, or exfiltrate sensitive data, leading to account compromise or data breaches.

Jwt Tokens-Specific Remediation in Adonisjs — concrete code fixes

To mitigate Api Key Exposure when using JWT tokens in AdonisJS, ensure that API keys are never embedded directly in JWT payloads. Instead, store API keys securely on the server side and reference them via opaque identifiers within the token. Use strong signing algorithms like RS256 and enforce short token lifetimes. Below are concrete code examples demonstrating secure practices.

Secure JWT generation without embedding API keys

const jwt = use('jwt')
const crypto = require('crypto')

class AuthController {
  async login ({ request, auth }) {
    const user = await User.findBy('email', request.input('email'))
    if (!user || !(await verifyPassword(request.input('password'), user.password))) {
      throw new Error('Invalid credentials')
    }

    // Do NOT include API keys in the payload
    const token = jwt.sign({
      sub: user.id,
      email: user.email,
      iat: Date.now(),
      exp: Math.floor(Date.now() / 1000) + (60 * 15), // 15 minutes
      iss: 'adonisjs-app',
      aud: 'api.example.com'
    }, Env.get('JWT_SECRET'), 'RS256')

    return { token }
  }
}
module.exports = AuthController

Validating JWTs and securely using API keys server-side

const jwt = use('jwt')
const axios = require('axios')

class ExternalServiceController {
  async callExternal ({ request }) {
    const authHeader = request.header('authorization')
    if (!authHeader || !authHeader.startsWith('Bearer ')) {
      throw new Error('Unauthorized')
    }

    const token = authHeader.split(' ')[1]
    let payload
    try {
      payload = jwt.verify(token, Env.get('JWT_PUBLIC_KEY'), { algorithms: ['RS256'] })
    } catch (error) {
      throw new Error('Invalid token')
    }

    // Retrieve API key securely from environment or secure vault using payload.sub as a lookup key
    const apiKey = process.env[`API_KEY_${payload.sub.toUpperCase()}`]
    if (!apiKey) {
      throw new Error('Service credentials not found')
    }

    const response = await axios.get('https://external-api.example.com/data', {
      headers: { Authorization: `Bearer ${apiKey}` }
    })

    return response.data
  }
}
module.exports = ExternalServiceController

Environment-based API key management

// .env.example
JWT_SECRET=your_jwt_signing_secret
API_KEY_USER1=sk_live_abc123
API_KEY_USER2=sk_live_xyz789

// config/jwt.js
module.exports = {
  secret: Env.getOrFail('JWT_SECRET'),
  ttl: '15m'
}

// config/api-keys.js (never commit real keys)
const Env = use('Env')
const apiKeys = {
  [Env.get('DB_USER_ID')]: Env.getOrFail('API_KEY_DB'),
  [Env.get('PAYMENT_SERVICE_ID')]: Env.getOrFail('API_KEY_PAYMENT')
}
module.exports = apiKeys

Middleware to prevent token leakage in logs

const Logger = use('Logger')

class SanitizeMiddleware {
  async handle ({ request, response }, next) {
    request.cleanHeaders = () => {
      const headers = request.headers()
      delete headers.authorization
      return headers
    }
    await next()
  }
}
module.exports = SanitizeMiddleware

Frequently Asked Questions

Can JWT tokens in AdonisJS ever safely carry API keys?
No. JWTs should never carry API keys as claims. Use the token only for identity and scope, and resolve API keys server-side from a secure store using the subject (sub) or other non-sensitive identifier.
How does middleBrick relate to JWT and API key security findings?
middleBrick scans unauthenticated attack surfaces and can detect exposed API keys in OpenAPI specs and runtime responses. It does not fix the exposure but provides prioritized findings with remediation guidance to help you remove embedded keys and strengthen token handling.