Broken Authentication in Feathersjs with Firestore
Broken Authentication in Feathersjs with Firestore — how this specific combination creates or exposes the vulnerability
FeathersJS is a minimal, extensible framework for creating JavaScript APIs with real-time capabilities. When used with Google Cloud Firestore as the persistence layer, authentication correctness depends on how the service is configured and how hooks validate identity and permissions. Broken Authentication occurs when identity verification is incomplete, tokens are mishandled, or authorization checks are missing, enabling attackers to impersonate users or escalate privileges.
In a FeathersJS + Firestore setup, common root causes include missing authentication on service hooks, trusting client-supplied user IDs, and failing to validate ID tokens server-side. For example, a Feathers service that uses only authentication: false or relies solely on client-provided parameters is vulnerable to direct object reference attacks. Attackers can modify resource IDs in requests to access other users' data, especially when the service does not enforce ownership checks against Firestore documents.
Firestore security rules are not a substitute for server-side authorization in FeathersJS. Rules protect data at the database level but do not enforce application-level business logic or identity validation. If a Feathers service does not explicitly verify the authenticated user's identity and permissions, an attacker with a valid session token (or a stolen token) can traverse relationships in Firestore by manipulating IDs in payloads or URLs. This is a classic Broken Authentication vector (OWASP API Top 10:2023 API1:2023 Broken Object Level Authorization).
Token handling issues exacerbate the risk. FeathersJS supports multiple authentication strategies, including JWT. If JWT secrets are weak, tokens are not validated properly, or tokens are accepted without signature verification, an attacker can forge tokens. Real-world incidents involving weak JWT configurations have been tracked in the CVE ecosystem, where missing or incorrect verification allowed account takeover. Additionally, if your Feathers app exposes an unauthenticated endpoint that returns sensitive data or accepts state-changing requests, it effectively bypasses identity checks.
Excessive agency patterns can also appear when integrating with AI-assisted tooling. An LLM endpoint used for code suggestions might inadvertently expose authentication logic or accept unsafe inputs that affect identity checks. While this does not introduce new classes of vulnerability, it highlights the importance of validating every input path, including those influenced by generated code.
To detect these issues, security scanners perform unauthenticated and authenticated tests across the attack surface, checking whether services correctly require authentication, validate object ownership, and enforce least privilege. Proper remediation requires explicit server-side checks, secure token validation, and strict Firestore document-level ownership verification.
Firestore-Specific Remediation in Feathersjs — concrete code fixes
Remediation centers on enforcing authentication on every relevant service hook, validating identity server-side, and ensuring Firestore queries are scoped to the authenticated user. Below are concrete, working examples for a FeathersJS service using the Firebase Admin SDK.
First, initialize the Firebase Admin SDK and configure Feathers authentication. This example uses JWT strategy, but the principles apply to other strategies as well.
const feathers = require('@feathersjs/feathers');
const express = require('@feathersjs/express');
const authentication = require('@feathersjs/authentication');
const jwt = require('@feathersjs/authentication-jwt');
const admin = require('firebase-admin');
admin.initializeApp({
credential: admin.credential.applicationDefault(),
});
const app = express(feathers());
app.configure(authentication({
secret: 'your_jwt_secret',
entity: 'user',
service: 'users',
}));
app.use('/messages', express.service({
async find(params) {
const { user } = params;
if (!user || !user._id) {
throw new Error('Unauthenticated');
}
const snapshot = await admin.firestore().collection('messages')
.where('ownerId', '==', user._id)
.get();
const messages = [];
snapshot.forEach(doc => messages.push({ id: doc.id, ...doc.data() }));
return messages;
},
async get(id, params) {
const { user } = params;
if (!user || !user._id) {
throw new Error('Unauthenticated');
}
const doc = await admin.firestore().collection('messages').doc(id).get();
if (!doc.exists) {
throw new Error('Not found');
}
const data = doc.data();
if (data.ownerId !== user._id) {
throw new Error('Forbidden: ownership mismatch');
}
return { id: doc.id, ...data };
},
async create(data, params) {
const { user } = params;
if (!user || !user._id) {
throw new Error('Unauthenticated');
}
const docRef = await admin.firestore().collection('messages').add({
...data,
ownerId: user._id,
createdAt: admin.firestore.FieldValue.serverTimestamp(),
});
return { id: docRef.id, ...data, ownerId: user._id };
},
}));
app.use('messages', authentication.hooks({
authenticate: ['jwt'],
}));
Key points in this setup:
- Authentication is explicitly required on the service via
authenticate: ['jwt']. - Each hook validates
params.userbefore proceeding, ensuring the request has a verified identity. - Firestore queries use
where('ownerId', '==', user._id)to enforce ownership at query time, preventing enumeration across users. - Create operations bind
ownerIdto the authenticated user server-side, ignoring any client-supplied value.
Additionally, ensure your Firebase project uses robust JWT secret rotation and that tokens are transmitted over HTTPS only. Monitor for unusual access patterns using Firebase logs and integrate alerts for anomalous reads or writes.
For continuous protection, the Pro plan enables continuous monitoring and can integrate with GitHub Actions to fail builds if security scores degrade. The dashboard and MCP Server provide visibility and developer context without changing your runtime behavior.
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 |
Frequently Asked Questions
Why aren't Firestore security rules enough to prevent Broken Authentication in FeathersJS?
Can client-supplied user IDs be trusted if Firestore rules restrict writes to ownerId?
params.user from an authenticated JWT) and use server-side fields like ownerId in queries and writes to enforce ownership.