Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
18 changes: 16 additions & 2 deletions admin/section/class-convertkit-admin-section-general.php
Original file line number Diff line number Diff line change
Expand Up @@ -193,9 +193,23 @@ private function maybe_disconnect() {
return;
}

// Delete Access Token.
// Get Settings class.
$settings = new ConvertKit_Settings();
$settings->delete_credentials();

// Revoke Access Token.
$api = new ConvertKit_API_V4(
Comment thread
n7studios marked this conversation as resolved.
Outdated
CONVERTKIT_OAUTH_CLIENT_ID,
CONVERTKIT_OAUTH_CLIENT_REDIRECT_URI,
$settings->get_access_token(),
$settings->get_refresh_token(),
$settings->debug_enabled(),
'settings'
);
$result = $api->revoke_token();
if ( is_wp_error( $result ) ) {
$this->output_error( $result->get_error_message() );
return;
}

// Delete cached resources.
$creator_network = new ConvertKit_Resource_Creator_Network_Recommendations();
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"type": "project",
"license": "GPLv3",
"require": {
"convertkit/convertkit-wordpress-libraries": "2.1.3"
"convertkit/convertkit-wordpress-libraries": "dev-add-revoke-token-method"
Comment thread
n7studios marked this conversation as resolved.
Outdated
},
"require-dev": {
"php-webdriver/webdriver": "^1.0",
Expand Down
26 changes: 26 additions & 0 deletions includes/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -792,6 +792,29 @@ function convertkit_maybe_update_credentials( $result, $client_id ) {

}

/**
* Deletes the stored access token, refresh token and its expiry from the Plugin settings,
* and clears any existing scheduled WordPress Cron event to refresh the token on expiry,
* when the user revokes the access token.
*
* @since 3.2.4
*
* @param string $client_id OAuth Client ID used for the Access and Refresh Tokens.
*/
function convertkit_revoke_credentials( $client_id ) {
Comment thread
n7studios marked this conversation as resolved.
Outdated

// Don't delete these credentials if they're not for this Client ID.
// They're for another Kit Plugin that uses OAuth.
if ( $client_id !== CONVERTKIT_OAUTH_CLIENT_ID ) {
return;
}

// Delete Access and Refresh Tokens.
$settings = new ConvertKit_Settings();
$settings->delete_credentials();
Comment thread
n7studios marked this conversation as resolved.

}

/**
* Deletes the stored access token, refresh token and its expiry from the Plugin settings,
* and clears any existing scheduled WordPress Cron event to refresh the token on expiry,
Expand Down Expand Up @@ -830,6 +853,9 @@ function convertkit_maybe_delete_credentials( $result, $client_id ) {
add_action( 'convertkit_api_get_access_token', 'convertkit_maybe_update_credentials', 10, 2 );
add_action( 'convertkit_api_refresh_token', 'convertkit_maybe_update_credentials', 10, 2 );

// Delete credentials when the user revokes the access token.
add_action( 'convertkit_api_revoke_token', 'convertkit_revoke_credentials', 10, 1 );

// Delete credentials if the API class uses a invalid access token.
// This prevents the Plugin making repetitive API requests that will 401.
add_action( 'convertkit_api_access_token_invalid', 'convertkit_maybe_delete_credentials', 10, 2 );
54 changes: 54 additions & 0 deletions tests/Integration/APITest.php
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,60 @@ public function testCronEventCreatedWhenTokenRefreshed()
$this->assertGreaterThanOrEqual( $nextScheduledTimestamp, time() + 10000 );
}

/**
* Test that the access token and refresh token are deleted from the Plugin's settings
* when the access token is revoked.
*
* @since 3.2.4
*/
public function testCredentialsDeletedAndInvalidWhenRevoked()
{
// Initialize the API without an access token or refresh token.
$api = new \ConvertKit_API_V4(
$_ENV['CONVERTKIT_OAUTH_CLIENT_ID'],
$_ENV['KIT_OAUTH_REDIRECT_URI']
);

// Generate an access token by API key and secret.
$result = $api->get_access_token_by_api_key_and_secret(
$_ENV['CONVERTKIT_API_KEY'],
$_ENV['CONVERTKIT_API_SECRET'],
wp_generate_password( 10, false ) // Random tenant name to produce a token for this request only.
);

// Store the access token in the Plugin's settings.
$settings = new \ConvertKit_Settings();
$settings->save(
array(
'access_token' => $result['oauth']['access_token'],
'refresh_token' => $result['oauth']['refresh_token'],
'token_expires' => $result['oauth']['expires_at'],
)
);

// Initialize the API with the access token and refresh token.
$api = new \ConvertKit_API_V4(
$_ENV['CONVERTKIT_OAUTH_CLIENT_ID'],
$_ENV['KIT_OAUTH_REDIRECT_URI'],
$settings->get_access_token(),
$settings->get_refresh_token()
);

// Confirm the token works when making an authenticated request.
$this->assertNotInstanceOf( 'WP_Error', $api->get_account() );

// Revoke the access token.
$api->revoke_token();

// Confirm the access token and refresh token are deleted from the Plugin's settings.
$this->assertEmpty( $settings->get_access_token() );
$this->assertEmpty( $settings->get_refresh_token() );
$this->assertEmpty( $settings->get_token_expiry() );

// Confirm the token no longer works when making an authenticated request.
$this->assertInstanceOf( 'WP_Error', $api->get_account() );
}

/**
* Mocks an API response as if the Access Token expired.
*
Expand Down