diff --git a/app/Users/Controllers/UserAccountController.php b/app/Users/Controllers/UserAccountController.php
index 6bf23df47..d9cb58f8c 100644
--- a/app/Users/Controllers/UserAccountController.php
+++ b/app/Users/Controllers/UserAccountController.php
@@ -161,7 +161,7 @@ class UserAccountController extends Controller
      */
     public function showAuth(SocialAuthService $socialAuthService)
     {
-        $mfaMethods = user()->mfaValues->groupBy('method');
+        $mfaMethods = user()->mfaValues()->get()->groupBy('method');
 
         $this->setPageTitle(trans('preferences.auth'));
 
diff --git a/tests/Permissions/RolePermissionsTest.php b/tests/Permissions/RolePermissionsTest.php
index d15c1617c..ccb158faf 100644
--- a/tests/Permissions/RolePermissionsTest.php
+++ b/tests/Permissions/RolePermissionsTest.php
@@ -49,6 +49,7 @@ class RolePermissionsTest extends TestCase
 
         $resp = $this->get('/my-account/profile')->assertOk();
         $this->withHtml($resp)->assertElementExists('input[name=email][disabled]');
+        $resp->assertSee('Unfortunately you don\'t have permission to change your email address.');
         $this->put('/my-account/profile', [
             'name'  => 'my_new_name',
             'email' => 'new_email@example.com',
diff --git a/tests/User/UserMyAccountTest.php b/tests/User/UserMyAccountTest.php
index 63c54daad..e1b40dadd 100644
--- a/tests/User/UserMyAccountTest.php
+++ b/tests/User/UserMyAccountTest.php
@@ -2,8 +2,13 @@
 
 namespace Tests\User;
 
+use BookStack\Access\Mfa\MfaValue;
 use BookStack\Activity\Tools\UserEntityWatchOptions;
 use BookStack\Activity\WatchLevels;
+use BookStack\Api\ApiToken;
+use BookStack\Uploads\Image;
+use Illuminate\Support\Facades\Hash;
+use Illuminate\Support\Str;
 use Tests\TestCase;
 
 class UserMyAccountTest extends TestCase
@@ -26,6 +31,166 @@ class UserMyAccountTest extends TestCase
             $resp->assertRedirect('/');
         }
     }
+
+    public function test_profile_updating()
+    {
+        $editor = $this->users->editor();
+
+        $resp = $this->actingAs($editor)->get('/my-account/profile');
+        $resp->assertSee('Profile Details');
+
+        $html = $this->withHtml($resp);
+        $html->assertFieldHasValue('name', $editor->name);
+        $html->assertFieldHasValue('email', $editor->email);
+
+        $resp = $this->put('/my-account/profile', [
+            'name' => 'Barryius',
+            'email' => 'barryius@example.com',
+            'language' => 'fr',
+        ]);
+
+        $resp->assertRedirect('/my-account/profile');
+        $this->assertDatabaseHas('users', [
+            'name' => 'Barryius',
+            'email' => $editor->email, // No email change due to not having permissions
+        ]);
+        $this->assertEquals(setting()->getUser($editor, 'language'), 'fr');
+    }
+
+    public function test_profile_user_avatar_update_and_reset()
+    {
+        $user = $this->users->viewer();
+        $avatarFile = $this->files->uploadedImage('avatar-icon.png');
+
+        $this->assertEquals(0, $user->image_id);
+
+        $upload = $this->actingAs($user)->call('PUT', "/my-account/profile", [
+            'name' => 'Barry Scott',
+        ], [], ['profile_image' => $avatarFile], []);
+        $upload->assertRedirect('/my-account/profile');
+
+
+        $user->refresh();
+        $this->assertNotEquals(0, $user->image_id);
+        /** @var Image $image */
+        $image = Image::query()->findOrFail($user->image_id);
+        $this->assertFileExists(public_path($image->path));
+
+        $reset = $this->put("/my-account/profile", [
+            'name' => 'Barry Scott',
+            'profile_image_reset' => 'true',
+        ]);
+        $upload->assertRedirect('/my-account/profile');
+
+        $user->refresh();
+        $this->assertFileDoesNotExist(public_path($image->path));
+        $this->assertEquals(0, $user->image_id);
+    }
+
+    public function test_profile_admin_options_link_shows_if_permissions_allow()
+    {
+        $editor = $this->users->editor();
+
+        $resp = $this->actingAs($editor)->get('/my-account/profile');
+        $resp->assertDontSee('Administrator Options');
+        $this->withHtml($resp)->assertLinkNotExists(url("/settings/users/{$editor->id}"));
+
+        $this->permissions->grantUserRolePermissions($editor, ['users-manage']);
+
+        $resp = $this->actingAs($editor)->get('/my-account/profile');
+        $resp->assertSee('Administrator Options');
+        $this->withHtml($resp)->assertLinkExists(url("/settings/users/{$editor->id}"));
+    }
+
+    public function test_profile_self_delete()
+    {
+        $editor = $this->users->editor();
+
+        $resp = $this->actingAs($editor)->get('/my-account/profile');
+        $this->withHtml($resp)->assertLinkExists(url('/my-account/delete'), 'Delete Account');
+
+        $resp = $this->get('/my-account/delete');
+        $resp->assertSee('Delete My Account');
+        $this->withHtml($resp)->assertElementContains('form[action$="/my-account"] button', 'Confirm');
+
+        $resp = $this->delete('/my-account');
+        $resp->assertRedirect('/');
+
+        $this->assertDatabaseMissing('users', ['id' => $editor->id]);
+    }
+
+    public function test_profile_self_delete_shows_ownership_migration_if_can_manage_users()
+    {
+        $editor = $this->users->editor();
+
+        $resp = $this->actingAs($editor)->get('/my-account/delete');
+        $resp->assertDontSee('Migrate Ownership');
+
+        $this->permissions->grantUserRolePermissions($editor, ['users-manage']);
+
+        $resp = $this->actingAs($editor)->get('/my-account/delete');
+        $resp->assertSee('Migrate Ownership');
+    }
+
+    public function test_auth_password_change()
+    {
+        $editor = $this->users->editor();
+
+        $resp = $this->actingAs($editor)->get('/my-account/auth');
+        $resp->assertSee('Change Password');
+        $this->withHtml($resp)->assertElementExists('form[action$="/my-account/auth/password"]');
+
+        $password = Str::random();
+        $resp = $this->put('/my-account/auth/password', [
+            'password' => $password,
+            'password-confirm' => $password,
+        ]);
+        $resp->assertRedirect('/my-account/auth');
+
+        $editor->refresh();
+        $this->assertTrue(Hash::check($password, $editor->password));
+    }
+
+    public function test_auth_password_change_hides_if_not_using_email_auth()
+    {
+        $editor = $this->users->editor();
+
+        $resp = $this->actingAs($editor)->get('/my-account/auth');
+        $resp->assertSee('Change Password');
+
+        config()->set('auth.method', 'oidc');
+
+        $resp = $this->actingAs($editor)->get('/my-account/auth');
+        $resp->assertDontSee('Change Password');
+    }
+
+    public function test_auth_page_has_mfa_links()
+    {
+        $editor = $this->users->editor();
+        $resp = $this->actingAs($editor)->get('/my-account/auth');
+        $resp->assertSee('0 methods configured');
+        $this->withHtml($resp)->assertLinkExists(url('/mfa/setup'));
+
+        MfaValue::upsertWithValue($editor, 'totp', 'testval');
+
+        $resp = $this->get('/my-account/auth');
+        $resp->assertSee('1 method configured');
+    }
+
+    public function test_auth_page_api_tokens()
+    {
+        $editor = $this->users->editor();
+        $resp = $this->actingAs($editor)->get('/my-account/auth');
+        $resp->assertSee('API Tokens');
+        $this->withHtml($resp)->assertLinkExists(url("/api-tokens/{$editor->id}/create?context=my-account"));
+
+        ApiToken::factory()->create(['user_id' => $editor->id, 'name' => 'My great token']);
+        $editor->unsetRelations();
+
+        $resp = $this->get('/my-account/auth');
+        $resp->assertSee('My great token');
+    }
+
     public function test_interface_shortcuts_updating()
     {
         $this->asEditor();