diff --git a/composer.json b/composer.json
index 0080381774855b085e46df496eebe50beb778cf1..ac022d80da954158d29ca69c2e46b12ea0e1186e 100644
--- a/composer.json
+++ b/composer.json
@@ -11,6 +11,7 @@
     "source": "https://git.drupalcode.org/project/login_gov"
   },
   "require": {
+    "drupal/key_asymmetric": "^1.1",
     "drupal/openid_connect": "^2.0",
     "firebase/php-jwt": "^6.3"
   }
diff --git a/config/schema/login_gov.schema.yml b/config/schema/login_gov.schema.yml
index cc6e2cdf5859b9bcf091badde07f578679066208..cdf883a56f7e54e31a3775ea018be87533643cf5 100644
--- a/config/schema/login_gov.schema.yml
+++ b/config/schema/login_gov.schema.yml
@@ -30,7 +30,7 @@ openid_connect.client.plugin.login_gov:
     force_reauth:
       type: boolean
       label: 'Force reauthorization'
-    private_key:
-      type: text
-      label: 'Private key in PEM format'
+    key_private_key:
+      type: string
+      label: 'Key ID from Key Module'
 
diff --git a/login_gov.info.yml b/login_gov.info.yml
index 6e236b7db236600a180acacf58839a866353f3e8..c8bc6f8a5409523f55378a363d11c72c6509a300 100644
--- a/login_gov.info.yml
+++ b/login_gov.info.yml
@@ -5,3 +5,4 @@ core_version_requirement: ^8.8 || ^9
 package: 'User authentication'
 dependencies:
   - openid_connect:openid_connect (>=2.0)
+  - key_asymmetric:key_asymmetric
diff --git a/login_gov.install b/login_gov.install
new file mode 100644
index 0000000000000000000000000000000000000000..78b55a9ecc662b6488151db5e9b5d8f6206f7fd1
--- /dev/null
+++ b/login_gov.install
@@ -0,0 +1,45 @@
+<?php
+
+/**
+ * @file
+ * Contains update functions for the login_gov module.
+ */
+
+use Drupal\key\Entity\Key;
+
+/**
+ * Implements hook_update_N().
+ *
+ * Convert old private keys to Key entities.
+ */
+function login_gov_update_9001(&$sandbox) {
+  $clients = \Drupal::entityTypeManager()->getStorage('openid_connect_client')->loadByProperties(['plugin' => 'login_gov']);
+  foreach ($clients as $id => $client) {
+    $settings = $client->get('settings');
+    // Skip entries without a private key.
+    if (empty($settings['private_key'])) {
+      continue;
+    }
+    // Choose a new unique key id.
+    $key_id = $id . '_private_key';
+    $index = 1;
+    while (Key::load($key_id)) {
+      $key_id = $id . '_private_key_' . $index++;
+    }
+    // Generate a new Private key object.
+    Key::create([
+      'id' => $key_id,
+      'label' => $client->label() . ' private key',
+      'description' => 'Automatically converted from Login.gov config.',
+      'key_type' => 'asymmetric_private',
+      'key_type_settings' => key_asymmetric_get_key_properties($settings['private_key']),
+      'key_provider_settings' => ['key_value' => $settings['private_key']],
+    ])->save();
+    // Update the client to use the new key.
+    $client->set('settings', [
+      'key_private_key' => $key_id,
+      'private_key' => NULL,
+    ]);
+    $client->save();
+  }
+}
diff --git a/src/Plugin/OpenIDConnectClient/OpenIDConnectLoginGovClient.php b/src/Plugin/OpenIDConnectClient/OpenIDConnectLoginGovClient.php
index 9733f0e7dcdc2f8e56489d22c78c6babbce2cc7d..0d2b0d0b20e9465954a41b55d7936ddc8edf7225 100644
--- a/src/Plugin/OpenIDConnectClient/OpenIDConnectLoginGovClient.php
+++ b/src/Plugin/OpenIDConnectClient/OpenIDConnectLoginGovClient.php
@@ -8,6 +8,7 @@ use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\GeneratedUrl;
 use Drupal\Core\Link;
 use Drupal\Core\Url;
+use Drupal\key\Entity\Key;
 use Drupal\openid_connect\Plugin\OpenIDConnectClientBase;
 use Firebase\JWT\JWK;
 use Firebase\JWT\JWT;
@@ -94,7 +95,7 @@ class OpenIDConnectLoginGovClient extends OpenIDConnectClientBase {
         'count' => 1,
         'units' => 'y',
       ],
-      'private_key' => '',
+      'key_private_key' => NULL,
     ];
   }
 
@@ -178,11 +179,12 @@ class OpenIDConnectLoginGovClient extends OpenIDConnectClientBase {
       '#description' => $this->t('Require the user to login again to Login.gov. <em>Requires login.gov administrator approval.</em>'),
     ];
 
-    $form['private_key'] = [
-      '#title' => $this->t('Private key in PEM format'),
-      '#type' => 'textarea',
-      '#default_value' => $this->configuration['private_key'],
-      '#description' => $this->t('Need to put this someplace more secure.'),
+    $form['key_private_key'] = [
+      '#title' => $this->t('Key from Key'),
+      '#type' => 'key_select',
+      '#default_value' => $this->configuration['key_private_key'],
+      '#key_filters' => ['type' => ['asymmetric_private']],
+      '#description' => ' ' . $this->t('A Private key managed by the @key_module.', ['@key_module' => Link::fromTextAndUrl($this->t('Key module'), Url::fromRoute('entity.key.collection'))->toString()]),
     ];
 
     // Add some custom CSS.
@@ -261,7 +263,10 @@ class OpenIDConnectLoginGovClient extends OpenIDConnectClientBase {
    *   The private key in PEM format.
    */
   protected function getPrivateKey(): ?string {
-    return $this->configuration['private_key'];
+    $key = Key::load($this->configuration['key_private_key']);
+    // Return the key's KeyValue, or fall back to the old configuration if there
+    // is no Key.
+    return $key ? $key->getKeyValue() : $this->configuration['private_key'];
   }
 
   /**