diff --git a/doc/reference/pidgin/pidgin-docs.xml b/doc/reference/pidgin/pidgin-docs.xml
--- a/doc/reference/pidgin/pidgin-docs.xml
+++ b/doc/reference/pidgin/pidgin-docs.xml
@@ -65,6 +65,8 @@
       <xi:include href="xml/pidgincontactlist.xml" />
       <xi:include href="xml/pidginconversationwindow.xml" />
       <xi:include href="xml/pidgincore.xml" />
+      <xi:include href="xml/pidgincredentialproviderstore.xml" />
+      <xi:include href="xml/pidgincredentialspage.xml" />
       <xi:include href="xml/pidgindebug.xml" />
       <xi:include href="xml/pidgindialog.xml" />
       <xi:include href="xml/pidgingdkpixbuf.xml" />
diff --git a/libpurple/purplecredentialmanager.h b/libpurple/purplecredentialmanager.h
--- a/libpurple/purplecredentialmanager.h
+++ b/libpurple/purplecredentialmanager.h
@@ -57,6 +57,8 @@
  * PURPLE_TYPE_CREDENTIAL_MANAGER:
  *
  * The standard _get_type macro for #PurpleCredentialManager.
+ *
+ * Since: 3.0.0
  */
 #define PURPLE_TYPE_CREDENTIAL_MANAGER (purple_credential_manager_get_type())
 G_DECLARE_DERIVABLE_TYPE(PurpleCredentialManager, purple_credential_manager,
@@ -95,6 +97,18 @@
 };
 
 /**
+ * PurpleCredentialManagerForeachFunc:
+ * @provider: The #PurpleCredentialProvider instance.
+ * @data: User supplied data.
+ *
+ * A function to be used as a callback with
+ * purple_credential_manager_foreach_provider().
+ *
+ * Since: 3.0.0
+ */
+typedef void (*PurpleCredentialManagerForeachFunc)(PurpleCredentialProvider *provider, gpointer data);
+
+/**
  * purple_credential_manager_get_default:
  *
  * Gets the default #PurpleCredentialManager instance.
@@ -146,10 +160,25 @@
  * id of @id.
  *
  * Returns: %TRUE on success or %FALSE with @error set on failure.
+ *
+ * Since: 3.0.0
  */
 gboolean purple_credential_manager_set_active_provider(PurpleCredentialManager *manager, const gchar *id, GError **error);
 
 /**
+ * purple_credential_manager_get_active_provider:
+ * @manager: The #PurpleCredentialManager instance.
+ *
+ * Gets the currently active #PurpleCredentialProvider or %NULL if there is no
+ * active provider.
+ *
+ * Returns: (transfer none): The active #PurpleCredentialProvider.
+ *
+ * Since: 3.0.0
+ */
+PurpleCredentialProvider *purple_credential_manager_get_active_provider(PurpleCredentialManager *manager);
+
+/**
  * purple_credential_manager_read_password_async:
  * @manager: The #PurpleCredentialManager instance.
  * @account: The #PurpleAccount whose password to read.
@@ -276,6 +305,19 @@
  */
 gboolean purple_credential_manager_write_settings(PurpleCredentialManager *manager, PurpleRequestFields *fields, GError **error);
 
+
+/**
+ * purple_credential_manager_foreach_provider:
+ * @manager: The #PurpleCredentialManager instance.
+ * @func: (scope call): The #PurpleCredentialManagerForeachFunc to call.
+ * @data: User data to pass to @func.
+ *
+ * Calls @func for each #PurpleCredentialProvider that @manager knows about.
+ *
+ * Since: 3.0.0
+ */
+void purple_credential_manager_foreach_provider(PurpleCredentialManager *manager, PurpleCredentialManagerForeachFunc func, gpointer data);
+
 G_END_DECLS
 
 #endif /* PURPLE_CREDENTIAL_MANAGER_H */
diff --git a/libpurple/purplecredentialmanager.c b/libpurple/purplecredentialmanager.c
--- a/libpurple/purplecredentialmanager.c
+++ b/libpurple/purplecredentialmanager.c
@@ -340,6 +340,18 @@
 	return TRUE;
 }
 
+PurpleCredentialProvider *
+purple_credential_manager_get_active_provider(PurpleCredentialManager *manager)
+{
+	PurpleCredentialManagerPrivate *priv = NULL;
+
+	g_return_val_if_fail(PURPLE_IS_CREDENTIAL_MANAGER(manager), NULL);
+
+	priv = purple_credential_manager_get_instance_private(manager);
+
+	return priv->active_provider;
+}
+
 void
 purple_credential_manager_read_password_async(PurpleCredentialManager *manager,
                                               PurpleAccount *account,
@@ -533,3 +545,23 @@
 	return purple_credential_provider_write_settings(priv->active_provider,
 	                                                 fields);
 }
+
+void
+purple_credential_manager_foreach_provider(PurpleCredentialManager *manager,
+                                           PurpleCredentialManagerForeachFunc func,
+                                           gpointer data)
+{
+	GHashTableIter iter;
+	PurpleCredentialManagerPrivate *priv = NULL;
+	gpointer value;
+
+	g_return_if_fail(PURPLE_IS_CREDENTIAL_MANAGER(manager));
+	g_return_if_fail(func != NULL);
+
+	priv = purple_credential_manager_get_instance_private(manager);
+
+	g_hash_table_iter_init(&iter, priv->providers);
+	while(g_hash_table_iter_next(&iter, NULL, &value)) {
+		func(PURPLE_CREDENTIAL_PROVIDER(value), data);
+	}
+}
\ No newline at end of file
diff --git a/pidgin/glade/pidgin3.xml.in b/pidgin/glade/pidgin3.xml.in
--- a/pidgin/glade/pidgin3.xml.in
+++ b/pidgin/glade/pidgin3.xml.in
@@ -8,6 +8,8 @@
     <glade-widget-class name="PidginAccountFilterProtocol" generic-name="account_filter_protocol" title="FilterProtocol"/>
     <glade-widget-class name="PidginCloseButton" generic-name="close-button" title="CloseButton"/>
     <glade-widget-class name="PidginConversationWindow" generic-name="conversation_window" title="ConversationWindow"/>
+    <glade-widget-class name="PidginCredentialProviderStore" generic-name="credential_provider_store" title="CredentialProviderStore"/>
+    <glade-widget-class name="PidginCredentialsPage" generic-name="credentials_page" title="Credentials Page"/>
     <glade-widget-class name="PidginDialog" generic-name="dialog" title="Dialog"/>
     <glade-widget-class name="PidginInviteDialog" generic-name="invite_dialog" title="InviteDialog"/>
     <glade-widget-class name="PidginMenuTray" generic-name="menu_tray" title="MenuTray"/>
@@ -25,6 +27,8 @@
     <glade-widget-class-ref name="PidginAccountFilterProtocol"/>
     <glade-widget-class-ref name="PidginCloseButton"/>
     <glade-widget-class-ref name="PidginConversationWindow"/>
+    <glade-widget-class-ref name="PidginCredentialProviderStore"/>
+    <glade-widget-class-ref name="PidginCredentialsPage"/>
     <glade-widget-class-ref name="PidginDialog"/>
     <glade-widget-class-ref name="PidginInviteDialog"/>
     <glade-widget-class-ref name="PidginMenuTray"/>
diff --git a/pidgin/meson.build b/pidgin/meson.build
--- a/pidgin/meson.build
+++ b/pidgin/meson.build
@@ -44,6 +44,8 @@
 	'pidgincontactcompletion.c',
 	'pidginconversationwindow.c',
 	'pidgincontactlist.c',
+	'pidgincredentialproviderstore.c',
+	'pidgincredentialspage.c',
 	'pidgindebug.c',
 	'pidgindialog.c',
 	'pidgingdkpixbuf.c',
@@ -112,6 +114,8 @@
 	'pidginconversationwindow.h',
 	'pidgincontactlist.h',
 	'pidgincore.h',
+	'pidgincredentialproviderstore.h',
+	'pidgincredentialspage.h',
 	'pidgindialog.h',
 	'pidgindebug.h',
 	'pidgingdkpixbuf.h',
diff --git a/pidgin/pidgincredentialproviderstore.h b/pidgin/pidgincredentialproviderstore.h
new file mode 100644
--- /dev/null
+++ b/pidgin/pidgincredentialproviderstore.h
@@ -0,0 +1,68 @@
+/*
+ * Pidgin - Internet Messenger
+ * Copyright (C) Pidgin Developers <devel@pidgin.im>
+ *
+ * Pidgin is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef PIDGIN_CREDENTIAL_PROVIDER_STORE_H
+#define PIDGIN_CREDENTIAL_PROVIDER_STORE_H
+
+/**
+ * SECTION:pidgincredentialproviderstore
+ * @section_id: pidgin-pidgincredentialproviderstore
+ * @short_description: A GtkListStore that keeps track of credential providers.
+ * @title: Credential Provider Store
+ *
+ * #PidginCredentialProviderStore is a #GtkListStore that automatically keeps
+ * track of what credential providers are currently available in libpurple.
+ * It's intended to be used any time that you need to present a credential
+ * provider selection to the user.
+ */
+
+#include <gtk/gtk.h>
+
+#include <purple.h>
+
+typedef enum {
+	PIDGIN_CREDENTIAL_PROVIDER_STORE_COLUMN_ID,
+	PIDGIN_CREDENTIAL_PROVIDER_STORE_COLUMN_NAME,
+	PIDGIN_CREDENTIAL_PROVIDER_STORE_N_COLUMNS,
+} PidginCredentialProviderStoreColumn;
+
+G_BEGIN_DECLS
+
+#define PIDGIN_TYPE_CREDENTIAL_PROVIDER_STORE pidgin_credential_provider_store_get_type()
+G_DECLARE_FINAL_TYPE(PidginCredentialProviderStore, pidgin_credential_provider_store, PIDGIN,
+                     CREDENTIAL_PROVIDER_STORE, GtkListStore)
+
+/**
+ * pidgin_credential_provider_store_new:
+ *
+ * Creates a new #PidginCredentialProviderStore that can be used anywhere a
+ * #GtkListStore can be used.
+ *
+ * Returns: (transfer full): The new #PidginCredentialProviderStore instance.
+ *
+ * Since: 3.0.0
+ */
+GtkListStore *pidgin_credential_provider_store_new(void);
+
+G_END_DECLS
+
+#endif /* PIDGIN_CREDENTIAL_PROVIDER_STORE_H */
diff --git a/pidgin/pidgincredentialproviderstore.c b/pidgin/pidgincredentialproviderstore.c
new file mode 100644
--- /dev/null
+++ b/pidgin/pidgincredentialproviderstore.c
@@ -0,0 +1,178 @@
+/*
+ * Pidgin - Internet Messenger
+ * Copyright (C) Pidgin Developers <devel@pidgin.im>
+ *
+ * Pidgin is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <glib/gi18n-lib.h>
+
+#include "pidgin/pidgincredentialproviderstore.h"
+
+struct _PidginCredentialProviderStore {
+	GtkListStore parent;
+};
+
+/******************************************************************************
+ * Helpers
+ *****************************************************************************/
+static void
+pidgin_credential_provider_store_add(PidginCredentialProviderStore *store,
+                                     PurpleCredentialProvider *provider)
+{
+	GtkTreeIter iter;
+	const gchar *id = NULL, *name = NULL;
+
+	id = purple_credential_provider_get_id(provider);
+	name = purple_credential_provider_get_name(provider);
+
+	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,
+		-1
+	);
+}
+
+static void
+pidgin_credential_provider_store_add_helper(PurpleCredentialProvider *provider,
+                                            gpointer data)
+{
+	pidgin_credential_provider_store_add(PIDGIN_CREDENTIAL_PROVIDER_STORE(data),
+	                                     provider);
+}
+
+static void
+pidgin_credential_provider_store_add_providers(PidginCredentialProviderStore *store)
+{
+	PurpleCredentialManager *manager = NULL;
+
+	manager = purple_credential_manager_get_default();
+
+	purple_credential_manager_foreach_provider(manager,
+	                                           pidgin_credential_provider_store_add_helper,
+	                                           store);
+}
+
+static void
+pidgin_credential_provider_store_remove(PidginCredentialProviderStore *store,
+                                        PurpleCredentialProvider *provider)
+{
+	GtkTreeIter iter;
+	const gchar *id = NULL;
+
+	id = purple_credential_provider_get_id(provider);
+
+	if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter) == FALSE) {
+		purple_debug_warning("credential-provider-store",
+		                     "asked to remove provider %s but the store is "
+		                     "empty",
+		                     id);
+		return;
+	}
+
+	/* walk through the store and look for the provider to remove */
+	do {
+		gchar *found = NULL;
+
+		gtk_tree_model_get(
+			GTK_TREE_MODEL(store),
+			&iter,
+			PIDGIN_CREDENTIAL_PROVIDER_STORE_COLUMN_ID, &found,
+			-1
+		);
+
+		if(purple_strequal(found, id)) {
+			g_free(found);
+
+			gtk_list_store_remove(GTK_LIST_STORE(store), &iter);
+
+			return;
+		}
+
+		g_free(found);
+	} while(gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter));
+}
+
+/******************************************************************************
+ * Callbacks
+ *****************************************************************************/
+static void
+purple_credential_provider_store_registered_cb(PurpleCredentialManager *manager,
+                                               PurpleCredentialProvider *provider,
+                                               gpointer data)
+{
+	pidgin_credential_provider_store_add(PIDGIN_CREDENTIAL_PROVIDER_STORE(data),
+	                                     provider);
+}
+
+static void
+purple_credential_provider_store_unregistered_cb(PurpleCredentialManager *manager,
+                                                 PurpleCredentialProvider *provider,
+                                                 gpointer data)
+{
+	pidgin_credential_provider_store_remove(PIDGIN_CREDENTIAL_PROVIDER_STORE(data),
+	                                        provider);
+}
+
+/******************************************************************************
+ * GObject Implementation
+ *****************************************************************************/
+G_DEFINE_TYPE(PidginCredentialProviderStore, pidgin_credential_provider_store, GTK_TYPE_LIST_STORE)
+
+static void
+pidgin_credential_provider_store_init(PidginCredentialProviderStore *store) {
+	PurpleCredentialManager *manager = NULL;
+	GType types[PIDGIN_CREDENTIAL_PROVIDER_STORE_N_COLUMNS] = {
+		G_TYPE_STRING,
+		G_TYPE_STRING,
+	};
+
+	gtk_list_store_set_column_types(
+		GTK_LIST_STORE(store),
+		PIDGIN_CREDENTIAL_PROVIDER_STORE_N_COLUMNS,
+		types
+	);
+
+	/* add the known providers */
+	pidgin_credential_provider_store_add_providers(store);
+
+	manager = purple_credential_manager_get_default();
+
+	g_signal_connect(G_OBJECT(manager), "provider-registered",
+	                 G_CALLBACK(purple_credential_provider_store_registered_cb),
+	                 store);
+	g_signal_connect(G_OBJECT(manager), "provider-unregistered",
+	                 G_CALLBACK(purple_credential_provider_store_unregistered_cb),
+	                 store);
+}
+
+static void
+pidgin_credential_provider_store_class_init(PidginCredentialProviderStoreClass *klass) {
+}
+
+/******************************************************************************
+ * API
+ *****************************************************************************/
+GtkListStore *
+pidgin_credential_provider_store_new(void) {
+	return GTK_LIST_STORE(g_object_new(PIDGIN_TYPE_CREDENTIAL_PROVIDER_STORE,
+	                      NULL));
+}
diff --git a/pidgin/pidgincredentialspage.h b/pidgin/pidgincredentialspage.h
new file mode 100644
--- /dev/null
+++ b/pidgin/pidgincredentialspage.h
@@ -0,0 +1,61 @@
+/*
+ * Pidgin - Internet Messenger
+ * Copyright (C) Pidgin Developers <devel@pidgin.im>
+ *
+ * Pidgin is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#if !defined(PIDGIN_GLOBAL_HEADER_INSIDE) && !defined(PIDGIN_COMPILATION)
+# error "only <pidgin.h> may be included directly"
+#endif
+
+#ifndef PIDGIN_CREDENTIALS_PAGE_H
+#define PIDGIN_CREDENTIALS_PAGE_H
+
+/**
+ * SECTION:pidgincredentialspage
+ * @section_id: pidgin-pidgincredentialspage
+ * @short_description: The preferences page for credential management.
+ * @title: Credential management widget
+ *
+ * #PidginCredentialsPage is a widget for the preferences window to let users
+ * choose and configure their credential provider.
+ */
+
+#include <glib.h>
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define PIDGIN_TYPE_CREDENTIALS_PAGE (pidgin_credentials_page_get_type())
+G_DECLARE_FINAL_TYPE(PidginCredentialsPage, pidgin_credentials_page,
+                     PIDGIN, CREDENTIALS_PAGE, GtkBox)
+
+/**
+ * pidgin_credentials_page_new:
+ *
+ * Creates a new #PidginCredentialsPage instance.
+ *
+ * Returns: (transfer full): The new #PidginCredentialsPage instance.
+ */
+GtkWidget *pidgin_credentials_page_new(void);
+
+G_END_DECLS
+
+#endif /* PIDGIN_CREDENTIALS_PAGE_H */
diff --git a/pidgin/pidgincredentialspage.c b/pidgin/pidgincredentialspage.c
new file mode 100644
--- /dev/null
+++ b/pidgin/pidgincredentialspage.c
@@ -0,0 +1,182 @@
+/*
+ * Pidgin - Internet Messenger
+ * Copyright (C) Pidgin Developers <devel@pidgin.im>
+ *
+ * Pidgin is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <purple.h>
+
+#include "pidgincredentialspage.h"
+
+#include "pidgincredentialproviderstore.h"
+
+struct _PidginCredentialsPage {
+	GtkBox parent;
+
+	GtkWidget *combo;
+};
+
+G_DEFINE_TYPE(PidginCredentialsPage, pidgin_credentials_page,
+              GTK_TYPE_BOX)
+
+/******************************************************************************
+ * Helpers
+ *****************************************************************************/
+static void
+pidgin_credentials_page_combo_changed_cb(GtkComboBox *widget, gpointer data) {
+	PidginCredentialsPage *page = PIDGIN_CREDENTIALS_PAGE(data);
+	GtkTreeIter iter;
+
+	if(gtk_combo_box_get_active_iter(GTK_COMBO_BOX(page->combo), &iter)) {
+		PurpleCredentialManager *manager = NULL;
+		GError *error = NULL;
+		GtkTreeModel *model = NULL;
+		gchar *id = NULL;
+
+		model = gtk_combo_box_get_model(GTK_COMBO_BOX(page->combo));
+
+		gtk_tree_model_get(model, &iter,
+		                   PIDGIN_CREDENTIAL_PROVIDER_STORE_COLUMN_ID, &id,
+		                   -1);
+
+		manager = purple_credential_manager_get_default();
+		if(purple_credential_manager_set_active_provider(manager, id, &error)) {
+			purple_prefs_set_string("/purple/credentials/active-provider", id);
+
+			g_free(id);
+
+			return;
+		}
+
+		purple_debug_warning("credentials-page", "failed to set the active "
+		                     "credential provider to '%s': %s",
+		                     id,
+		                     error ? error->message : "unknown error");
+
+		g_free(id);
+		g_clear_error(&error);
+	}
+}
+
+static void
+pidgin_credentials_page_set_active_provider(PidginCredentialsPage *page,
+                                            const gchar *new_id)
+{
+	GtkTreeIter iter;
+	GtkTreeModel *model = NULL;
+
+	model = gtk_combo_box_get_model(GTK_COMBO_BOX(page->combo));
+
+	if(gtk_tree_model_get_iter_first(model, &iter)) {
+		do {
+			gchar *id = NULL;
+
+			gtk_tree_model_get(model, &iter,
+			                   PIDGIN_CREDENTIAL_PROVIDER_STORE_COLUMN_ID, &id,
+			                   -1);
+
+			if(purple_strequal(new_id, id)) {
+				g_signal_handlers_block_by_func(page->combo,
+				                                pidgin_credentials_page_combo_changed_cb,
+				                                page);
+
+				gtk_combo_box_set_active_iter(GTK_COMBO_BOX(page->combo),
+				                              &iter);
+
+				g_signal_handlers_unblock_by_func(page->combo,
+				                                  pidgin_credentials_page_combo_changed_cb,
+				                                  page);
+
+				g_free(id);
+
+				return;
+			}
+
+			g_free(id);
+		} while(gtk_tree_model_iter_next(model, &iter));
+	}
+}
+
+static void
+pidgin_credentials_page_active_provider_changed_cb(const gchar *name,
+                                                   PurplePrefType type,
+                                                   gconstpointer value,
+                                                   gpointer data)
+{
+	PidginCredentialsPage *page = PIDGIN_CREDENTIALS_PAGE(data);
+
+	pidgin_credentials_page_set_active_provider(page, (const gchar *)value);
+}
+
+/******************************************************************************
+ * GObjectImplementation
+ *****************************************************************************/
+static void
+pidgin_credentials_page_finalize(GObject *obj) {
+	purple_prefs_disconnect_by_handle(obj);
+
+	G_OBJECT_CLASS(pidgin_credentials_page_parent_class)->finalize(obj);
+}
+
+static void
+pidgin_credentials_page_init(PidginCredentialsPage *page) {
+	const gchar *active = NULL;
+
+	gtk_widget_init_template(GTK_WIDGET(page));
+
+	purple_prefs_add_none("/purple/credentials");
+	purple_prefs_add_string("/purple/credentials/active-provider", NULL);
+
+	purple_prefs_connect_callback(page, "/purple/credentials/active-provider",
+	                              pidgin_credentials_page_active_provider_changed_cb,
+	                              page);
+
+	g_signal_connect(G_OBJECT(page->combo), "changed",
+	                 G_CALLBACK(pidgin_credentials_page_combo_changed_cb),
+	                 page);
+
+	active = purple_prefs_get_string("/purple/credentials/active-provider");
+	if(active != NULL) {
+		pidgin_credentials_page_set_active_provider(page, active);
+	}
+}
+
+static void
+pidgin_credentials_page_class_init(PidginCredentialsPageClass *klass) {
+	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+	GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
+
+	obj_class->finalize = pidgin_credentials_page_finalize;
+
+	gtk_widget_class_set_template_from_resource(
+	    widget_class,
+	    "/im/pidgin/Pidgin/Prefs/credentials.ui"
+	);
+
+	gtk_widget_class_bind_template_child(widget_class, PidginCredentialsPage,
+	                                     combo);
+}
+
+/******************************************************************************
+ * API
+ *****************************************************************************/
+GtkWidget *
+pidgin_credentials_page_new(void) {
+	return GTK_WIDGET(g_object_new(PIDGIN_TYPE_CREDENTIALS_PAGE, NULL));
+}
diff --git a/pidgin/resources/Prefs/credentials.ui b/pidgin/resources/Prefs/credentials.ui
new file mode 100644
--- /dev/null
+++ b/pidgin/resources/Prefs/credentials.ui
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.2 -->
+<interface>
+  <requires lib="gtk+" version="3.20"/>
+  <requires lib="pidgin" version="3.0"/>
+  <object class="PidginCredentialProviderStore" id="store"/>
+  <template class="PidginCredentialsPage" parent="GtkBox">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="border_width">12</property>
+    <property name="orientation">vertical</property>
+    <property name="spacing">18</property>
+    <child>
+      <object class="GtkFrame">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="label_xalign">0</property>
+        <property name="shadow_type">none</property>
+        <child>
+          <object class="GtkAlignment">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="left_padding">12</property>
+            <child>
+              <object class="GtkBox">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <child>
+                  <object class="GtkLabel">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="label" translatable="yes">Provider:</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkComboBox" id="combo">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="model">store</property>
+                    <child>
+                      <object class="GtkCellRendererText"/>
+                      <attributes>
+                        <attribute name="text">1</attribute>
+                      </attributes>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child type="label">
+          <object class="GtkLabel">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">Credential Provider</property>
+            <attributes>
+              <attribute name="weight" value="bold"/>
+            </attributes>
+          </object>
+        </child>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="fill">True</property>
+        <property name="position">0</property>
+      </packing>
+    </child>
+  </template>
+</interface>
diff --git a/pidgin/resources/Prefs/prefs.ui b/pidgin/resources/Prefs/prefs.ui
--- a/pidgin/resources/Prefs/prefs.ui
+++ b/pidgin/resources/Prefs/prefs.ui
@@ -22,6 +22,7 @@
 <interface>
   <requires lib="Talkatu" version="0.0"/>
   <requires lib="gtk+" version="3.20"/>
+  <requires lib="pidgin" version="3.0"/>
   <!-- interface-license-type gplv2 -->
   <!-- interface-name Pidgin -->
   <!-- interface-description Internet Messenger -->
@@ -2639,6 +2640,25 @@
                     <property name="position">7</property>
                   </packing>
                 </child>
+                <child>
+                  <object class="PidginCredentialsPage">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="orientation">vertical</property>
+                    <property name="spacing">18</property>
+                    <child>
+                      <placeholder/>
+                    </child>
+                    <child>
+                      <placeholder/>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="name">credentials</property>
+                    <property name="title" translatable="yes">Credentials</property>
+                    <property name="position">8</property>
+                  </packing>
+                </child>
               </object>
               <packing>
                 <property name="expand">False</property>
@@ -2646,6 +2666,9 @@
                 <property name="position">1</property>
               </packing>
             </child>
+            <child>
+              <placeholder/>
+            </child>
           </object>
           <packing>
             <property name="expand">True</property>
diff --git a/pidgin/resources/pidgin.gresource.xml b/pidgin/resources/pidgin.gresource.xml
--- a/pidgin/resources/pidgin.gresource.xml
+++ b/pidgin/resources/pidgin.gresource.xml
@@ -20,6 +20,7 @@
     <file compressed="true">Log/log-viewer.ui</file>
     <file compressed="true">Plugins/dialog.ui</file>
     <file compressed="true">Plugins/menu.ui</file>
+    <file compressed="true">Prefs/credentials.ui</file>
     <file compressed="true">Prefs/ip.css</file>
     <file compressed="true">Prefs/prefs.ui</file>
     <file compressed="true">Prefs/vv.ui</file>
diff --git a/po/POTFILES.in b/po/POTFILES.in
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -354,6 +354,8 @@
 pidgin/pidgincontactcompletion.c
 pidgin/pidgincontactlist.c
 pidgin/pidginconversationwindow.c
+pidgin/pidgincredentialproviderstore.c
+pidgin/pidgincredentialspage.c
 pidgin/pidgindebug.c
 pidgin/pidgindialog.c
 pidgin/pidgingdkpixbuf.c
@@ -403,6 +405,7 @@
 pidgin/resources/Log/log-viewer.ui
 pidgin/resources/Plugins/dialog.ui
 pidgin/resources/Plugins/menu.ui
+pidgin/resources/Prefs/credentials.ui
 pidgin/resources/Prefs/prefs.ui
 pidgin/resources/Prefs/vv.ui
 pidgin/resources/Privacy/dialog.ui
