HIGH broken authenticationadonisjsfirestore

Broken Authentication in Adonisjs with Firestore

Broken Authentication in Adonisjs with Firestore — how this specific combination creates or exposes the vulnerability

When AdonisJS applications rely on Firestore as the identity and session store, several implementation patterns can weaken authentication. A common root cause is treating Firestore documents as trusted sources of authorization without re-verifying authentication state on each request. Because Firestore security rules operate separately from application logic, rules that are too permissive can allow unauthenticated or unverified clients to read or write user data, effectively bypassing intended access controls.

Session management in AdonisJS often uses JWTs or cookie-based sessions. If tokens or session identifiers are stored insecurely (for example, in client-side storage without HttpOnly and Secure flags) or if the application fails to validate token signatures and expiration on every request, an attacker can reuse captured tokens. Similarly, if the application uses Firestore UID fields directly from client-supplied payloads to look up user documents, an attacker can tamper with identifiers to escalate privileges horizontally or vertically (BOLA/IDOR).

AdonisJS middleware stacks must enforce authentication before route handlers execute. If middleware is misconfigured or omitted for sensitive endpoints (password change, email verification, token refresh), requests may execute without a verified identity context. Because Firestore rules cannot distinguish between intentional application calls and direct client writes, over-reliance on rules for authentication rather than server-side checks creates a gap. For instance, a rule that allows users to update only their own documents is insufficient if the application layer does not validate that the authenticated user ID matches the document being modified.

The combination of AdonisJS routing and Firestore’s realtime, schema-flexible model can also expose metadata that aids attackers. Error messages leaking stack traces or Firestore-specific details can reveal collection structures. If rate limiting is applied at the Firestore rules level rather than at the AdonisJS layer, attackers can perform credential spraying or token enumeration without triggering application-side protections. Inadequate logging in AdonisJS means suspicious authentication events may go unnoticed, reducing the ability to detect brute-force or token replay attacks against Firestore-backed accounts.

Finally, insecure default configurations in AdonisJS projects, such as using development-mode secrets or retaining debug utilities in production, can expose authentication endpoints. If Firestore credentials are embedded in frontend code or environment variables improperly scoped, attackers can gain read/write access to user collections. Continuous monitoring and strict separation of authentication responsibilities between AdonisJS middleware and Firestore rules are essential to prevent broken authentication in this stack.

Firestore-Specific Remediation in Adonisjs — concrete code fixes

Remediation centers on enforcing authentication in AdonisJS before any Firestore interaction and tightening Firestore rules to align with least-privilege principles. Always validate the authenticated user ID server-side and use it to scope Firestore queries rather than accepting identifiers from the client.

Secure authentication guard

Create an AdonisJS middleware that ensures a valid session or JWT exists and attaches the user identity to the request context before handlers run:

// start/hooks.ts
import { Exception } from '@poppinss/utils'

export const authenticate = async (ctx, next) => {
  const auth = ctx.auth
  if (!auth || !auth.user) {
    throw new Exception('Unauthorized', 401, 'E_UNAUTHENTICATED')
  }
  ctx.authUser = auth.user // normalized user object
  await next()
}

Apply this middleware to routes that interact with Firestore user data:

// routes/auth.ts
Route.patch('profile/:profileId', ['auth:api', 'firestore.validateOwnership'], ProfileController.update)

Firestore rule alignment with AdonisJS identity

Rules should reference authenticated UID from request.auth and reject any client-supplied UID in paths. Use getAfter to enforce updates only via server-side logic:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /users/{userId} {
      allow read, write: if request.auth != null && request.auth.uid == userId;
      // Prevent client from changing userId in path
    }
    match /profiles/{docId} {
      allow read: if request.auth != null;
      allow write: if request.auth != null && request.auth.uid == request.resource.data.user_id;
    }
  }
}

Server-side Firestore access in AdonisJS controller

Use the Firebase Admin SDK on the server to avoid trusting client input. Resolve user-specific paths with the authenticated UID, not client-supplied identifiers:

// controllers/ProfileController.ts
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import { getFirestore, doc, getDoc, updateDoc } from 'firebase-admin/firestore'

export default class ProfileController {
  public async update({ auth, request, response }: HttpContextContract) {
    const db = getFirestore()
    const userId = auth.user!.uid // from authenticated guard
    const profileRef = doc(db, 'users', userId, 'profile', 'public')
    const snapshot = await getDoc(profileRef)
    if (!snapshot.exists()) {
      return response.notFound({ message: 'Profile not found' })
    }
    // Apply only validated, server-side transformations
    await updateDoc(profileRef, { bio: request.input('bio') })
    return response.ok({ updated: true })
  }
}

Token and session hardening

Ensure JWTs or session cookies are HttpOnly, Secure, and SameSite strict. Validate signatures and claims on each request and rotate secrets regularly. Avoid storing sensitive identifiers in localStorage to mitigate XSS-driven token theft that could lead to Firestore data exposure.

Monitoring and least privilege

Instrument AdonisJS logs to record authentication successes and failures alongside Firestore rule denials. Regularly audit Firestore rules to ensure they do not grant write access based solely on request.auth presence without UID matching. Combine AdonisJS middleware checks with tightly scoped Firestore rules for defense-in-depth.

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 can I verify that my AdonisJS middleware is correctly protecting Firestore endpoints?
Instrument AdonisJS logging to record authentication outcomes and Firestore rule denials. Use automated tests that simulate unauthenticated and tampered-ID requests, confirming that Firestore reads/writes are rejected when the authenticated UID does not match the document path.
What Firestore rules are recommended for user-specific data in an AdonisJS application?
Use rules that require request.auth != null and enforce UID equality between request.auth.uid and document path segments. Avoid rules that allow writes based only on request.auth presence; always tie write permissions to validated server-side logic and resource ownership checks.