feathersjs-ecosystem/feathers-authentication-management

Rework

TheSinding opened this issue · 22 comments

I was thinking about whether we should rework the repo.
I have two suggestion in mind.

  1. Moving the source code to a TypeScript base.
    I would argue this is more maintainable and this would also help with intellisense in various IDE's.

  2. This is more radical - Moving away from actions in data and instead use authmanagement/{action} .
    So a reset password would move from

{
    "action": "resetShortToken",
    "data": { ... }
}

To a more REST like approach with /authmanagement/reset
This would make it work more like a REST API and as well as a standard feathers service.

I realize this would be breaking changes, but I think it would benefit the overall structure of calling the API

Let me know what you think, and if I should elaborate.

Personally I am not convinced at all by TypeScript, I share a lot with https://medium.com/javascript-scene/the-typescript-tax-132ff4cb175b notably that type safety doesn’t seem to make a big difference and 99% of the bugs are not linked to it (I come from a long C++ background and I have a good idea about this). Moreover, I was using babel for a while in order to create isomorphic code and now Nodejs is supporting most of ES6 including import/export I am pretty happy to go away from transpiling. As a consequence TS seems to me a step back. However, this is a community-driven project and if most people prefer to go for TS I don't have any problem with this, I will try to help.

About the more "REST" approach I would argue that it will completely break the API and this is not really what users want except if it is balanced by huge improvements in functionalities, security or whatever. Moreover, a lot of people are using it with websockets and are far less concerned by this topic. Last but not least, it seems to be that the current implementation relies on the "recommended way" by the Feathers team itself (see eg feathersjs/feathers#488 and https://docs.feathersjs.com/help/faq.html#what-node-versions-does-feathers-support). But maybe you can detail a little bit more your though, do you want to create a service with a create method per authentication management operation for instance ?

Thanks for taking time to try enhancing the module, I hope others will provide their own views.

I'm working on a typescript fork of this module and will be ready in a few days for me the IntelliSense alone is enough many actions with different properties, if you decided to migrate I'll be very happy to participate.

PRs are welcome, waiting for your feedback.

it will take some work to merge the changes here so please give it a look and if everything is good I'll open a PR.

https://github.com/MohammedFaragallah/feathers-authentication-management-ts
https://www.npmjs.com/package/feathers-authentication-management-ts

I tested it in JS/TS projects there are no breaking changes only some type related changes for TS projects

- "feathers-authentication-management": "^2.0.1",
+ "feathers-authentication-management-ts": "^1.0.0",

I think a PR is the good way to go because we can then easily compare changes and review code. Do you plan to migrate the tests as well ? That's probably the best way to see if there are no breaking changes.

Not sure to have time to look at it really soon however.

Thanks again.

I would test the TS version in our app, however, it seems it has to be installed with Yarn, which we do not use in our projects:

feathers-authentication-management-ts@1.0.0 preinstall: `node -e "if(process.env.npm_execpath.indexOf('yarn') === -1) throw new Error('feathers-authentication-management-ts must be installed with Yarn: https://yarnpkg.com/')"`

In general, I agree with claustres. There are benefits in using TypeScript, but in our Feathers apps we still use pure NodeJS/ES6. And we hesitate to migrate just for type safety and intellisense. But I will not stand against it, if this package is moving to TS.

We have to be a little careful about the maintenance of this project. We are just trying to take it over, so if new maintainers are coming, willing to support and think it will be better with TS go for it. However, if this is just a one shot to be "up-to-date" and then the current maintainers are forced to manage a new code version and tooling they don't know without any support after the migration I am pretty reluctant at this stage. Let me know what you think.

I see both of your points @OnnoGabriel and @claustres and I agree if we are moving to typescript we should have some sort of migration plan.

Regarding the RPC and actions the reasoning I had was regarding the hooks of a service.
We started with the RPC approach in our project, but the x.hooks.{js|ts} file of a service quickly became cluttered with hooks which would only run when a specific action was given.
But as I'm typing this, I realize that this is only a "issue" behind the scenes and wouldn't benefit the user. Though I still argue that it would be a better approach to split out the actions into paths, if this were a purely REST API.
IMO it would better describe the API.

But as you argue, people mostly use sockets, and it would only be a pain for those and I totally agree.
Also it wouldn't be an improvement in performance and only break the API for all users.

it seems it has to be installed with Yarn

fixed

I think a good start would be adding types without typescript for IntelliSense and type safety in projects using TS.

@MohammedFaragallah - I agree, that makes total sense.

If I may chip in.. I like the idea of REST-like approach (e.g authmanagement/reset) and so on as mentioned by @TheSinding but that would meant a number of services rather than a single service, am I right? Using { data } is a little tough on documentation wise, since it's a single service with multiple types. Not sure if can define clearly in docs like swagger.

I have a single (feathers) backend which supports for WS/REST connection for different type of client (web, mobile, apps), hence, having a more structure and defined service(s) is definitely going to make it a lot better for my case. Breaking change for sure, but I do see the benefit of it.

As of whether to move to typescript, I think we should start by providing @types rather than diving straight into refactoring the entire library as typescript-based.

I am wondering if we cannot simply provide a REST wrapper connecting routes to service operations as for sockets it is not so relevant (although we could also provide an event wrapper). No breaking change, nothing intrusive, what do you think ?

@bwgjoseph
True, we should provide the @types as it would be a big job to refactor all the code.

@claustres
That's not a bad idea actually and it would be a fairly easy job as well (famous last words)

guzz commented

Hi everyone, I like @claustres idea. Another thing I have implemented in my apps using feathers-authentication-management is a two-factor login/confirmation, maybe this could be a new feature of the release.

@guzz - Make a PR and we'll take a look at it :)

REST wrapper as in exposing a express route and then call the service (internally)?

// /authm/<action> as expose to external

// Different class? Both create will call the `authmanagement` method
app.use('/authm/forget', new AuthForget());
app.use('/authm/reset', new AuthReset());

// I'm not sure if you can init same class, and call the internal methods
app.use('/authm/forget', new AuthM());
app.use('/authm/reset', new AuthM());

class AuthM {
  forgetPassword = (data) => {
    this.app.service('authmanagement').create({
      action: 'resetPwdLong',
      value: data,
    })
  }

  // reset password and so on
}

I think one good thing about this is that it works for both REST/WS since it's tapping back to feathers-service? Never done anything like this before, so not sure if it's feasible..

Yes a wrapper binding routes to service operations, something like this (not tested):

app.post('/authm/forget', async (req, res) => {
  const result = await app.service('authmanagement').create({
      action: 'resetPwdLong',
      value: req.body,
    })
  res.json(result)
})

When I wrap, I usually create a custom service for the specific wrapper.

it will take some work to merge the changes here so please give it a look and if everything is good I'll open a PR.

https://github.com/MohammedFaragallah/feathers-authentication-management-ts
https://www.npmjs.com/package/feathers-authentication-management-ts

I tested it in JS/TS projects there are no breaking changes only some type related changes for TS projects

- "feathers-authentication-management": "^2.0.1",
+ "feathers-authentication-management-ts": "^1.0.0",

would you mind sharing code of your implementation ?
didn't get same behavior my side... but I'm at my first implementation of auth management with feathers (and going a bit crazy) as can't find proper exemple to base myself onto.

ie: how to declare notify():Notify ?

I'm happy to help build an exemple app with a full implementation of auth management.. It's such a common thing to use in projects, can't believe the time I'm waisting on this!

PS: not sure if I should have posted this in the right thread... sorry will follow up on feathers-authentication-management-ts
lov

@guzz I also need a 2nd factor auth in my project and I'm about to work on adding it to feathers-authentication-management.
Would you like to share your code ?

first official typescript release:

npm i feathers-authentication-management@pre

also checkout https://feathers-a-m.netlify.app/ for the new docs made by @OnnoGabriel 🎉.
The release aims to have no breaking changes at all.
But it also has a lot of new things. Every action is now callable in three ways:

  1. old traditional way
  2. through a separate service like: app.use('auth-management/password-change', new PasswordChangeService(app))
  3. through custom methods: app.service('authManagement').passwordChange(...) (in preparation of feathers v5)

Option 2 and 3 also have a flattened data argument. Please see the comparison:

const { AuthenticationManagementService } = require('feathers-authentication-management');

app.use('auth-management', new AuthenticationManagementService(app, options));

app.service('auth-management').create({
  action: 'passwordChange',
  value: {
    user: identifyUser, // identify user, e.g. {email: 'a@a.com'}. See options.identifyUserProps.
    oldPassword, // old password for verification
    password, // new password
    notifierOptions: {}, // optional - an object passed to notifier function
  },
}
const { PasswordChangeService } = require('feathers-authentication-management');

app.use("auth-management/password-change", new PasswordChangeService(app, options));

app.service('auth-management/password-change').create({
  user: identifyUser, // identify user, e.g. {email: 'a@a.com'}. See options.identifyUserProps.
  oldPassword, // old password for verification
  password, // new password
  notifierOptions: {}, // optional - an object passed to notifier function
}

I think once we ship the pre-release as an official release, we can close this issue. What do you think? Is there anyone who's willing to test out the new pre release?