Open BahaMagi opened 3 years ago
@BahaMagi in short I understand that you want to bypass the authenticate('jwt')
hook when the service which needs to call has another strategy?
The best way to do this is to create exceptions or whitelist where the next authenticate('jwt')
hook will not execute. So if I understand your question:
hooks/exceptionsServices.js
module.exports = function checkIsException() {
const exceptions = ['login', 'logout', 'service-with-own-strategy']; // Or context.app.get('exceptionServices') to get from env vars
return context => {
const serviceName = context.path;
return exceptions.includes(serviceName);
}
}
In app.hooks.js
const { iff, isProvider } = require('feathers-hooks-common');
const checkIsException = require('./hooks/exceptionsServices');
module.exports = {
before: {
all: [
iff(isProvider('external'),
iff(!checkIsException(), authenticate('jwt')) // <-- Pay attention to "!". The conditional will evaluate if it's not exception!!
)
],
...
},
...
};
With this solution, you will be able to add an authorization
to all services but with the flexibility of do exceptions with certain services.
Sorry, I guess my explanation was not easily understandable :x
The problem was, that if we applied a hook in app hooks to be run before any other hooks (that included the auth hook), the database call of the auth hook that fetches the user data for authentication gets messed up.
So in app.hooks.ts
we had ( see my post above for details on appLevelFilter):
export default {
before: {
all: [ appLevelFilter ],
...
},
And in the other data services in datatservice.hooks.ts
we had something like:
import { authenticate } from '@feathersjs/authentication/lib';
export default {
before: {
all: [ authenticate('jwt') ],
...
},
We expected the authentication to work as intended. However, we found out that the authenticate makes a GET request to the users
service in order to fetch the authentication data. This request also passes the appLevelFilter which should not alter the request at all. However, that call is then loaded with the data of the original service call to dataservice
not(!) with user data. This, in turn, causes the authentication to fail, despite the requesting user being authenticated.
The error is thrown in feathers-knex
and were able to find the spot in index.ts
:
_get (id, params = {}) {
return this._findOrGet(id, params).then(data => {
if (data.length !== 1) {
throw new errors.NotFound(`No record found for id '${id}', ${this.fullName} Data: ${data && JSON.stringify(data)}`);
}
return data[0];
}).catch(errorHandler);
}
This error (extended by us for debugging) shows that a service call to the users services is receiving data from the dataservice. Sorry if this issue is better of placed in feathers-knex. Wasnt quite sure where to put it.
We solved it by pretty much doing what you suggested. We reversed the order of the hooks, and provided a white list to the auth hook and it works.
// app.hooks.ts
export default {
before: {
all: [ authenticateJWTWrapper, appLevelFilter ],
Just did not understand why the other order did not work and suspecting a bug in either feathers-knex or the authenticate hook itself.
When having a security hook in place in app/before/all (thus being executed before the service level hooks) using an
authenticate('jwt')
hook in other services screwed up the auth hook for us.User information is handled by a
users
service. Having several other services in place that need authentication as well as further query filtering. Hence we put a hook like this on app/before/all:Steps to reproduce:
Having
appLevelFilter
execute before the auth hook leads to the GET call to theusers
service during the auth hook to be mixed up with the original service FIND call. Reversing the order of the hooks, i.e. having auth run first in a wrapper that excludes the auth call for services/methods we dont want it for (like theauthentication
service) solves the problem.Sorry for not providing a repo that reproduces this. Hope the information provided is enough to figure out what might have caused this.
Expected behavior:
Authenticating that rejects un-authenticated queries but accepts authenticated ones.
Actual Behavior:
NotFound
Error is thrown by theusers
service when searching for the current user, canceling the auth hook.The data returned by the GET request to the
users
service is the data intended for the service that called the auth hook. We looked at what was returned here inindex.js
in thefeathers-knex
package and for theusers
service the data comes from the calling service (hence data.length > 1, hence the error throw).Configuration:
Relevant backend dependencies:
App config: