diff --git a/libpurple/plugins/keyrings/secretservice.c b/libpurple/plugins/keyrings/secretservice.c
--- a/libpurple/plugins/keyrings/secretservice.c
+++ b/libpurple/plugins/keyrings/secretservice.c
@@ -38,8 +38,10 @@
    project name. It may not be appropriate to translate this string, but
    transliterating to your alphabet is reasonable. More info about the
    project can be found at https://wiki.gnome.org/Projects/Libsecret */
+#define SECRETSERVICE_ID "secret-service"
 #define SECRETSERVICE_NAME N_("Secret Service")
-#define SECRETSERVICE_ID "secret-service"
+#define SECRETSERVICE_DESCRIPTION N_("D-Bus Secret Service. Common in GNOME " \
+                                     "and other desktop environments.")
 
 /******************************************************************************
  * Globals
@@ -264,6 +266,7 @@
 		PURPLE_TYPE_SECRET_SERVICE,
 		"id", SECRETSERVICE_ID,
 		"name", _(SECRETSERVICE_NAME),
+		"description", _(SECRETSERVICE_DESCRIPTION),
 		NULL
 	));
 }
diff --git a/libpurple/plugins/keyrings/wincred.c b/libpurple/plugins/keyrings/wincred.c
--- a/libpurple/plugins/keyrings/wincred.c
+++ b/libpurple/plugins/keyrings/wincred.c
@@ -25,8 +25,9 @@
 
 #include <wincred.h>
 
+#define WINCRED_ID          "keyring-wincred"
 #define WINCRED_NAME        N_("Windows credentials")
-#define WINCRED_ID          "keyring-wincred"
+#define WINCRED_DESCRIPTION N_("The built-in credential manager for Windows.")
 
 #define WINCRED_MAX_TARGET_NAME 256
 
@@ -364,6 +365,7 @@
 		PURPLE_TYPE_WINCRED,
 		"id", WINCRED_ID,
 		"name", _(WINCRED_NAME),
+		"description", _(WINCRED_DESCRIPTION),
 		NULL
 	));
 }
diff --git a/libpurple/purplecredentialprovider.h b/libpurple/purplecredentialprovider.h
--- a/libpurple/purplecredentialprovider.h
+++ b/libpurple/purplecredentialprovider.h
@@ -125,6 +125,19 @@
 const gchar *purple_credential_provider_get_name(PurpleCredentialProvider *provider);
 
 /**
+ * purple_credential_provider_get_description:
+ * @provider: The #PurpleCredentialProvider instance.
+ *
+ * Gets the description of @provider which can be displayed in user interfaces
+ * to help users figure out which provider to use.
+ *
+ * Returns: The description of @provider.
+ *
+ * Since: 3.0.0
+ */
+const gchar *purple_credential_provider_get_description(PurpleCredentialProvider *provider);
+
+/**
  * purple_credential_provider_is_valid:
  * @provider: The #PurpleCredentialProvider instance.
  * @error: (out) (optional) (nullable): Return address for a #GError.
diff --git a/libpurple/purplecredentialprovider.c b/libpurple/purplecredentialprovider.c
--- a/libpurple/purplecredentialprovider.c
+++ b/libpurple/purplecredentialprovider.c
@@ -21,12 +21,14 @@
 typedef struct {
 	gchar *id;
 	gchar *name;
+	gchar *description;
 } PurpleCredentialProviderPrivate;
 
 enum {
 	PROP_0,
 	PROP_ID,
 	PROP_NAME,
+	PROP_DESCRIPTION,
 	N_PROPERTIES,
 };
 static GParamSpec *properties[N_PROPERTIES] = {NULL, };
@@ -65,6 +67,20 @@
 	g_object_notify_by_pspec(G_OBJECT(provider), properties[PROP_NAME]);
 }
 
+static void
+purple_credential_provider_set_description(PurpleCredentialProvider *provider,
+                                           const gchar *description)
+{
+	PurpleCredentialProviderPrivate *priv = NULL;
+
+	priv = purple_credential_provider_get_instance_private(provider);
+
+	g_free(priv->description);
+	priv->description = g_strdup(description);
+
+	g_object_notify_by_pspec(G_OBJECT(provider), properties[PROP_DESCRIPTION]);
+}
+
 /******************************************************************************
  * GObject Implementation
  *****************************************************************************/
@@ -83,6 +99,10 @@
 			g_value_set_string(value,
 			                   purple_credential_provider_get_name(provider));
 			break;
+		case PROP_DESCRIPTION:
+			g_value_set_string(value,
+			                   purple_credential_provider_get_description(provider));
+			break;
 		default:
 			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
 			break;
@@ -104,6 +124,10 @@
 			purple_credential_provider_set_name(provider,
 			                                    g_value_get_string(value));
 			break;
+		case PROP_DESCRIPTION:
+			purple_credential_provider_set_description(provider,
+			                                           g_value_get_string(value));
+			break;
 		default:
 			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
 			break;
@@ -141,6 +165,8 @@
 	 *
 	 * The ID of the provider.  Used for preferences and other things that need
 	 * to address it.
+	 *
+	 * Since: 3.0.0
 	 */
 	properties[PROP_ID] = g_param_spec_string(
 		"id", "id", "The identifier of the provider",
@@ -152,6 +178,8 @@
 	 * PurpleCredentialProvider::name:
 	 *
 	 * The name of the provider which will be displayed to the user.
+	 *
+	 * Since: 3.0.0
 	 */
 	properties[PROP_NAME] = g_param_spec_string(
 		"name", "name", "The name of the provider",
@@ -159,6 +187,19 @@
 		G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS
 	);
 
+	/**
+	 * PurpleCredentialProvider::description:
+	 *
+	 * The description of the provider which will be displayed to the user.
+	 *
+	 * Since: 3.0.0
+	 */
+	properties[PROP_DESCRIPTION] = g_param_spec_string(
+		"description", "description", "The description of the provider",
+		NULL,
+		G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS
+	);
+
 	g_object_class_install_properties(obj_class, N_PROPERTIES, properties);
 }
 
@@ -187,6 +228,17 @@
 	return priv->name;
 }
 
+const gchar *
+purple_credential_provider_get_description(PurpleCredentialProvider *provider) {
+	PurpleCredentialProviderPrivate *priv = NULL;
+
+	g_return_val_if_fail(PURPLE_IS_CREDENTIAL_PROVIDER(provider), NULL);
+
+	priv = purple_credential_provider_get_instance_private(provider);
+
+	return priv->description;
+}
+
 gboolean
 purple_credential_provider_is_valid(PurpleCredentialProvider *provider,
                                     GError **error)
diff --git a/libpurple/purplenoopcredentialprovider.c b/libpurple/purplenoopcredentialprovider.c
--- a/libpurple/purplenoopcredentialprovider.c
+++ b/libpurple/purplenoopcredentialprovider.c
@@ -111,6 +111,7 @@
 		PURPLE_TYPE_NOOP_CREDENTIAL_PROVIDER,
 		"id", "noop-provider",
 		"name", _("None"),
+		"description", _("Passwords will not be saved."),
 		NULL
 	));
 }
diff --git a/pidgin/pidgincredentialproviderstore.h b/pidgin/pidgincredentialproviderstore.h
--- a/pidgin/pidgincredentialproviderstore.h
+++ b/pidgin/pidgincredentialproviderstore.h
@@ -39,9 +39,22 @@
 
 #include <purple.h>
 
+/**
+ * PidginCredentialProviderStoreColumn:
+ * @PIDGIN_CREDENTIAL_PROVIDER_STORE_COLUMN_ID: A constant for the id column.
+ * @PIDGIN_CREDENTIAL_PROVIDER_STORE_COLUMN_MARKUP: A constant for the markup
+ *                                                  that shoule be displayed.
+ * @PIDGIN_CREDENTIAL_PROVIDER_STORE_N_COLUMNS: The number of columns in the
+ *                                              store.
+ *
+ * A collection of constants for referring to the columns in a
+ * #PidginCredentialProviderStore.
+ *
+ * Since: 3.0.0
+ */
 typedef enum {
 	PIDGIN_CREDENTIAL_PROVIDER_STORE_COLUMN_ID,
-	PIDGIN_CREDENTIAL_PROVIDER_STORE_COLUMN_NAME,
+	PIDGIN_CREDENTIAL_PROVIDER_STORE_COLUMN_MARKUP,
 	PIDGIN_CREDENTIAL_PROVIDER_STORE_N_COLUMNS,
 } PidginCredentialProviderStoreColumn;
 
diff --git a/pidgin/pidgincredentialproviderstore.c b/pidgin/pidgincredentialproviderstore.c
--- a/pidgin/pidgincredentialproviderstore.c
+++ b/pidgin/pidgincredentialproviderstore.c
@@ -36,19 +36,25 @@
                                      PurpleCredentialProvider *provider)
 {
 	GtkTreeIter iter;
-	const gchar *id = NULL, *name = NULL;
+	gchar *markup = NULL;
+	const gchar *id = NULL, *name = NULL, *description = NULL;
 
 	id = purple_credential_provider_get_id(provider);
 	name = purple_credential_provider_get_name(provider);
+	description = purple_credential_provider_get_description(provider);
+
+	markup = g_strdup_printf("<b>%s</b>\n%s", name, description);
 
 	gtk_list_store_append(GTK_LIST_STORE(store), &iter);
 	gtk_list_store_set(
 		GTK_LIST_STORE(store),
 		&iter,
 		PIDGIN_CREDENTIAL_PROVIDER_STORE_COLUMN_ID, id,
-		PIDGIN_CREDENTIAL_PROVIDER_STORE_COLUMN_NAME, name,
+		PIDGIN_CREDENTIAL_PROVIDER_STORE_COLUMN_MARKUP, markup,
 		-1
 	);
+
+	g_free(markup);
 }
 
 static void
diff --git a/pidgin/pidgincredentialspage.c b/pidgin/pidgincredentialspage.c
--- a/pidgin/pidgincredentialspage.c
+++ b/pidgin/pidgincredentialspage.c
@@ -30,6 +30,7 @@
 	GtkBox parent;
 
 	GtkWidget *combo;
+	GtkCellRenderer *renderer;
 };
 
 G_DEFINE_TYPE(PidginCredentialsPage, pidgin_credentials_page,
@@ -140,6 +141,15 @@
 
 	gtk_widget_init_template(GTK_WIDGET(page));
 
+	/* Set some constant properties on the renderer. This stuff is kind of
+	 * dodgy, but it does stop the dialog from growing to fit a long
+	 * description.
+	 */
+	g_object_set(G_OBJECT(page->renderer),
+	             "width-chars", 10,
+	             "wrap-mode", PANGO_WRAP_WORD_CHAR,
+	             NULL);
+
 	purple_prefs_add_none("/purple/credentials");
 	purple_prefs_add_string("/purple/credentials/active-provider", NULL);
 
@@ -171,6 +181,8 @@
 
 	gtk_widget_class_bind_template_child(widget_class, PidginCredentialsPage,
 	                                     combo);
+	gtk_widget_class_bind_template_child(widget_class, PidginCredentialsPage,
+	                                     renderer);
 }
 
 /******************************************************************************
diff --git a/pidgin/resources/Prefs/credentials.ui b/pidgin/resources/Prefs/credentials.ui
--- a/pidgin/resources/Prefs/credentials.ui
+++ b/pidgin/resources/Prefs/credentials.ui
@@ -49,6 +49,7 @@
                 <property name="visible">True</property>
                 <property name="can-focus">False</property>
                 <property name="label" translatable="yes">Provider:</property>
+                <property name="xalign">0</property>
               </object>
               <packing>
                 <property name="expand">False</property>
@@ -62,9 +63,9 @@
                 <property name="can-focus">False</property>
                 <property name="model">store</property>
                 <child>
-                  <object class="GtkCellRendererText"/>
+                  <object class="GtkCellRendererText" id="renderer"/>
                   <attributes>
-                    <attribute name="text">1</attribute>
+                    <attribute name="markup">1</attribute>
                   </attributes>
                 </child>
               </object>
