wp-graphql / wp-graphql-jwt-authentication

Authentication for WPGraphQL using JWT (JSON Web Tokens)
GNU General Public License v3.0
333 stars 73 forks source link

Add mutation to forceLogout or invalidateRefreshTokens of user #79

Open henrikwirth opened 4 years ago

henrikwirth commented 4 years ago

One thing I'm wondering is how to force logout users.

  1. When a user changes his password, all old Tokens should be invalid. Is this happening already?
  2. There should be a way to invalidate all refreshTokens, so all clients would have to login with user credentials again.
  3. Is it possible to only invalidate tokens, that are linked to one client?
jasonbahl commented 4 years ago

@henrikwirth these questions are great and much needed to bring clarity to this project.

When a user changes his password, all old Tokens should be invalid. Is this happening already?

This was a planned feature, but it has yet to be coded.


There should be a way to invalidate all refreshTokens, so all clients would have to login with user credentials again.

The "auth" token is free to use until it expires, which is why it's recommended to keep the expiration pretty short. I believe the default is 5 minutes.

The Refresh Token can be invalidated or revoked.

Invalidated Refresh Token

When a token is invalidated, it means the shape of existing tokens will no longer properly validate and users must login to get a new one.

The refresh tokens have a user_secret that is added to their hashed token. This secret is stored in user_meta under the key graphql_jwt_auth_secret.

If that meta value ever changes, all previously issued refresh tokens will fail to validate and users must login again to get new tokens.

This is essentially the same as "logout of all clients" as once the Auth tokens already granted to any client expire, refreshTokens will no longer work for getting new auth tokens.

Users can still login to get new tokens.

Revoked Refresh Token

When a Refresh Token is revoked, this means new tokens won't be granted to the user at all, even during a login mutation or refreshJwtAuthToken

The following static methods currently exist for revoking / unrevoking tokens:

Auth::revoke_user_secret( $user_id ) Auth::unrevoke_user_secret( $user_id )

At the moment, a Boolean input field named revokeJwtUserSecret exists on some mutations such as createUser, registerUser and updateUser where you can pass true to revoke tokens from the user (prevent new tokens from being issued), or false to unrevoke them (allow new tokens to be issued).

Currently, the requesting user must have the edit_users capability to revoke / unrevoke tokens.


Is it possible to only invalidate tokens, that are linked to one client?

No. Tokens aren't tied to any particular client.

henrikwirth commented 4 years ago

Thanks for clarifying.

For invalidating the Refresh Tokens/ changing user_secret: Is there a mutation for it? So the user can do something like Logout of all clients?

henrikwirth commented 4 years ago

@jasonbahl Okay so i just tried the refreshUserSecret and it works to create a new User Secret, but the old Auth Tokens still works. I can use the old Auth Token and also I can still use the Refresh Token.

atomicacorn commented 4 years ago

@jasonbahl Great plugin, thanks! I've followed the advice above, and found the same issue as @henrikwirth, changing the meta value graphql_jwt_auth_secret doesn't seem to invalidate previous refresh tokens. I can see that Auth tokens would still work as they don't have the user's secret encoded.

I dug around a little, and have tweaked the validate_token function in Auth.js in my plugin installation here to the following:

<?php

if ( isset( $token->data->user->user_secret ) ) {

  $token_user_secret = $token->data->user->user_secret;
  $current_user_secret = get_user_meta( $token->data->user->id, 'graphql_jwt_auth_secret', true );

if ( Auth::is_jwt_secret_revoked( $token->data->user->id ) || strcmp($token_user_secret, $current_user_secret) != 0 ) {
  return new \WP_Error( 'invalid-jwt', __( 'The User Secret does not match or has been revoked for this user', 'wp-graphql-jwt-authentication' ) );
}

I can see this is an open issue. Is there any reason the above isn't OK? I'd rather not revoke tokens, as I'm just trying to provide a "logout" style feature for an app.

Appreciate the feedback!

spiralni commented 3 years ago

Why you just don't delete the token from your client app?

olatechpro commented 7 months ago

@spiralni Your suggestion is not really the best way to go about it.

What if user log in on a public computer and after awhile, they noticed suspicious activities on their account and decided to change password? That shows changing password doesn't matter as they'll still be logged in on other browser.

I think we do need a way to destroy all session.