feathersjs-ecosystem / feathers-authentication-management

Adds sign up verification, forgotten password reset, and other capabilities to local feathers-authentication
https://feathers-a-m.netlify.app/
MIT License
246 stars 98 forks source link

[FR] Support revocation date #205

Open FossPrime opened 1 year ago

FossPrime commented 1 year ago

Having a revokedAt field would allows to cheaply invalidate existing JWT tokens.

Steps to reproduce

  1. Have your session cookies compromised, Like LTT recently did
  2. Change your password

Expected behavior

Attacker should not be able to log in.

Actual behavior

JWT cookie will still be valid. So would the socketio reconnection key. Allowing the attacker to login to your account, despite having changed your password.

Context

I use SAML where cascading logouts are a core feature. You should be able to logout once, and have all your SAML apps be disconnected remotely.

claustres commented 1 year ago

As far as I know there is no way to revoke the token in a pure stateless authentication as the token itself is the sole source of truth, and any revocation mechanism of tokens is currently not really standardized in OAuth (see https://datatracker.ietf.org/doc/html/rfc7009#section-3). So maybe you could more detail what you are thinking about with this revokedAt field ?

I wonder as well if this issue should not be directly posted to feathers authentication package as authentication management is not responsible of issuing or validating tokens. Notably, although Single Logout is a feature you'd like to have with token revocation, it's also a feature by itself, not directly related to revocation.

FossPrime commented 1 year ago

Authentication-management handles changing the password during password resets. revokeJWTHook could be an after hook on the authentication service that blocks logging-in with JWT's created before revokedAt timestamp.

claustres commented 1 year ago

I think it's more general as I could want to revoke tokens event without changing the user password, think about the case of users connected by OAuth or if I don't want to rely on the fact the user changes his password to ensure security. So for me these hooks could be at feathers authentication level as well to be used in others operations.

Sorry, but it's not yet clear what is the mechanism you'd like. The revokedAt field should be set on the user so that all tokens generated prior to it should be considered invalid ?

The easiest way to revoke tokens instantaneously is to change the secret used to generate it or some built-in fields like the issuer. So maybe we should use the encrypted password of the user to generate his tokens so that when changing the password they automatically become invalid. I am not an authentication expert so I wonder if it could be possible to generate/validate tokens with such a dynamic behaviour.

FossPrime commented 1 year ago

We can easily regenerate the bcrypt salt... as long as we have the user's password. We can't invalidate JWT's with salting or a revokation array without incurring a performance penalty before the call to the User service.

If we use revokedAt as a userField in the user service, it would be extremely cheap to revoke whenever OAuth/SAML, if the user asks us to, or if fishy behavior is detected.

OnnoGabriel commented 1 year ago

revokeJWTHook could be an after hook on the authentication service that blocks logging-in with JWT's created before revokedAt timestamp.

Do you want to revoke an issued JWT? There is an example in the Feathers cookbook: https://feathersjs.com/cookbook/authentication/revoke-jwt.html

Or do you want to disable the login/authentication for a user in general? In that case I agree with @claustres that such a function should be implemented as an extension of the authentication service and not of this package. We do something similar with an after hook in the authentication service, where we check user.isActive and throw an authentication error if false.