I'm a newbie using feathersjs, and it is very flexible and seemed to be very productive for simple CRUD use cases. I've been having issues trying to customize feathers' authorization. The example in the documentation for customizing the login response shows here.
app.service('/authentication').hooks({
after: {
create: [
hook => {
hook.result.foo = 'bar';
}
]
}
});
works as expected, the JSON received has the access token and the foo property. However, if I modified it adding a hook function like this:
app.service('/authentication').hooks({
after: {
create: [
hook => {
hook.result.foo = 'bar';
},
login()
]
}
});
or just
after:{
create: [
login()
] ...
or set it in the before, it doesn't matter the new property is not set. the login hook code is:
const errors = require('feathers-errors');
const jwt = require('feathers-authentication-jwt');
const ExtractJwt = require('passport-jwt').ExtractJwt;
const moment = require('moment');
module.exports = function () {
return function (hook) {
// call a function that validates the username and password and returns a session id, rol and other information to fillout the payload
const sequelizeClient = hook.app.get('sequelizeClient');
sequelizeClient.query('SELECT ... ) // Sequelize magic
.then(mySession => { // session successfully created
hook.data.resultcode = mySession[0].resultcode;
delete hook.data.usr;
delete hook.data.pwd;
//payload I want, but simply doesn't go or is partially taken
var pload = { header: { typ: 'access' },
strategy: 'jwt',
'issuer': 'feathers',
'subject': hook.data.resultcode.session_id,
'audience': 'localhost',
'rol': hook.data.resultcode.rol,
'nbf': moment(),
'iet': moment()
};
var opts = {
name: 'jwt',
entity: 'sessions',
service: 'sessions',
passReqToCallback: false,
session: false // whether to use sessions,
//Verifier: Verifier
};
opts.jwtFromRequest = [ExtractJwt.fromAuthHeader(),
ExtractJwt.fromAuthHeaderWithScheme('Bearer'),
ExtractJwt.fromBodyField('body')
];
opts.secret = 'secret';
hook.data.payload = pload; // as documentation says to modify the payload, but does not work
hook.params.payload = pload;
hook.app.passport.createJWT(pload, opts)
.then( jwtResult => {
hook.result.token = jwtResult;
console.log("after hook result:"+ JSON.stringify(hook.result));
return hook;
})
.catch(error => {
console.log("JWT-ERROR: "+error);
throw new errors.GeneralError('Error generating jwt. Login failed');
});
}).catch(error => {
console.log("ERROR: "+error);
throw new errors.GeneralError('Database error');
});
};
};
This code runs, the session is created in the database, all good, but the response goes to the client before the new token is created and shown in the console. the foo is there, but not the new token property added in the hook.result object. The difference is that foo is synchronically added, the token property is asynchronously set. I read this answer (Understanding FeathersJS hooks), but for a the code generated with feathers-cli I don't get how to do it, and if it applies for Auk (the feathers version I'm using.) Now my questions:
- How am I able to send the token property when it is generated asynchronously?
- How can I change/override the payload, the secret and the options of the token. The secret in fact will be by session, not unique or system-wide as it is in the configuration. The system wide-one maybe are going to be set as a public key if the token is encrypted using RSA for instance.
- Where is an example of how to create a custom service (not based on sequelize, memory, or other backend) if the resource is calculated by the REST server itself?. Would be good to have an example in the advanced section of the docs.
Thanks, and sorry if the answer is obvious, but I haven't reach the aha! moment with feathersjs for cases as the third and first question is about.