Insufficient Logging in Feathersjs with Jwt Tokens
Insufficient Logging in Feathersjs with Jwt Tokens — how this combination creates or exposes the vulnerability
FeathersJS is a popular framework for building REST and real-time APIs. When JWT tokens are used for authentication, insufficient logging can prevent detection of token misuse, replay, or token‑theft attacks. Because JWTs often carry identity and scope without server‑side session state, logging becomes the primary mechanism to observe and correlate suspicious activity.
In a FeathersJS service configured with JWT authentication, developers may log only high‑level outcomes (e.g., “authentication succeeded”) and omit details needed for security investigations. Missing log fields include token metadata (iss, sub, exp, jti), client IP and user‑agent, resource identifiers, and outcome context (success/failure). Without these, an attacker can reuse a stolen token or perform privilege escalation with low risk of detection.
Additionally, FeathersJS hooks that validate JWTs may proceed silently when validation fails, producing no audit trail. If rate‑limiting or anomaly detection relies on logs, gaps in logging prevent detection of credential‑stuffing or token‑guessing attempts. Real‑world attack patterns such as token replay (CVE‑2022‑24785 style issues in related ecosystems) or horizontal privilege abuse become harder to detect when logs lack token identifiers and timestamps with sufficient granularity.
Compliance mappings also suffer: frameworks such as OWASP API Top 10 2023 A07 (Identification and Authentication Failures) and SOC2 controls expect audit trails for authentication events. Insufficient logging with JWTs in FeathersJS can breach these expectations because there is no reliable record of token issuance, validation attempts, and associated user context.
To illustrate, consider a FeathersJS service where authentication succeeds but the hook logs only the user ID. An attacker who obtains a JWT can iterate through IDs without triggering alerts because token‑specific events are not recorded. Effective logging must capture the JWT jti (JWT ID), issuer, subject, scopes, and the endpoint invoked, alongside request metadata, to enable correlation with runtime findings reported by scanners such as middleBrick.
Jwt Tokens-Specific Remediation in Feathersjs — concrete code fixes
Remediation centers on enriching log data in authentication and token validation hooks and ensuring failures are recorded with sufficient detail. Below are concrete, realistic examples for a FeathersJS app using @feathersjs/authentication and @feathersjs/authentication-jwt.
1) Configure JWT authentication with detailed audit logging
Extend the JWT authentication service to log token metadata and request context on both success and failure.
// src/authentication.js
const { AuthenticationService } = require('@feathersjs/authentication');
const { JWTStrategy } = require('@feathersjs/authentication-jwt');
const logger = require('./logger'); // your structured logger
class AuditAuthenticationService extends AuthenticationService {
async create(data, params) {
const result = await super.create(data, params);
const { user } = result;
logger.info({
event: 'jwt_issued',
jti: result.accessToken, // store token identifier if available
userId: user.id,
email: user.email,
ip: params.connection?.remoteAddress || params.headers['x-forwarded-for'] || null,
userAgent: params.headers['user-agent'] || null,
timestamp: new Date().toISOString()
});
return result;
}
}
module.exports = (app) => {
app.set('auth', new AuditAuthenticationService(app, {
secret: process.env.JWT_SECRET,
path: '/authentication',
service: 'users',
strategy: new JWTStrategy()
}));
};
2) Log token validation details in a custom JWT hook
Add a Feathers hook that runs before authentication calls to capture validation outcomes and token claims.
// src/hooks/log-jwt.js
const { Forbidden } = require('@feathersjs/errors');
module.exports = function () {
return async context => {
const { token } = context.params.headers || {};
if (!token) return context;
// Assume decodeJwt is a utility that validates signature and returns payload
const { jti, sub, iss, exp, scopes } = await context.app.get('jwtUtils').verify(token);
context.params.audit = {
jti,
sub,
iss,
exp,
scopes,
ip: context.params.connection?.remoteAddress || context.params.headers['x-forwarded-for'],
userAgent: context.params.headers['user-agent'],
path: context.path,
method: context.method
};
return context;
};
};
Then log validation outcomes in a after hook:
// src/hooks/log-auth-result.js
module.exports = function () {
return async context => {
const { audit } = context.params;
if (!audit) return context;
const success = context.result && context.result.accessToken;
const logger = context.app.get('logger');
logger.info({
event: 'jwt_validation',
...audit,
outcome: success ? 'success' : 'failure',
timestamp: new Date().toISOString()
});
if (!success) {
throw new Forbidden('Invalid token');
}
return context;
};
};
3) Include JWT metadata in service method logging
Within service methods, log resource identifiers and the JWT subject to tie operations to token ownership.
// src/services/orders/hooks.js
module.exports = {
before: {
async create(context) {
const { user } = context.params.account;
logger.info({
event: 'order_create_attempt',
userId: user.id,
jwtSub: context.params.account.user.id,
itemCount: context.data.items?.length || 0,
ip: context.params.connection?.remoteAddress,
timestamp: new Date().toISOString()
});
}
},
after: {
async create(context) {
logger.info({
event: 'order_create_complete',
orderId: context.result.id,
jwtSub: context.params.account.user.id,
status: 'ok',
timestamp: new Date().toISOString()
});
return context;
}
}
};
These changes ensure logs contain JWT-specific fields (jti, sub, iss, exp), request metadata, and outcome status, enabling detection of token replay, privilege escalation, and anomalous usage patterns. Combined with middleBrick’s runtime findings, teams can correlate logged events with security risk scores and remediation guidance.