Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 20 additions & 8 deletions src/Auth.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ public static function login_and_get_token( $username, $password ) {
* The token is signed, now create the object with basic user data to send to the client
*/
$response = [
'authToken' => self::get_signed_token( $user ),
'refreshToken' => self::get_refresh_token( $user ),
'authToken' => self::get_signed_token( wp_get_current_user() ),
'refreshToken' => self::get_refresh_token( wp_get_current_user() ),
'user' => DataSource::resolve_user( $user->data->ID, \WPGraphQL::get_app_context() ),
'id' => $user->data->ID,
];
Expand Down Expand Up @@ -123,7 +123,8 @@ public static function get_token_expiration() {
/**
* Retrieves validates user and retrieve signed token
*
* @param User|WP_User $user Owner of the token.
* @param \WP_User $user Owner of the token.
* @param bool $cap_check Whether to check capabilities when getting the token
*
* @return null|string
*/
Expand Down Expand Up @@ -200,11 +201,13 @@ protected static function get_signed_token( $user, $cap_check = true ) {
*/
public static function get_user_jwt_secret( $user_id ) {

$is_revoked = Auth::is_jwt_secret_revoked( $user_id );

/**
* If the secret has been revoked, throw an error
*/
if ( true === Auth::is_jwt_secret_revoked( $user_id ) ) {
return new \WP_Error( 'graphql-jwt-revoked-secret', __( 'The JWT Auth secret cannot be returned', 'wp-graphql-jwt-authentication' ) );
if ( true === (bool) $is_revoked ) {
return null;
}

/**
Expand All @@ -216,11 +219,11 @@ public static function get_user_jwt_secret( $user_id ) {
$capability = apply_filters( 'graphql_jwt_auth_edit_users_capability', 'edit_users', $user_id );

/**
* If the request is not from the current_user AND the current_user doesn't have the proper capabilities, don't return the secret
* If the request is not from the current_user or the current_user doesn't have the proper capabilities, don't return the secret
*/
$is_current_user = ( $user_id === get_current_user_id() ) ? true : false;
if ( ! $is_current_user && ! current_user_can( $capability ) ) {
return new \WP_Error( 'graphql-jwt-improper-capabilities', __( 'The JWT Auth secret for this user cannot be returned', 'wp-graphql-jwt-authentication' ) );
return null;
}

/**
Expand All @@ -232,7 +235,7 @@ public static function get_user_jwt_secret( $user_id ) {
* If there is no stored secret, or it's not a string
*/
if ( empty( $secret ) || ! is_string( $secret ) ) {
Auth::issue_new_user_secret( $user_id );
$secret = Auth::issue_new_user_secret( $user_id );
}

/**
Expand Down Expand Up @@ -291,13 +294,21 @@ public static function is_jwt_secret_revoked( $user_id ) {
* Public method for getting an Auth token for a given user
*
* @param \WP_USer $user The user to get the token for
* @param boolean $cap_check Whether to check capabilities. Default is true.
*
* @return null|string
*/
public static function get_token( $user, $cap_check = true ) {
return self::get_signed_token( $user, $cap_check );
}

/**
* Given a WP_User, this returns a refresh token for the user
* @param \WP_User $user A WP_User object
* @param bool $cap_check
*
* @return null|string
*/
public static function get_refresh_token( $user, $cap_check = true ) {

self::$is_refresh_token = true;
Expand All @@ -309,6 +320,7 @@ public static function get_refresh_token( $user, $cap_check = true ) {
*/
add_filter( 'graphql_jwt_auth_token_before_sign', function( $token, \WP_User $user ) {
$secret = Auth::get_user_jwt_secret( $user->ID );

if ( ! empty( $secret ) && ! is_wp_error( $secret ) && true === self::is_refresh_token() ) {

/**
Expand Down
60 changes: 50 additions & 10 deletions src/ManageTokens.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
namespace WPGraphQL\JWT_Authentication;

use GraphQL\Error\UserError;
use WPGraphQL\Model\User;

/**
* Class - ManageToken
Expand Down Expand Up @@ -75,46 +76,83 @@ public static function register_jwt_fields_to( $type ) {
'type' => 'String',
'description' => __( 'A JWT token that can be used in future requests for authentication/authorization', 'wp-graphql-jwt-authentication' ),
'resolve' => function ( $user ) {
$user = get_user_by( 'id', $user->ID );

$user_id = 0;
if ( isset( $user->userId ) ) {
$user_id = $user->userId;
} else if ( isset( $user->ID ) ) {
$user_id = $user->ID;
}

if ( ! $user instanceof \WP_User && ! empty( $user_id ) ) {
$user = get_user_by( 'id', $user_id );
}

// Get the token for the user.
$token = Auth::get_token( $user );

// If the token cannot be returned, throw an error.
if ( empty( $token ) || is_wp_error( $token ) ) {
if ( empty( $token ) ) {
throw new UserError( __( 'The JWT token could not be returned', 'wp-graphql-jwt-authentication' ) );
}

if ( $token instanceof \WP_Error ) {
throw new UserError( $token->get_error_message() );
}

return ! empty( $token ) ? $token : null;
},
],
'jwtRefreshToken' => [
'type' => 'String',
'description' => __( 'A JWT token that can be used in future requests to get a refreshed jwtAuthToken. If the refresh token used in a request is revoked or otherwise invalid, a valid Auth token will NOT be issued in the response headers.', 'wp-graphql-jwt-authentication' ),
'resolve' => function ( $user ) {
$user = get_user_by( 'id', $user->ID );

$user_id = 0;
if ( isset( $user->userId ) ) {
$user_id = $user->userId;
} else if ( isset( $user->ID ) ) {
$user_id = $user->ID;
}

if ( ! $user instanceof \WP_User && ! empty( $user_id ) ) {
$user = get_user_by( 'id', $user_id );
}

// Get the token for the user.
$token = Auth::get_refresh_token( $user );

// If the token cannot be returned, throw an error.
if ( empty( $token ) || is_wp_error( $token ) ) {
if ( empty( $token ) ) {
throw new UserError( __( 'The JWT token could not be returned', 'wp-graphql-jwt-authentication' ) );
}

if ( $token instanceof \WP_Error ) {
throw new UserError( $token->get_error_message() );
}

return ! empty( $token ) ? $token : null;
},
],
'jwtUserSecret' => [
'type' => 'String',
'description' => __( 'A unique secret tied to the users JWT token that can be revoked or refreshed. Revoking the secret prevents JWT tokens from being issued to the user. Refreshing the token invalidates previously issued tokens, but allows new tokens to be issued.', 'wp-graphql' ),
'resolve' => function ( $user ) {

$user_id = 0;

if ( isset( $user->userId ) ) {
$user_id = $user->userId;
} else if ( isset( $user->ID ) ) {
$user_id = $user->ID;
}

// Get the user's JWT Secret.
$secret = Auth::get_user_jwt_secret( $user->ID );
$secret = Auth::get_user_jwt_secret( $user_id );

// If the secret cannot be returned, throw an error.
if ( is_wp_error( $secret ) ) {
throw new UserError( __( 'The user secret could not be returned', 'wp-graphql-jwt-authentication' ) );
if ( $secret instanceof \WP_Error ) {
throw new UserError( $secret->get_error_message() );
}

// Return the secret.
Expand All @@ -134,7 +172,7 @@ public static function register_jwt_fields_to( $type ) {
'type' => [ 'non_null' => 'Boolean' ],
'description' => __( 'Whether the JWT User secret has been revoked. If the secret has been revoked, auth tokens will not be issued until an admin, or user with proper capabilities re-issues a secret for the user.', 'wp-graphql-jwt-authentication' ),
'resolve' => function ( $user ) {
$revoked = Auth::is_jwt_secret_revoked( $user->ID );
$revoked = Auth::is_jwt_secret_revoked( $user->userId );

return true === $revoked ? true : false;
},
Expand Down Expand Up @@ -229,9 +267,10 @@ public static function prevent_token_from_returning_if_revoked( $token, $user_id
/**
* Returns tokens in the response headers
*
* @param array $headers GraphQL HTTP response headers.
* @param array $headers GraphQL HTTP response headers.
*
* @return array
* @throws \Exception
*/
public static function add_tokens_to_graphql_response_headers( $headers ) {
/**
Expand Down Expand Up @@ -277,9 +316,10 @@ public static function add_tokens_to_graphql_response_headers( $headers ) {
* This allows clients the ability to Authenticate with WPGraphQL, use the token
* with REST API Requests, but get new refresh tokens from the REST API Headers
*
* @param WP_HTTP_Response $response Response object.
* @param \WP_HTTP_Response $response Response object.
*
* @return \WP_HTTP_Response
* @throws \Exception
*/
public static function add_auth_headers_to_rest_response( $response ) {
if ( ! $response instanceof \WP_HTTP_Response ) {
Expand Down