diff --git a/apps/twofactor_backupcodes/js/settings.js b/apps/twofactor_backupcodes/js/settings.js
index 0341dbf13a6bbccef68520adb9ed01448f462eeb..29252548de595cd6659c7844ed241a01134bbad7 100644
Binary files a/apps/twofactor_backupcodes/js/settings.js and b/apps/twofactor_backupcodes/js/settings.js differ
diff --git a/apps/twofactor_backupcodes/js/settings.js.map b/apps/twofactor_backupcodes/js/settings.js.map
index 01fc5d81ea47cceed6b01dfae336d77be013bbd8..27b3318ff64a2ea40823d2de7e764ee97ffad3f2 100644
Binary files a/apps/twofactor_backupcodes/js/settings.js.map and b/apps/twofactor_backupcodes/js/settings.js.map differ
diff --git a/apps/twofactor_backupcodes/lib/Provider/BackupCodesProvider.php b/apps/twofactor_backupcodes/lib/Provider/BackupCodesProvider.php
index 03d1ee0d40572a9f042f0afac15a7d9ab178753f..27653c1dd619db50a212dccfa9ad69d7dd1f74c4 100644
--- a/apps/twofactor_backupcodes/lib/Provider/BackupCodesProvider.php
+++ b/apps/twofactor_backupcodes/lib/Provider/BackupCodesProvider.php
@@ -25,12 +25,15 @@ namespace OCA\TwoFactorBackupCodes\Provider;
 
 use OC\App\AppManager;
 use OCA\TwoFactorBackupCodes\Service\BackupCodeStorage;
+use OCA\TwoFactorBackupCodes\Settings\Personal;
+use OCP\Authentication\TwoFactorAuth\IPersonalProviderSettings;
 use OCP\Authentication\TwoFactorAuth\IProvider;
+use OCP\Authentication\TwoFactorAuth\IProvidesPersonalSettings;
 use OCP\IL10N;
 use OCP\IUser;
 use OCP\Template;
 
-class BackupCodesProvider implements IProvider {
+class BackupCodesProvider implements IProvider, IProvidesPersonalSettings {
 
 	/** @var string */
 	private $appName;
@@ -139,4 +142,14 @@ class BackupCodesProvider implements IProvider {
 		return false;
 	}
 
+	/**
+	 * @param IUser $user
+	 *
+	 * @return IPersonalProviderSettings
+	 */
+	public function getPersonalSettings(IUser $user): IPersonalProviderSettings {
+		return new Personal();
+	}
+
 }
+
diff --git a/apps/twofactor_backupcodes/lib/Settings/Personal.php b/apps/twofactor_backupcodes/lib/Settings/Personal.php
index eb28dacb42b5edbc663133c764d4e055302a5baf..0b71b1da0886e1fdcc2529efac5f5e6b8fe12dca 100644
--- a/apps/twofactor_backupcodes/lib/Settings/Personal.php
+++ b/apps/twofactor_backupcodes/lib/Settings/Personal.php
@@ -1,8 +1,9 @@
 <?php
+
+declare(strict_types=1);
+
 /**
- * @copyright Copyright (c) 2017 Arthur Schiwon <blizzz@arthur-schiwon.de>
- *
- * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
+ * @author Christoph Wurst <christoph@winzerhof-wurst.at>
  *
  * @license GNU AGPL version 3 or any later version
  *
@@ -24,59 +25,13 @@
 namespace OCA\TwoFactorBackupCodes\Settings;
 
 
-use OCA\TwoFactorBackupCodes\AppInfo\Application;
-use OCA\TwoFactorBackupCodes\Provider\BackupCodesProvider;
-use OCP\AppFramework\Http\TemplateResponse;
-use OCP\IUserSession;
-use OCP\Settings\ISettings;
-
-class Personal implements ISettings {
-
-	/** @var Application */
-	private $app;
-	/** @var BackupCodesProvider */
-	private $provider;
-	/** @var IUserSession */
-	private $userSession;
+use OCP\Authentication\TwoFactorAuth\IPersonalProviderSettings;
+use OCP\Template;
 
-	public function __construct(Application $app, BackupCodesProvider $provider, IUserSession $userSession) {
-		$this->app = $app;
-		$this->provider = $provider;
-		$this->userSession = $userSession;
-	}
-
-	/**
-	 * @return TemplateResponse returns the instance with all parameters set, ready to be rendered
-	 * @since 9.1
-	 */
-	public function getForm() {
-		$templateOwner = 'settings';
-		$templateName = 'settings/empty';
-		if ($this->provider->isActive($this->userSession->getUser())) {
-			$templateOwner = $this->app->getContainer()->getAppName();
-			$templateName = 'personal';
-		}
+class Personal implements IPersonalProviderSettings {
 
-		return new TemplateResponse($templateOwner, $templateName, [], '');
+	public function getBody(): Template {
+		return new Template('twofactor_backupcodes', 'personal');
 	}
 
-	/**
-	 * @return string the section ID, e.g. 'sharing'
-	 * @since 9.1
-	 */
-	public function getSection() {
-		return 'security';
-	}
-
-	/**
-	 * @return int whether the form should be rather on the top or bottom of
-	 * the admin section. The forms are arranged in ascending order of the
-	 * priority values. It is required to return a value between 0 and 100.
-	 *
-	 * E.g.: 70
-	 * @since 9.1
-	 */
-	public function getPriority() {
-		return 40;
-	}
 }
diff --git a/apps/twofactor_backupcodes/src/views/PersonalSettings.vue b/apps/twofactor_backupcodes/src/views/PersonalSettings.vue
index ac53de2e65cf74d0dc75de33a26bdc73245edaf8..fb4980abb59ea731f0a340a3bf7e1804334cf1d3 100644
--- a/apps/twofactor_backupcodes/src/views/PersonalSettings.vue
+++ b/apps/twofactor_backupcodes/src/views/PersonalSettings.vue
@@ -14,7 +14,7 @@
 					<li v-for="code in codes" class="backup-code">{{code}}</li>
 					</ul>
 					<a :href="downloadUrl"
-					   class="button"
+					   class="button primary"
 					   download="Nextcloud-backup-codes.txt">{{ t('twofactor_backupcodes', 'Save backup codes') }}</a>
 					<button class="button"
 							v-on:click="printCodes">{{ t('twofactor_backupcodes', 'Print backup codes') }}</button>
@@ -25,9 +25,9 @@
 						:class="{'icon-loading-small': generatingCodes}"
 						v-on:click="generateBackupCodes">{{ t('twofactor_backupcodes', 'Regenerate backup codes') }}</button>
 			</p>
-			<p>
+			<p><em>
 				{{ t('twofactor_backupcodes', 'If you regenerate backup codes, you automatically invalidate old codes.') }}
-			</p>
+			</em></p>
 		</template>
 	</div>
 </template>
diff --git a/apps/twofactor_backupcodes/templates/personal.php b/apps/twofactor_backupcodes/templates/personal.php
index e440158f4cdf554538e8b17cc4a454666d9d195a..4c887aff91596b3bfe487f4619e1bcff58348018 100644
--- a/apps/twofactor_backupcodes/templates/personal.php
+++ b/apps/twofactor_backupcodes/templates/personal.php
@@ -5,7 +5,4 @@ style('twofactor_backupcodes', 'style');
 
 ?>
 
-<div class="section">
-    <h2 data-anchor-name="second-factor-backup-codes"><?php p($l->t('Second-factor backup codes')); ?></h2>
-    <div id="twofactor-backupcodes-settings"></div>
-</div>
+<div id="twofactor-backupcodes-settings"></div>
diff --git a/lib/private/Settings/Personal/Security.php b/lib/private/Settings/Personal/Security.php
index efcfd5589ceb74fea38f0cd6b34324a514d34fd6..0efe2d0746b3dc0b0d019d7fe06578e1d8c76a2c 100644
--- a/lib/private/Settings/Personal/Security.php
+++ b/lib/private/Settings/Personal/Security.php
@@ -24,18 +24,41 @@
 namespace OC\Settings\Personal;
 
 
+use function array_filter;
+use function array_map;
+use function is_null;
+use OC\Authentication\TwoFactorAuth\Manager as TwoFactorManager;
+use OC\Authentication\TwoFactorAuth\ProviderLoader;
 use OCP\AppFramework\Http\TemplateResponse;
+use OCP\Authentication\TwoFactorAuth\IProvider;
+use OCP\Authentication\TwoFactorAuth\IProvidesPersonalSettings;
 use OCP\IUserManager;
+use OCP\IUserSession;
 use OCP\Settings\ISettings;
 
 class Security implements ISettings {
 
+	/** @var IUserManager */
 	private $userManager;
 
-	public function __construct(
-		IUserManager $userManager
-	) {
+	/** @var TwoFactorManager */
+	private $twoFactorManager;
+
+	/** @var ProviderLoader */
+	private $providerLoader;
+
+	/** @var IUserSession */
+	private $userSession;
+
+
+	public function __construct(IUserManager $userManager,
+								TwoFactorManager $providerManager,
+								ProviderLoader $providerLoader,
+								IUserSession $userSession) {
 		$this->userManager = $userManager;
+		$this->twoFactorManager = $providerManager;
+		$this->providerLoader = $providerLoader;
+		$this->userSession = $userSession;
 	}
 
 	/**
@@ -50,7 +73,8 @@ class Security implements ISettings {
 		}
 
 		return new TemplateResponse('settings', 'settings/personal/security', [
-			'passwordChangeSupported' => $passwordChangeSupported
+			'passwordChangeSupported' => $passwordChangeSupported,
+			'twoFactorProviderData' => $this->getTwoFactorProviderData(),
 		]);
 	}
 
@@ -73,4 +97,24 @@ class Security implements ISettings {
 	public function getPriority() {
 		return 10;
 	}
+
+	private function getTwoFactorProviderData(): array {
+		$user = $this->userSession->getUser();
+		if (is_null($user)) {
+			// Actually impossible, but still …
+			return [];
+		}
+
+		return [
+			'isEnabled' => $this->twoFactorManager->isTwoFactorAuthenticated($user),
+			'providers' => array_map(function (IProvidesPersonalSettings $provider) use ($user) {
+				return [
+					'provider' => $provider,
+					'settings' => $provider->getPersonalSettings($user)
+				];
+			}, array_filter($this->providerLoader->getProviders($user), function (IProvider $provider) {
+				return $provider instanceof IProvidesPersonalSettings;
+			}))
+		];
+	}
 }
diff --git a/lib/public/Authentication/TwoFactorAuth/IPersonalProviderSettings.php b/lib/public/Authentication/TwoFactorAuth/IPersonalProviderSettings.php
new file mode 100644
index 0000000000000000000000000000000000000000..80552d1fe8cf1a6610bcde9772d26bcc8e449727
--- /dev/null
+++ b/lib/public/Authentication/TwoFactorAuth/IPersonalProviderSettings.php
@@ -0,0 +1,43 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @author Christoph Wurst <christoph@owncloud.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCP\Authentication\TwoFactorAuth;
+
+use OCP\Template;
+
+/**
+ * Interface IPersonalProviderSettings
+ *
+ * @since 15.0.0
+ */
+interface IPersonalProviderSettings {
+
+	/**
+	 * @return Template
+	 *
+	 * @since 15.0.0
+	 */
+	public function getBody(): Template;
+
+}
diff --git a/lib/public/Authentication/TwoFactorAuth/IProvidesPersonalSettings.php b/lib/public/Authentication/TwoFactorAuth/IProvidesPersonalSettings.php
new file mode 100644
index 0000000000000000000000000000000000000000..5ba7ad547e976194d4909ffd340724656a6d4ca3
--- /dev/null
+++ b/lib/public/Authentication/TwoFactorAuth/IProvidesPersonalSettings.php
@@ -0,0 +1,47 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @author Christoph Wurst <christoph@owncloud.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCP\Authentication\TwoFactorAuth;
+
+use OCP\IUser;
+
+/**
+ * Interface for admins that have personal settings. These settings will be shown in the
+ * security sections. Some information like the display name of the provider is read
+ * from the provider directly.
+ *
+ * @since 15.0.0
+ */
+interface IProvidesPersonalSettings extends IProvider {
+
+	/**
+	 * @param IUser $user
+	 *
+	 * @return IPersonalProviderSettings
+	 *
+	 * @since 15.0.0
+	 */
+	public function getPersonalSettings(IUser $user): IPersonalProviderSettings;
+
+}
diff --git a/settings/css/settings.scss b/settings/css/settings.scss
index ae1a456b699fd231a142b3bd5ae11b33f4358a08..08baaed4cc6877afccb4f287f23660d3c943da38 100644
--- a/settings/css/settings.scss
+++ b/settings/css/settings.scss
@@ -471,6 +471,26 @@ table.nostyle {
 	}
 }
 
+
+
+/* Two-Factor Authentication (2FA) */
+
+#two-factor-auth {
+	h3 {
+		margin-top: 24px;
+	}
+
+	li > div {
+    	margin-left: 20px;
+	}
+
+	.two-factor-provider-settings-icon {
+		width: 16px;
+		height: 16px;
+	}
+}
+
+
 #new-app-login-name,
 #new-app-password {
 	width: 245px;
diff --git a/settings/templates/settings/personal/security.php b/settings/templates/settings/personal/security.php
index 6dd0e8d3cefea175fa7b5de5f2c712c1e34fc816..6b2c37b6a88968bb35a16863c9d111413a26f8e9 100644
--- a/settings/templates/settings/personal/security.php
+++ b/settings/templates/settings/personal/security.php
@@ -101,3 +101,38 @@ if($_['passwordChangeSupported']) {
 		</div>
 	</div>
 </div>
+
+<div id="two-factor-auth" class="section">
+	<h2><?php p($l->t('Two-Factor Authentication'));?></h2>
+	<p class="settings-hint">
+		<?php
+		if ($_['twoFactorProviderData']['enabled']) {
+			p($l->t('Two-factor authentication is enabled on your account.'));
+		} else {
+			p($l->t('Two-factor authentication is disabled on your account.'));
+		}
+		?>
+	</p>
+	<ul>
+	<?php foreach ($_['twoFactorProviderData']['providers'] as $data) { ?>
+		<li>
+			<?php
+			/** @var \OCP\Authentication\TwoFactorAuth\IProvidesPersonalSettings $provider */
+			$provider = $data['provider'];
+			if ($provider instanceof \OCP\Authentication\TwoFactorAuth\IProvidesIcons) {
+				$icon = $provider->getDarkIcon();
+			} else {
+				$icon = image_path('core', 'actions/password.svg');
+			}
+			/** @var \OCP\Authentication\TwoFactorAuth\IPersonalProviderSettings $settings */
+			$settings = $data['settings'];
+			?>
+			<h3>
+				<img class="two-factor-provider-settings-icon" src="<?php p($icon) ?>" alt="">
+				<?php p($provider->getDisplayName()) ?>
+			</h3>
+			<?php print_unescaped($settings->getBody()->fetchPage()) ?>
+		</li>
+	<?php } ?>
+	</ul>
+</div>