diff --git a/README.txt b/README.txt
index f689305..7a02f5a 100644
--- a/README.txt
+++ b/README.txt
@@ -201,6 +201,17 @@ On the client website:
    (admin/content/entity_share/pull), and select your remote website, the
    available channels will be listed and when selecting a channel, the entities
    exposed on this channel will be available to synchronize.
+ * Optional Key Module Integration
+   - https://www.drupal.org/project/key
+   - https://www.drupal.org/docs/8/modules/key/concepts-and-terminology
+   Credentials used to authorize pulling from remotes may be more securely stored
+   using the Key module.  Additional optional modules allow the storage in an
+   external key/value storage service.  With only the Key module credentials may
+   be stored in JSON format in files outside the web root.
+   1. Configure Keys: Key types for Entity Share are listed in Key config form
+   (/admin/config/system/keys). Instructions for each type are shown in the form.
+   2. Create a remote and select Key module as the credential provider, then
+   select the appropriate key.


 TROUBLESHOOTING
diff --git a/modules/entity_share_client/config/schema/entity_share_client.schema.yml b/modules/entity_share_client/config/schema/entity_share_client.schema.yml
new file mode 100644
index 0000000..bd4bdb1
--- /dev/null
+++ b/modules/entity_share_client/config/schema/entity_share_client.schema.yml
@@ -0,0 +1,38 @@
+entity_share_client.remote.*:
+  type: config_entity
+  label: 'Remote config'
+  mapping:
+    id:
+      type: string
+      label: 'ID'
+    label:
+      type: label
+      label: 'Label'
+    url:
+      type: string
+      label: 'URL'
+    auth:
+      type: mapping
+      mapping:
+        pid:
+          label: 'Plugin ID'
+          type: string
+        uuid:
+            label: 'UUID'
+            type: string
+        verified:
+          label: 'Verified'
+          type: boolean
+        data:
+          type: mapping
+          label: 'Credential data'
+          mapping:
+            credential_provider:
+              type: string
+              label: 'Credential provider'
+            storage_key:
+              type: string
+              label: 'Storage key'
+
+key.type.entity_share_basic_auth:
+  type: sequence
diff --git a/modules/entity_share_client/config/schema/remote.schema.yml b/modules/entity_share_client/config/schema/remote.schema.yml
deleted file mode 100644
index cd30b16..0000000
--- a/modules/entity_share_client/config/schema/remote.schema.yml
+++ /dev/null
@@ -1,19 +0,0 @@
-entity_share_client.remote.*:
-  type: config_entity
-  label: 'Remote config'
-  mapping:
-    id:
-      type: string
-      label: 'ID'
-    label:
-      type: label
-      label: 'Label'
-    url:
-      type: string
-      label: 'URL'
-    basic_auth_username:
-      type: string
-      label: 'Basic auth username'
-    basic_auth_password:
-      type: string
-      label: 'Basic auth password'
diff --git a/modules/entity_share_client/entity_share_client.install b/modules/entity_share_client/entity_share_client.install
index 242ec0b..ff0fab1 100644
--- a/modules/entity_share_client/entity_share_client.install
+++ b/modules/entity_share_client/entity_share_client.install
@@ -40,3 +40,34 @@ function entity_share_client_update_8302() {
     ],
   ]));
 }
+
+/**
+ * Move any basic auth credentials stored in configuration into the new plugin.
+ */
+function entity_share_client_update_8303() {
+  /** @var \Drupal\entity_share_client\Plugin\ClientAuthorizationManager $manager */
+  $manager = \Drupal::service('plugin.manager.entity_share_auth');
+  $state = \Drupal::state();
+  // Iterate remotes.
+  /** @var \Drupal\entity_share_client\Entity\Remote[] $remotes */
+  $remotes = Remote::loadMultiple();
+  foreach ($remotes as $remote) {
+    /** @var \Drupal\entity_share_client\Plugin\ClientAuthorization\BasicAuth $plugin */
+    $plugin = $manager->createInstance('basic_auth');
+    $configuration = $plugin->getConfiguration();
+    $credentials = [];
+    $credentials['username'] = $remote->get('basic_auth_username');
+    $credentials['password'] = $remote->get('basic_auth_password');
+    unset($remote->basic_auth_username);
+    unset($remote->basic_auth_password);
+    $state->set($configuration['uuid'], $credentials);
+    $key = $configuration['uuid'];
+    $configuration['data'] = [
+      'credential_provider' => 'entity_share',
+      'storage_key' => $key,
+    ];
+    $plugin->setConfiguration($configuration);
+    $remote->mergePluginConfig($plugin);
+    $remote->save();
+  }
+}
diff --git a/modules/entity_share_client/entity_share_client.services.yml b/modules/entity_share_client/entity_share_client.services.yml
index 2fb5a23..d4cd492 100644
--- a/modules/entity_share_client/entity_share_client.services.yml
+++ b/modules/entity_share_client/entity_share_client.services.yml
@@ -18,7 +18,6 @@ services:
   entity_share_client.remote_manager:
     class: Drupal\entity_share_client\Service\RemoteManager
     arguments:
-      - '@http_client_factory'
       - '@logger.channel.entity_share_client'

   entity_share_client.import_service:
@@ -67,3 +66,13 @@ services:
     arguments:
       - '@string_translation'
       - '@entity_share_client.import_service'
+
+  entity_share_client.key_provider:
+    class: Drupal\entity_share_client\Service\KeyProvider
+    arguments: ['@state']
+    calls:
+      - [setKeyRepository, ['@?key.repository']]
+
+  plugin.manager.entity_share_auth:
+    class: Drupal\entity_share_client\Plugin\ClientAuthorizationManager
+    parent: default_plugin_manager
diff --git a/modules/entity_share_client/src/Annotation/ClientAuthorization.php b/modules/entity_share_client/src/Annotation/ClientAuthorization.php
new file mode 100644
index 0000000..8a8a5b2
--- /dev/null
+++ b/modules/entity_share_client/src/Annotation/ClientAuthorization.php
@@ -0,0 +1,41 @@
+<?php
+
+namespace Drupal\entity_share_client\Annotation;
+
+use Drupal\Component\Annotation\Plugin;
+
+/**
+ * Defines an Entity Share Client authorization annotation object.
+ *
+ * The Entity Share Client must be authorized to pull entities from the
+ * Entity Share Server offering the content.  Such authorization could be
+ * by authenticating as an authorized user or it could be by presententing
+ * some previously created proof of authorization, such as an OAuth2 token.
+ *
+ * @see \Drupal\entity_share_client\Plugin\ClientAuthorizationManager
+ * @see plugin_api
+ *
+ * @Annotation
+ */
+class ClientAuthorization extends Plugin {
+
+
+  /**
+   * The plugin ID.
+   *
+   * A machine name for the authorization type provided by this plugin.
+   *
+   * @var string
+   */
+  public $id;
+
+  /**
+   * A human readable name for the authorization type provided by this plugin.
+   *
+   * @var \Drupal\Core\Annotation\Translation
+   *
+   * @ingroup plugin_translatable
+   */
+  public $label;
+
+}
diff --git a/modules/entity_share_client/src/Entity/Remote.php b/modules/entity_share_client/src/Entity/Remote.php
index 3328bd7..553ba8a 100644
--- a/modules/entity_share_client/src/Entity/Remote.php
+++ b/modules/entity_share_client/src/Entity/Remote.php
@@ -6,6 +6,7 @@ namespace Drupal\entity_share_client\Entity;

 use Drupal\Core\Config\Entity\ConfigEntityBase;
 use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\entity_share_client\Plugin\ClientAuthorizationInterface;

 /**
  * Defines the Remote entity.
@@ -35,8 +36,7 @@ use Drupal\Core\Entity\EntityStorageInterface;
  *     "id",
  *     "label",
  *     "url",
- *     "basic_auth_username",
- *     "basic_auth_password",
+ *     "auth",
  *   },
  *   links = {
  *     "canonical" = "/admin/config/services/entity_share/remote/{remote}",
@@ -71,18 +71,11 @@ class Remote extends ConfigEntityBase implements RemoteInterface {
   protected $url;

   /**
-   * The Remote basic auth username.
+   * An associative array of the authorization plugin data.
    *
-   * @var string
-   */
-  protected $basic_auth_username;
-
-  /**
-   * The Remote basic auth password.
-   *
-   * @var string
+   * @var array
    */
-  protected $basic_auth_password;
+  protected $auth;

   /**
    * {@inheritdoc}
@@ -98,4 +91,41 @@ class Remote extends ConfigEntityBase implements RemoteInterface {
     }
   }

+  /**
+   * {@inheritdoc}
+   */
+  public function getAuthPlugin() {
+    $pluginData = $this->auth;
+    if (!empty($pluginData['pid'])) {
+      // DI not available in entities:
+      // https://www.drupal.org/project/drupal/issues/2142515.
+      /** @var \Drupal\entity_share_client\Plugin\ClientAuthorizationManager $manager */
+      $manager = \Drupal::service('plugin.manager.entity_share_auth');
+      $pluginId = $pluginData['pid'];
+      unset($pluginData['pid']);
+      return $manager->createInstance($pluginId, $pluginData);
+    }
+    return NULL;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function mergePluginConfig(ClientAuthorizationInterface $plugin) {
+    $auth = ['pid' => $plugin->getPluginId()] +
+      $plugin->getConfiguration();
+    $this->auth = $auth;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getHttpClient(bool $json) {
+    $plugin = $this->getAuthPlugin();
+    if ($json) {
+      return $plugin->getJsonApiClient($this->url);
+    }
+    return $plugin->getClient($this->url);
+  }
+
 }
diff --git a/modules/entity_share_client/src/Entity/RemoteInterface.php b/modules/entity_share_client/src/Entity/RemoteInterface.php
index 77d1147..e667f5f 100644
--- a/modules/entity_share_client/src/Entity/RemoteInterface.php
+++ b/modules/entity_share_client/src/Entity/RemoteInterface.php
@@ -5,11 +5,40 @@ declare(strict_types = 1);
 namespace Drupal\entity_share_client\Entity;

 use Drupal\Core\Config\Entity\ConfigEntityInterface;
+use Drupal\entity_share_client\Plugin\ClientAuthorizationInterface;

 /**
  * Provides an interface for defining Remote entities.
  */
 interface RemoteInterface extends ConfigEntityInterface {

-  // Add get/set methods for your configuration properties here.
+  /**
+   * Copies plugin specific data into the Remote.
+   *
+   * @param \Drupal\entity_share_client\Plugin\ClientAuthorizationInterface $plugin
+   *   The authorization plugin to merge.
+   */
+  public function mergePluginConfig(ClientAuthorizationInterface $plugin);
+
+  /**
+   * Helper method to instantiate auth plugin from this entity.
+   *
+   * @return \Drupal\entity_share_client\Plugin\ClientAuthorizationInterface|null
+   *   The plugin if it is defined.
+   *
+   * @throws \Drupal\Component\Plugin\Exception\PluginException
+   */
+  public function getAuthPlugin();
+
+  /**
+   * Prepares a client object with options pulled from the auth plugin.
+   *
+   * @param bool $json
+   *   Is this client for JSON operations?
+   *
+   * @return \GuzzleHttp\Client
+   *   The configured client.
+   */
+  public function getHttpClient(bool $json);
+
 }
diff --git a/modules/entity_share_client/src/Form/RemoteForm.php b/modules/entity_share_client/src/Form/RemoteForm.php
index 397077b..14077d1 100644
--- a/modules/entity_share_client/src/Form/RemoteForm.php
+++ b/modules/entity_share_client/src/Form/RemoteForm.php
@@ -7,6 +7,9 @@ namespace Drupal\entity_share_client\Form;
 use Drupal\Component\Utility\UrlHelper;
 use Drupal\Core\Entity\EntityForm;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Form\SubformState;
+use Drupal\entity_share_client\Plugin\ClientAuthorizationInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;

 /**
  * Class RemoteForm.
@@ -15,6 +18,29 @@ use Drupal\Core\Form\FormStateInterface;
  */
 class RemoteForm extends EntityForm {

+  /**
+   * Injected plugin service.
+   *
+   * @var \Drupal\entity_share_client\Plugin\ClientAuthorizationManager
+   */
+  protected $authPluginManager;
+
+  /**
+   * The currently configured auth plugin.
+   *
+   * @var \Drupal\entity_share_client\Plugin\ClientAuthorizationInterface
+   */
+  protected $authPlugin;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    $instance = parent::create($container);
+    $instance->authPluginManager = $container->get('plugin.manager.entity_share_auth');
+    return $instance;
+  }
+
   /**
    * {@inheritdoc}
    */
@@ -36,6 +62,7 @@ class RemoteForm extends EntityForm {
       '#type' => 'machine_name',
       '#default_value' => $remote->id(),
       '#machine_name' => [
+        'source' => ['label'],
         'exists' => '\Drupal\entity_share_client\Entity\Remote::load',
       ],
       '#disabled' => !$remote->isNew(),
@@ -50,23 +77,7 @@ class RemoteForm extends EntityForm {
       '#required' => TRUE,
     ];

-    $form['basic_auth'] = [
-      '#type' => 'fieldset',
-      '#title' => $this->t('Basic Auth'),
-    ];
-
-    $form['basic_auth']['basic_auth_username'] = [
-      '#type' => 'textfield',
-      '#title' => $this->t('Username'),
-      '#default_value' => $remote->get('basic_auth_username'),
-      '#required' => TRUE,
-    ];
-
-    $form['basic_auth']['basic_auth_password'] = [
-      '#type' => 'password',
-      '#title' => $this->t('Password'),
-      '#required' => TRUE,
-    ];
+    $this->addAuthOptions($form, $form_state);

     return $form;
   }
@@ -79,6 +90,22 @@ class RemoteForm extends EntityForm {
     if (!UrlHelper::isValid($form_state->getValue('url'), TRUE)) {
       $form_state->setError($form['url'], $this->t('Invalid URL.'));
     }
+    $selectedPlugin = $this->getSelectedPlugin($form, $form_state);
+    $subformState = SubformState::createForSubform($form['auth']['data'], $form, $form_state);
+    $selectedPlugin->validateConfigurationForm($form['auth']['data'], $subformState);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitForm(array &$form, FormStateInterface $form_state) {
+    parent::submitForm(
+      $form,
+      $form_state
+    );
+    $selectedPlugin = $this->getSelectedPlugin($form, $form_state);
+    $subformState = SubformState::createForSubform($form['auth']['data'], $form, $form_state);
+    $selectedPlugin->submitConfigurationForm($form['auth']['data'], $subformState);
   }

   /**
@@ -87,6 +114,12 @@ class RemoteForm extends EntityForm {
   public function save(array $form, FormStateInterface $form_state) {
     /** @var \Drupal\entity_share_client\Entity\RemoteInterface $remote */
     $remote = $this->entity;
+
+    if (!empty($form['auth']['#plugins'])) {
+      $selectedPlugin = $this->getSelectedPlugin($form, $form_state);
+      $remote->mergePluginConfig($selectedPlugin);
+    }
+
     $status = $remote->save();

     switch ($status) {
@@ -104,4 +137,91 @@ class RemoteForm extends EntityForm {
     $form_state->setRedirectUrl($remote->toUrl('collection'));
   }

+  /**
+   * Helper function to build the authorization options in the form.
+   *
+   * @param array $form
+   *   The form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current form state.
+   *
+   * @throws \Drupal\Component\Plugin\Exception\PluginException
+   */
+  protected function addAuthOptions(array &$form, FormStateInterface $form_state) {
+    $options = [];
+    $plugins = [];
+    if ($this->getAuthPlugin()) {
+      $options[$this->authPlugin->getPluginId()] = $this->authPlugin->getLabel();
+      $plugins[$this->authPlugin->getPluginId()] = $this->authPlugin;
+    }
+    $availableTypes = $this->authPluginManager->getDefinitions();
+    foreach ($availableTypes as $definition) {
+      if (empty($options[$definition['id']])) {
+        // This plugin type was not previously set as an option.
+        /** @var \Drupal\entity_share_client\Plugin\ClientAuthorizationInterface $plugin */
+        $plugin = $this->authPluginManager->createInstance($definition['id']);
+        $plugins[$plugin->getPluginId()] = $plugin;
+        $options[$plugin->getPluginId()] = $plugin->getLabel();
+      }
+    }
+    // If we still don't have an auth plugin, use the first option.
+    if (empty($this->authPlugin)) {
+      $this->authPlugin = reset($plugins);
+    }
+    $form['auth'] = [
+      '#type' => 'container',
+      '#plugins' => $plugins,
+      'pid' => [
+        '#type' => 'radios',
+        '#title' => $this->t('Authorization methods'),
+        '#options' => $options,
+        '#default_value' => $this->authPlugin->getPluginId(),
+      ],
+      'data' => [],
+    ];
+    $subformState = SubformState::createForSubform($form['auth']['data'], $form, $form_state);
+    $form['auth']['data'] = $this->authPlugin->buildConfigurationForm($form['auth']['data'], $subformState);
+    $form['auth']['data']['#tree'] = TRUE;
+  }
+
+  /**
+   * Helper method to instantiate plugin from this entity.
+   *
+   * @return bool
+   *   The Remote entity has a plugin.
+   *
+   * @throws \Drupal\Component\Plugin\Exception\PluginException
+   */
+  protected function getAuthPlugin() {
+    /** @var \Drupal\entity_share_client\Entity\RemoteInterface $remote */
+    $remote = $this->entity;
+    $plugin = $remote->getAuthPlugin();
+    if ($plugin instanceof ClientAuthorizationInterface) {
+      $this->authPlugin = $plugin;
+      return TRUE;
+    }
+    return FALSE;
+  }
+
+  /**
+   * Helper method to get selected plugin from the form.
+   *
+   * @param array $form
+   *   The form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current form state.
+   *
+   * @return \Drupal\entity_share_client\Plugin\ClientAuthorizationInterface
+   *   The selected plugin.
+   */
+  protected function getSelectedPlugin(
+    array &$form,
+    FormStateInterface $form_state) {
+    $authPluginId = $form_state->getValue('pid');
+    $plugins = $form['auth']['#plugins'];
+    /** @var \Drupal\entity_share_client\Plugin\ClientAuthorizationInterface $selectedPlugin */
+    $selectedPlugin = $plugins[$authPluginId];
+    return $selectedPlugin;
+  }
+
 }
diff --git a/modules/entity_share_client/src/Plugin/ClientAuthorization/BasicAuth.php b/modules/entity_share_client/src/Plugin/ClientAuthorization/BasicAuth.php
new file mode 100644
index 0000000..a3da4e7
--- /dev/null
+++ b/modules/entity_share_client/src/Plugin/ClientAuthorization/BasicAuth.php
@@ -0,0 +1,95 @@
+<?php
+
+namespace Drupal\entity_share_client\Plugin\ClientAuthorization;
+
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\entity_share_client\Plugin\ClientAuthorizationBase;
+
+/**
+ * Provides Basic Auth based client authorization.
+ *
+ * @ClientAuthorization(
+ *   id = "basic_auth",
+ *   label = @Translation("Basic Auth"), * )
+ */
+class BasicAuth extends ClientAuthorizationBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function checkIfAvailable() {
+    // Basic Auth is a core module which any server can enable.
+    return TRUE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getClient($url) {
+    $credentials = $this->keyService->getCredentials($this);
+    $http_client = $this->httpClientFactory->fromOptions([
+      'base_uri' => $url . '/',
+      'cookies' => TRUE,
+      'allow_redirects' => TRUE,
+    ]);
+
+    $http_client->post('/user/login', [
+      'form_params' => [
+        'name' => $credentials['username'],
+        'pass' => $credentials['password'],
+        'form_id' => 'user_login_form',
+      ],
+    ]);
+
+    return $http_client;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getJsonApiClient($url) {
+    $credentials = $this->keyService->getCredentials($this);
+    return $this->httpClientFactory->fromOptions([
+      'base_uri' => $url . '/',
+      'auth' => [
+        $credentials['username'],
+        $credentials['password'],
+      ],
+      'headers' => [
+        'Content-type' => 'application/vnd.api+json',
+      ],
+    ]);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildConfigurationForm(
+    array $form,
+    FormStateInterface $form_state
+  ) {
+    $form = parent::buildConfigurationForm($form, $form_state);
+
+    $credentials = $this->keyService->getCredentials($this);
+    $form['entity_share']['username'] = [
+      '#type' => 'textfield',
+      '#required' => FALSE,
+      '#title' => $this->t('Username'),
+      '#default_value' => isset($credentials['username']) ? $credentials['username'] : '',
+    ];
+
+    $form['entity_share']['password'] = [
+      '#type' => 'textfield',
+      '#required' => FALSE,
+      '#title' => $this->t('Password'),
+      '#default_value' => isset($credentials['password']) ? $credentials['password'] : '',
+    ];
+    if ($this->keyService->additionalProviders()) {
+      $this->expandedProviderOptions($form);
+      $form['key']['id']['#key_filters'] = ['type' => 'entity_share_basic_auth'];
+      $form['key']['id']['#description'] = $this->t('Select the key you have configured to hold the Basic Auth credentials.');
+    }
+    return $form;
+  }
+
+}
diff --git a/modules/entity_share_client/src/Plugin/ClientAuthorizationBase.php b/modules/entity_share_client/src/Plugin/ClientAuthorizationBase.php
new file mode 100644
index 0000000..ca62331
--- /dev/null
+++ b/modules/entity_share_client/src/Plugin/ClientAuthorizationBase.php
@@ -0,0 +1,275 @@
+<?php
+
+namespace Drupal\entity_share_client\Plugin;
+
+use Drupal\Component\Uuid\UuidInterface;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\Plugin\PluginBase;
+use Drupal\Component\Utility\NestedArray;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\State\StateInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Drupal\entity_share_client\Service\KeyProvider;
+use Drupal\Core\Http\ClientFactory;
+
+/**
+ * Base class for Client authorization plugins.
+ */
+abstract class ClientAuthorizationBase extends PluginBase implements ClientAuthorizationInterface, ContainerFactoryPluginInterface {
+
+  /**
+   * Injected key service.
+   *
+   * @var \Drupal\entity_share_client\Service\KeyProvider
+   */
+  protected $keyService;
+
+  /**
+   * Injected state service.
+   *
+   * @var \Drupal\Core\State\StateInterface
+   */
+  protected $state;
+
+  /**
+   * Injected UUID service.
+   *
+   * @var \Drupal\Component\Uuid\UuidInterface
+   */
+  protected $uuid;
+
+  /**
+   * Injected HTTP client factory.
+   *
+   * @var \Drupal\Core\Http\ClientFactory
+   */
+  protected $httpClientFactory;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function __construct(
+    array $configuration,
+    $plugin_id,
+    $plugin_definition,
+    KeyProvider $keyProvider,
+    StateInterface $state,
+    UuidInterface $uuid,
+    ClientFactory $clientFactory
+  ) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+    $this->keyService = $keyProvider;
+    $this->state = $state;
+    $this->uuid = $uuid;
+    $this->httpClientFactory = $clientFactory;
+    $this->setConfiguration($configuration);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(
+    ContainerInterface $container,
+    array $configuration,
+    $plugin_id,
+    $plugin_definition
+  ) {
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $container->get('entity_share_client.key_provider'),
+      $container->get('state'),
+      $container->get('uuid'),
+      $container->get('http_client_factory')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function defaultConfiguration() {
+    return [
+      'uuid' => $this->uuid->generate(),
+      'verified' => FALSE,
+      'data' => [],
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getConfiguration() {
+    return $this->configuration;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setConfiguration(array $configuration) {
+    $this->configuration = NestedArray::mergeDeep(
+      $this->defaultConfiguration(),
+      $configuration
+    );
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCredentialProvider() {
+    $configuration = $this->getConfiguration();
+    return $configuration['data']['credential_provider'] ?? NULL;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getStorageKey() {
+    $configuration = $this->getConfiguration();
+    return $configuration['data']['storage_key'] ?? NULL;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildConfigurationForm(
+    array $form,
+    FormStateInterface $form_state
+  ) {
+    return $form + [
+      'credential_provider' => [
+        '#type' => 'hidden',
+        '#value' => 'entity_share',
+      ],
+      'entity_share' => [
+        '#type' => 'fieldset',
+        '#title' => $this->t('Stored in local State'),
+      ],
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getLabel() {
+    return $this->pluginDefinition['label'];
+  }
+
+  /**
+   * Helper method to build the credential provider elements of the form.
+   *
+   * @param array $form
+   *   The configuration form.
+   */
+  protected function expandedProviderOptions(array &$form) {
+    $provider = $this->getCredentialProvider();
+    // Provide selectors for the api key credential provider.
+    $form['credential_provider'] = [
+      '#type' => 'select',
+      '#title' => $this->t('Credential provider'),
+      '#default_value' => empty($provider) ? 'entity_share' : $provider,
+      '#options' => [
+        'entity_share' => 'Local Storage',
+        'key' => 'Key Module',
+      ],
+      '#attributes' => [
+        'data-states-selector' => 'provider',
+      ],
+      '#weight' => -99,
+    ];
+    $form['entity_share']['#states'] = [
+      'required' => [
+        ':input[data-states-selector="provider"]' => ['value' => 'entity_share'],
+      ],
+      'visible' => [
+        ':input[data-states-selector="provider"]' => ['value' => 'entity_share'],
+      ],
+      'enabled' => [
+        ':input[data-states-selector="provider"]' => ['value' => 'entity_share'],
+      ],
+    ];
+    $key_id = $provider == 'key' ? $this->getStorageKey() : '';
+    $form['key'] = [
+      '#type' => 'fieldset',
+      '#title' => $this->t('Managed by Key module'),
+      '#states' => [
+        'required' => [
+          ':input[data-states-selector="provider"]' => ['value' => 'key'],
+        ],
+        'visible' => [
+          ':input[data-states-selector="provider"]' => ['value' => 'key'],
+        ],
+        'enabled' => [
+          ':input[data-states-selector="provider"]' => ['value' => 'key'],
+        ],
+      ],
+    ];
+    $form['key']['id'] = [
+      '#type' => 'key_select',
+      '#title' => $this->t('Select a Stored Key'),
+      '#default_value' => $key_id,
+      '#empty_option' => $this->t('- Please select -'),
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validateConfigurationForm(
+    array &$form,
+    FormStateInterface $form_state
+  ) {
+    $values = $form_state->getValues();
+    if (empty($values['credential_provider'])) {
+      $form_state->setError(
+        $form['credential_provider'],
+        'A credential provider is required.'
+      );
+    }
+    else {
+      $provider = $values['credential_provider'];
+      foreach ($values[$provider] as $key => $value) {
+        if (empty($value)) {
+          $form_state->setError(
+            $form[$provider][$key],
+            'All credential values are required.'
+          );
+        }
+      }
+    }
+
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitConfigurationForm(
+    array &$form,
+    FormStateInterface $form_state
+  ) {
+    $key = NULL;
+    $values = $form_state->getValues();
+    $configuration = $this->getConfiguration();
+    $provider = $values['credential_provider'];
+    $credentials = $values[$provider];
+    switch ($provider) {
+      case 'entity_share':
+        $this->state->set($configuration['uuid'], $credentials);
+        $key = $configuration['uuid'];
+        break;
+
+      case 'key':
+        $this->state->delete($configuration['uuid']);
+        $key = $credentials['id'];
+        break;
+
+    }
+    $configuration['data'] = [
+      'credential_provider' => $provider,
+      'storage_key' => $key,
+    ];
+    $this->setConfiguration($configuration);
+  }
+
+}
diff --git a/modules/entity_share_client/src/Plugin/ClientAuthorizationInterface.php b/modules/entity_share_client/src/Plugin/ClientAuthorizationInterface.php
new file mode 100644
index 0000000..4c7ed5e
--- /dev/null
+++ b/modules/entity_share_client/src/Plugin/ClientAuthorizationInterface.php
@@ -0,0 +1,70 @@
+<?php
+
+namespace Drupal\entity_share_client\Plugin;
+
+use Drupal\Component\Plugin\ConfigurableInterface;
+use Drupal\Component\Plugin\PluginInspectionInterface;
+use Drupal\Core\Plugin\PluginFormInterface;
+
+/**
+ * Defines an interface for Client authorization plugins.
+ */
+interface ClientAuthorizationInterface extends PluginInspectionInterface, PluginFormInterface, ConfigurableInterface {
+
+  /**
+   * Gets the plugin label.
+   *
+   * @return string
+   *   The plugin label.
+   */
+  public function getLabel();
+
+  /**
+   * Returns true if the plugin method is supported.
+   *
+   * The method could be in core, or it could require a contrib module.
+   *
+   * @return bool
+   *   Is this plugin available?
+   */
+  public function checkIfAvailable();
+
+  /**
+   * Prepares a guzzle client for JSON operations with the supported auth.
+   *
+   * @param string $url
+   *   The remote url.
+   *
+   * @return \GuzzleHttp\Client
+   *   The HTTP client.
+   */
+  public function getJsonApiClient($url);
+
+  /**
+   * Prepares a guzzle client for http operations with the supported auth.
+   *
+   * @param string $url
+   *   The url to set in the client.
+   *
+   * @return \GuzzleHttp\Client
+   *   The HTTP client.
+   */
+  public function getClient($url);
+
+  /**
+   * Returns the plugin data if it is set, otherwise returns NULL.
+   *
+   * @return string|null
+   *   The data.
+   */
+  public function getCredentialProvider();
+
+  /**
+   * Returns the plugin data if it is set, otherwise returns NULL.
+   *
+   * @return mixed|null
+   *   The data.
+   */
+  public function getStorageKey();
+
+}
diff --git a/modules/entity_share_client/src/Plugin/ClientAuthorizationManager.php b/modules/entity_share_client/src/Plugin/ClientAuthorizationManager.php
new file mode 100644
index 0000000..257217a
--- /dev/null
+++ b/modules/entity_share_client/src/Plugin/ClientAuthorizationManager.php
@@ -0,0 +1,32 @@
+<?php
+
+namespace Drupal\entity_share_client\Plugin;
+
+use Drupal\Core\Plugin\DefaultPluginManager;
+use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+
+/**
+ * Provides the Client authorization plugin manager.
+ */
+class ClientAuthorizationManager extends DefaultPluginManager {
+
+  /**
+   * Constructs a new ClientAuthorizationManager object.
+   *
+   * @param \Traversable $namespaces
+   *   An object that implements \Traversable which contains the root paths
+   *   keyed by the corresponding namespace to look for plugin implementations.
+   * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
+   *   Cache backend instance to use.
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+   *   The module handler to invoke the alter hook with.
+   */
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
+    parent::__construct('Plugin/ClientAuthorization', $namespaces, $module_handler, 'Drupal\entity_share_client\Plugin\ClientAuthorizationInterface', 'Drupal\entity_share_client\Annotation\ClientAuthorization');
+
+    $this->alterInfo('entity_share_client_entity_share_auth_info');
+    $this->setCacheBackend($cache_backend, 'entity_share_client_entity_share_auth_plugins');
+  }
+
+}
diff --git a/modules/entity_share_client/src/Plugin/KeyType/EntityShareBasicAuth.php b/modules/entity_share_client/src/Plugin/KeyType/EntityShareBasicAuth.php
new file mode 100644
index 0000000..02017e4
--- /dev/null
+++ b/modules/entity_share_client/src/Plugin/KeyType/EntityShareBasicAuth.php
@@ -0,0 +1,29 @@
+<?php
+
+namespace Drupal\entity_share_client\Plugin\KeyType;
+
+use Drupal\key\Plugin\KeyType\AuthenticationMultivalueKeyType;
+
+/**
+ * Key module plugin to define a basic_auth credentials KeyType.
+ *
+ * @KeyType(
+ *   id = "entity_share_basic_auth",
+ *   label = @Translation("Entity Share Basic Auth"),
+ *   description = @Translation("A key type to store Basic Auth credentials for the Entity Share module. Store as JSON:<br><pre>{<br>&quot;username&quot;: &quot;username value&quot;,<br>&quot;password&quot;: &quot;password value&quot;<br>}</pre>"),
+ *   group = "authentication",
+ *   key_value = {
+ *     "plugin" = "textarea_field"
+ *   },
+ *   multivalue = {
+ *     "enabled" = true,
+ *     "fields" = {
+ *       "username" = @Translation("Username"),
+ *       "password" = @Translation("Password")
+ *     }
+ *   }
+ * )
+ */
+class EntityShareBasicAuth extends AuthenticationMultivalueKeyType {
+
+}
diff --git a/modules/entity_share_client/src/Service/KeyProvider.php b/modules/entity_share_client/src/Service/KeyProvider.php
new file mode 100644
index 0000000..b0bf7c5
--- /dev/null
+++ b/modules/entity_share_client/src/Service/KeyProvider.php
@@ -0,0 +1,94 @@
+<?php
+
+namespace Drupal\entity_share_client\Service;
+
+use Drupal\key\Entity\Key;
+use Drupal\Core\State\StateInterface;
+use Drupal\entity_share_client\Plugin\ClientAuthorizationInterface;
+use Drupal\key\KeyRepositoryInterface;
+
+/**
+ * Class KeyProvider.
+ *
+ * @package Drupal\entity_share_client\Service
+ */
+class KeyProvider {
+
+  /**
+   * Key module service conditionally injected.
+   *
+   * @var \Drupal\key\KeyRepositoryInterface
+   */
+  protected $keyRepository;
+
+  /**
+   * Injected service.
+   *
+   * @var \Drupal\Core\State\StateInterface
+   */
+  protected $state;
+
+  /**
+   * KeyService constructor.
+   *
+   * @param \Drupal\Core\State\StateInterface $state
+   *   Injected service.
+   */
+  public function __construct(StateInterface $state) {
+    $this->state = $state;
+  }
+
+  /**
+   * Provides a means to our services.yml file to conditionally inject service.
+   *
+   * @param \Drupal\key\KeyRepositoryInterface $repository
+   *   The injected service, if it exists.
+   *
+   * @see maw_luminate.services.yml
+   */
+  public function setKeyRepository(KeyRepositoryInterface $repository) {
+    $this->keyRepository = $repository;
+  }
+
+  /**
+   * Detects if key module service was injected.
+   *
+   * @return bool
+   *   True if the KeyRepository is present.
+   */
+  public function additionalProviders() {
+    return $this->keyRepository instanceof KeyRepositoryInterface;
+  }
+
+  /**
+   * Get the provided credentials.
+   *
+   * @param \Drupal\entity_share_client\Plugin\ClientAuthorizationInterface $plugin
+   *   An authorization plugin.
+   *
+   * @return array|string
+   *   The value of the configured key.
+   */
+  public function getCredentials(ClientAuthorizationInterface $plugin) {
+    $provider = $plugin->getCredentialProvider();
+    $credentials = [];
+    if (empty($provider)) {
+      return $credentials;
+    }
+    switch ($provider) {
+      case 'key':
+        $keyEntity = $this->keyRepository->getKey($plugin->getStorageKey());
+        if ($keyEntity instanceof Key) {
+          // A key was found in the repository.
+          $credentials = $keyEntity->getKeyValues();
+        }
+        break;
+
+      default:
+        $credentials = $this->state->get($plugin->getStorageKey());
+    }
+
+    return $credentials;
+  }
+
+}
diff --git a/modules/entity_share_client/src/Service/RemoteManager.php b/modules/entity_share_client/src/Service/RemoteManager.php
index 8c21bda..f91868c 100644
--- a/modules/entity_share_client/src/Service/RemoteManager.php
+++ b/modules/entity_share_client/src/Service/RemoteManager.php
@@ -5,7 +5,6 @@ declare(strict_types = 1);
 namespace Drupal\entity_share_client\Service;

 use Drupal\Component\Serialization\Json;
-use Drupal\Core\Http\ClientFactory;
 use Drupal\entity_share_client\Entity\RemoteInterface;
 use GuzzleHttp\ClientInterface;
 use GuzzleHttp\Exception\ClientException;
@@ -21,11 +20,18 @@ use Psr\Log\LoggerInterface;
 class RemoteManager implements RemoteManagerInterface {

   /**
-   * The HTTP client factory.
+   * A constant to document the call for a standard client.
    *
-   * @var \Drupal\Core\Http\ClientFactory
+   * @var bool
    */
-  protected $httpClientFactory;
+  const STANDARD_CLIENT = FALSE;
+
+  /**
+   * A constant to document the call for a JSON:API client.
+   *
+   * @var bool
+   */
+  const JSON_API_CLIENT = TRUE;

   /**
    * Logger.
@@ -58,16 +64,10 @@ class RemoteManager implements RemoteManagerInterface {
   /**
    * RemoteManager constructor.
    *
-   * @param \Drupal\Core\Http\ClientFactory $http_client_factory
-   *   The HTTP client factory.
    * @param \Psr\Log\LoggerInterface $logger
    *   The logger service.
    */
-  public function __construct(
-    ClientFactory $http_client_factory,
-    LoggerInterface $logger
-  ) {
-    $this->httpClientFactory = $http_client_factory;
+  public function __construct(LoggerInterface $logger) {
     $this->logger = $logger;
   }

@@ -129,21 +129,7 @@ class RemoteManager implements RemoteManagerInterface {
   protected function getHttpClient(RemoteInterface $remote) {
     $remote_id = $remote->id();
     if (!isset($this->httpClients[$remote_id])) {
-      $http_client = $this->httpClientFactory->fromOptions([
-        'base_uri' => $remote->get('url') . '/',
-        'cookies' => TRUE,
-        'allow_redirects' => TRUE,
-      ]);
-
-      $http_client->post('user/login', [
-        'form_params' => [
-          'name' => $remote->get('basic_auth_username'),
-          'pass' => $remote->get('basic_auth_password'),
-          'form_id' => 'user_login_form',
-        ],
-      ]);
-
-      $this->httpClients[$remote_id] = $http_client;
+      $this->httpClients[$remote_id] = $remote->getHttpClient(self::STANDARD_CLIENT);
     }

     return $this->httpClients[$remote_id];
@@ -155,16 +141,7 @@ class RemoteManager implements RemoteManagerInterface {
   protected function getJsonApiHttpClient(RemoteInterface $remote) {
     $remote_id = $remote->id();
     if (!isset($this->jsonApiHttpClients[$remote_id])) {
-      $this->jsonApiHttpClients[$remote_id] = $this->httpClientFactory->fromOptions([
-        'base_uri' => $remote->get('url') . '/',
-        'auth' => [
-          $remote->get('basic_auth_username'),
-          $remote->get('basic_auth_password'),
-        ],
-        'headers' => [
-          'Content-type' => 'application/vnd.api+json',
-        ],
-      ]);
+      $this->jsonApiHttpClients[$remote_id] = $remote->getHttpClient(self::JSON_API_CLIENT);
     }

     return $this->jsonApiHttpClients[$remote_id];
