Error: No 'authenticate' hook on service leads to open endpoint
0 reputation · 23 Apr 2021, 03:34 UTC
0 reputation · 23 Apr 2021, 03:34 UTC
The goal is to ensure that every service exposed via REST or Socket.io is protected by an authentication check. By default, if a service lacks the authenticate hook, FeathersJS treats it as public and returns data without requiring credentials.
Key constraints include:
before hook chain contains authenticate.Given these uncertainties, the following questions need resolution:
authenticate hook on every service automatically, without manually editing each service file?35275 reputation · 23 Apr 2021, 13:59 UTC
In FeathersJS a service is considered public if its before hook chain does not contain an authenticate hook. To avoid accidental exposure you can enforce the presence of the hook globally, guarantee its order, and optionally block any endpoint that lacks it.
app.hooks({ before: { all: […] } }) run on every service method unless a service explicitly replaces that chain.authenticate must be the first element to protect any subsequent data‑fetching hooks.If a service is missing authenticate (either because it was never added or because a service replaced the global chain), FeathersJS treats the endpoint as public. A data‑fetching hook placed before the authentication hook can expose sensitive data even when authentication is added later in the chain.
authenticate hook
const { authenticate } = require('@feathersjs/authentication').hooks;
app.hooks({
before: {
all: [authenticate] // runs on every service method
}
});
When adding service‑specific hooks, place authenticate first and then any other hooks:
service.hooks({
before: {
all: [authenticate, populate('user'), query()]
}
});
If a service intentionally removes the global chain, you can detect that with a small middleware that runs before service handlers:
function enforceAuthHook(req, res, next) {
const serviceName = req.path.split('/')[1];
const service = app.service(serviceName);
const hooks = service?.hooks?.before?.all ?? [];
if (!hooks.includes(authenticate)) {
return res.status(401).send('Authentication required');
}
next();
}
app.use('/**', enforceAuthHook);
Place this middleware after all services are registered so it sees the final hook configuration.
Start the app and call a service endpoint without credentials. A 401 Unauthorized response indicates the global hook is active. If you intentionally remove authenticate from a service’s before array, the same request should succeed, confirming the enforcement can be overridden.
Could you tell me which FeathersJS version you are using? The behavior of global hooks and the ability to override them varies slightly between v3 and v4+. Knowing the version will help refine the recommendation.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.