diff --git a/.gitmodules b/.gitmodules
index d8e04923add20729550ca15a38e34d05d58982d4..26c6735cd911f2416c6e7487fe92c6020760832a 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -46,3 +46,6 @@
 [submodule "vcpkg"]
 	path = externals/vcpkg
 	url = https://github.com/Microsoft/vcpkg.git
+[submodule "cpp-jwt"]
+	path = externals/cpp-jwt
+	url = https://github.com/arun11299/cpp-jwt.git
diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt
index b4570bb697d41b42f7fe9567d3f6cac76563241a..5b74a17731598b9a95dff095f399af6130a16840 100644
--- a/externals/CMakeLists.txt
+++ b/externals/CMakeLists.txt
@@ -116,6 +116,11 @@ if (ENABLE_WEB_SERVICE)
     if (WIN32)
         target_link_libraries(httplib INTERFACE crypt32 cryptui ws2_32)
     endif()
+	
+    # cpp-jwt
+    add_library(cpp-jwt INTERFACE)
+    target_include_directories(cpp-jwt INTERFACE ./cpp-jwt/include)
+    target_compile_definitions(cpp-jwt INTERFACE CPP_JWT_USE_VENDORED_NLOHMANN_JSON)
 endif()
 
 # Opus
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 48f5c1ee0aa7904492ab5baec1d12fd2d7b8debb..c1cc62a456606c4310d961deef0aa7f360bc336f 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -716,6 +716,11 @@ add_library(core STATIC
     hle/service/vi/vi_u.h
     hle/service/wlan/wlan.cpp
     hle/service/wlan/wlan.h
+    internal_network/network.cpp
+    internal_network/network.h
+    internal_network/network_interface.cpp
+    internal_network/network_interface.h
+    internal_network/sockets.h
     loader/deconstructed_rom_directory.cpp
     loader/deconstructed_rom_directory.h
     loader/elf.cpp
@@ -743,11 +748,6 @@ add_library(core STATIC
     memory/dmnt_cheat_vm.h
     memory.cpp
     memory.h
-    internal_network/network.cpp
-    internal_network/network.h
-    internal_network/network_interface.cpp
-    internal_network/network_interface.h
-    internal_network/sockets.h
     perf_stats.cpp
     perf_stats.h
     reporter.cpp
diff --git a/src/input_common/helpers/udp_protocol.h b/src/input_common/helpers/udp_protocol.h
index 597f51cd37beb6e3b6660fababaffc64d327988a..889693e731b46ad371ea7c1a2ffbc396891c4898 100644
--- a/src/input_common/helpers/udp_protocol.h
+++ b/src/input_common/helpers/udp_protocol.h
@@ -85,7 +85,7 @@ enum RegisterFlags : u8 {
 struct Version {};
 /**
  * Requests the server to send information about what controllers are plugged into the ports
- * In citra's case, we only have one controller, so for simplicity's sake, we can just send a
+ * In yuzu's case, we only have one controller, so for simplicity's sake, we can just send a
  * request explicitly for the first controller port and leave it at that. In the future it would be
  * nice to make this configurable
  */
diff --git a/src/network/room.h b/src/network/room.h
index 5d4371c166d575d905780406ae8b5340cb231d1d..df2253bf812998fc7a3738a0042586bccbf256a1 100644
--- a/src/network/room.h
+++ b/src/network/room.h
@@ -13,7 +13,7 @@
 
 namespace Network {
 
-constexpr u32 network_version = 4; ///< The version of this Room and RoomMember
+constexpr u32 network_version = 1; ///< The version of this Room and RoomMember
 
 constexpr u16 DefaultRoomPort = 24872;
 
diff --git a/src/web_service/CMakeLists.txt b/src/web_service/CMakeLists.txt
index aff81f26d8fcbd6bb028f68b84d974c1886dd45a..753fb6e7aca99d744e987b56b57b3735babac750 100644
--- a/src/web_service/CMakeLists.txt
+++ b/src/web_service/CMakeLists.txt
@@ -5,10 +5,12 @@ add_library(web_service STATIC
     telemetry_json.h
     verify_login.cpp
     verify_login.h
+    verify_user_jwt.cpp
+    verify_user_jwt.h
     web_backend.cpp
     web_backend.h
     web_result.h
 )
 
 create_target_directory_groups(web_service)
-target_link_libraries(web_service PRIVATE common network nlohmann_json::nlohmann_json httplib)
+target_link_libraries(web_service PRIVATE common network nlohmann_json::nlohmann_json httplib cpp-jwt)
diff --git a/src/web_service/verify_user_jwt.cpp b/src/web_service/verify_user_jwt.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..78fe7bed5ae6f40989f524a9d2228d0b3db88de3
--- /dev/null
+++ b/src/web_service/verify_user_jwt.cpp
@@ -0,0 +1,60 @@
+// Copyright 2018 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <system_error>
+#include <jwt/jwt.hpp>
+#include "common/logging/log.h"
+#include "web_service/verify_user_jwt.h"
+#include "web_service/web_backend.h"
+#include "web_service/web_result.h"
+
+namespace WebService {
+
+static std::string public_key;
+std::string GetPublicKey(const std::string& host) {
+    if (public_key.empty()) {
+        Client client(host, "", ""); // no need for credentials here
+        public_key = client.GetPlain("/jwt/external/key.pem", true).returned_data;
+        if (public_key.empty()) {
+            LOG_ERROR(WebService, "Could not fetch external JWT public key, verification may fail");
+        } else {
+            LOG_INFO(WebService, "Fetched external JWT public key (size={})", public_key.size());
+        }
+    }
+    return public_key;
+}
+
+VerifyUserJWT::VerifyUserJWT(const std::string& host) : pub_key(GetPublicKey(host)) {}
+
+Network::VerifyUser::UserData VerifyUserJWT::LoadUserData(const std::string& verify_UID,
+                                                          const std::string& token) {
+    const std::string audience = fmt::format("external-{}", verify_UID);
+    using namespace jwt::params;
+    std::error_code error;
+    auto decoded =
+        jwt::decode(token, algorithms({"rs256"}), error, secret(pub_key), issuer("yuzu-core"),
+                    aud(audience), validate_iat(true), validate_jti(true));
+    if (error) {
+        LOG_INFO(WebService, "Verification failed: category={}, code={}, message={}",
+                 error.category().name(), error.value(), error.message());
+        return {};
+    }
+    Network::VerifyUser::UserData user_data{};
+    if (decoded.payload().has_claim("username")) {
+        user_data.username = decoded.payload().get_claim_value<std::string>("username");
+    }
+    if (decoded.payload().has_claim("displayName")) {
+        user_data.display_name = decoded.payload().get_claim_value<std::string>("displayName");
+    }
+    if (decoded.payload().has_claim("avatarUrl")) {
+        user_data.avatar_url = decoded.payload().get_claim_value<std::string>("avatarUrl");
+    }
+    if (decoded.payload().has_claim("roles")) {
+        auto roles = decoded.payload().get_claim_value<std::vector<std::string>>("roles");
+        user_data.moderator = std::find(roles.begin(), roles.end(), "moderator") != roles.end();
+    }
+    return user_data;
+}
+
+} // namespace WebService
diff --git a/src/web_service/verify_user_jwt.h b/src/web_service/verify_user_jwt.h
new file mode 100644
index 0000000000000000000000000000000000000000..826e01eed7f3be5b9a18776bda923b362ea3ac92
--- /dev/null
+++ b/src/web_service/verify_user_jwt.h
@@ -0,0 +1,25 @@
+// Copyright 2018 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <fmt/format.h>
+#include "network/verify_user.h"
+#include "web_service/web_backend.h"
+
+namespace WebService {
+
+class VerifyUserJWT final : public Network::VerifyUser::Backend {
+public:
+    VerifyUserJWT(const std::string& host);
+    ~VerifyUserJWT() = default;
+
+    Network::VerifyUser::UserData LoadUserData(const std::string& verify_UID,
+                                               const std::string& token) override;
+
+private:
+    std::string pub_key;
+};
+
+} // namespace WebService
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index f3cad8f311f3509f2018ccc4b3dcde9d8ba1577b..66873143e32c5ae01b3630f8384a2bab3397862d 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -326,6 +326,10 @@ if (USE_DISCORD_PRESENCE)
     target_compile_definitions(yuzu PRIVATE -DUSE_DISCORD_PRESENCE)
 endif()
 
+if (ENABLE_WEB_SERVICE)
+    target_compile_definitions(yuzu PRIVATE -DENABLE_WEB_SERVICE)
+endif()
+
 if (YUZU_USE_QT_WEB_ENGINE)
     target_link_libraries(yuzu PRIVATE Qt::WebEngineCore Qt::WebEngineWidgets)
     target_compile_definitions(yuzu PRIVATE -DYUZU_USE_QT_WEB_ENGINE)
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 7c11e2c0342253060c2344548807397e005c26c6..3b22102a800fe481c042563078698c7a39456917 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -585,48 +585,6 @@ void Config::ReadMiscellaneousValues() {
     qt_config->endGroup();
 }
 
-void Config::ReadMultiplayerValues() {
-    qt_config->beginGroup(QStringLiteral("Multiplayer"));
-
-    UISettings::values.nickname = ReadSetting(QStringLiteral("nickname"), QString{}).toString();
-    UISettings::values.ip = ReadSetting(QStringLiteral("ip"), QString{}).toString();
-    UISettings::values.port =
-        ReadSetting(QStringLiteral("port"), Network::DefaultRoomPort).toString();
-    UISettings::values.room_nickname =
-        ReadSetting(QStringLiteral("room_nickname"), QString{}).toString();
-    UISettings::values.room_name = ReadSetting(QStringLiteral("room_name"), QString{}).toString();
-    UISettings::values.room_port =
-        ReadSetting(QStringLiteral("room_port"), QStringLiteral("24872")).toString();
-    bool ok;
-    UISettings::values.host_type = ReadSetting(QStringLiteral("host_type"), 0).toUInt(&ok);
-    if (!ok) {
-        UISettings::values.host_type = 0;
-    }
-    UISettings::values.max_player = ReadSetting(QStringLiteral("max_player"), 8).toUInt();
-    UISettings::values.game_id = ReadSetting(QStringLiteral("game_id"), 0).toULongLong();
-    UISettings::values.room_description =
-        ReadSetting(QStringLiteral("room_description"), QString{}).toString();
-    // Read ban list back
-    int size = qt_config->beginReadArray(QStringLiteral("username_ban_list"));
-    UISettings::values.ban_list.first.resize(size);
-    for (int i = 0; i < size; ++i) {
-        qt_config->setArrayIndex(i);
-        UISettings::values.ban_list.first[i] =
-            ReadSetting(QStringLiteral("username")).toString().toStdString();
-    }
-    qt_config->endArray();
-    size = qt_config->beginReadArray(QStringLiteral("ip_ban_list"));
-    UISettings::values.ban_list.second.resize(size);
-    for (int i = 0; i < size; ++i) {
-        qt_config->setArrayIndex(i);
-        UISettings::values.ban_list.second[i] =
-            ReadSetting(QStringLiteral("ip")).toString().toStdString();
-    }
-    qt_config->endArray();
-
-    qt_config->endGroup();
-}
-
 void Config::ReadPathValues() {
     qt_config->beginGroup(QStringLiteral("Paths"));
 
@@ -904,6 +862,42 @@ void Config::ReadWebServiceValues() {
     qt_config->endGroup();
 }
 
+void Config::ReadMultiplayerValues() {
+    qt_config->beginGroup(QStringLiteral("Multiplayer"));
+
+    ReadBasicSetting(UISettings::values.multiplayer_nickname);
+    ReadBasicSetting(UISettings::values.multiplayer_ip);
+    ReadBasicSetting(UISettings::values.multiplayer_port);
+    ReadBasicSetting(UISettings::values.multiplayer_room_nickname);
+    ReadBasicSetting(UISettings::values.multiplayer_room_name);
+    ReadBasicSetting(UISettings::values.multiplayer_room_port);
+    ReadBasicSetting(UISettings::values.multiplayer_host_type);
+    ReadBasicSetting(UISettings::values.multiplayer_port);
+    ReadBasicSetting(UISettings::values.multiplayer_max_player);
+    ReadBasicSetting(UISettings::values.multiplayer_game_id);
+    ReadBasicSetting(UISettings::values.multiplayer_room_description);
+
+    // Read ban list back
+    int size = qt_config->beginReadArray(QStringLiteral("username_ban_list"));
+    UISettings::values.multiplayer_ban_list.first.resize(size);
+    for (int i = 0; i < size; ++i) {
+        qt_config->setArrayIndex(i);
+        UISettings::values.multiplayer_ban_list.first[i] =
+            ReadSetting(QStringLiteral("username")).toString().toStdString();
+    }
+    qt_config->endArray();
+    size = qt_config->beginReadArray(QStringLiteral("ip_ban_list"));
+    UISettings::values.multiplayer_ban_list.second.resize(size);
+    for (int i = 0; i < size; ++i) {
+        qt_config->setArrayIndex(i);
+        UISettings::values.multiplayer_ban_list.second[i] =
+            ReadSetting(QStringLiteral("ip")).toString().toStdString();
+    }
+    qt_config->endArray();
+
+    qt_config->endGroup();
+}
+
 void Config::ReadValues() {
     if (global) {
         ReadControlValues();
@@ -920,6 +914,7 @@ void Config::ReadValues() {
     ReadRendererValues();
     ReadAudioValues();
     ReadSystemValues();
+    ReadMultiplayerValues();
 }
 
 void Config::SavePlayerValue(std::size_t player_index) {
@@ -1069,6 +1064,7 @@ void Config::SaveValues() {
     SaveRendererValues();
     SaveAudioValues();
     SaveSystemValues();
+    SaveMultiplayerValues();
 }
 
 void Config::SaveAudioValues() {
@@ -1205,40 +1201,6 @@ void Config::SaveMiscellaneousValues() {
     qt_config->endGroup();
 }
 
-void Config::SaveMultiplayerValues() {
-    qt_config->beginGroup(QStringLiteral("Multiplayer"));
-
-    WriteSetting(QStringLiteral("nickname"), UISettings::values.nickname, QString{});
-    WriteSetting(QStringLiteral("ip"), UISettings::values.ip, QString{});
-    WriteSetting(QStringLiteral("port"), UISettings::values.port, Network::DefaultRoomPort);
-    WriteSetting(QStringLiteral("room_nickname"), UISettings::values.room_nickname, QString{});
-    WriteSetting(QStringLiteral("room_name"), UISettings::values.room_name, QString{});
-    WriteSetting(QStringLiteral("room_port"), UISettings::values.room_port,
-                 QStringLiteral("24872"));
-    WriteSetting(QStringLiteral("host_type"), UISettings::values.host_type, 0);
-    WriteSetting(QStringLiteral("max_player"), UISettings::values.max_player, 8);
-    WriteSetting(QStringLiteral("game_id"), UISettings::values.game_id, 0);
-    WriteSetting(QStringLiteral("room_description"), UISettings::values.room_description,
-                 QString{});
-    // Write ban list
-    qt_config->beginWriteArray(QStringLiteral("username_ban_list"));
-    for (std::size_t i = 0; i < UISettings::values.ban_list.first.size(); ++i) {
-        qt_config->setArrayIndex(static_cast<int>(i));
-        WriteSetting(QStringLiteral("username"),
-                     QString::fromStdString(UISettings::values.ban_list.first[i]));
-    }
-    qt_config->endArray();
-    qt_config->beginWriteArray(QStringLiteral("ip_ban_list"));
-    for (std::size_t i = 0; i < UISettings::values.ban_list.second.size(); ++i) {
-        qt_config->setArrayIndex(static_cast<int>(i));
-        WriteSetting(QStringLiteral("ip"),
-                     QString::fromStdString(UISettings::values.ban_list.second[i]));
-    }
-    qt_config->endArray();
-
-    qt_config->endGroup();
-}
-
 void Config::SavePathValues() {
     qt_config->beginGroup(QStringLiteral("Paths"));
 
@@ -1490,6 +1452,40 @@ void Config::SaveWebServiceValues() {
     qt_config->endGroup();
 }
 
+void Config::SaveMultiplayerValues() {
+    qt_config->beginGroup(QStringLiteral("Multiplayer"));
+
+    WriteBasicSetting(UISettings::values.multiplayer_nickname);
+    WriteBasicSetting(UISettings::values.multiplayer_ip);
+    WriteBasicSetting(UISettings::values.multiplayer_port);
+    WriteBasicSetting(UISettings::values.multiplayer_room_nickname);
+    WriteBasicSetting(UISettings::values.multiplayer_room_name);
+    WriteBasicSetting(UISettings::values.multiplayer_room_port);
+    WriteBasicSetting(UISettings::values.multiplayer_host_type);
+    WriteBasicSetting(UISettings::values.multiplayer_port);
+    WriteBasicSetting(UISettings::values.multiplayer_max_player);
+    WriteBasicSetting(UISettings::values.multiplayer_game_id);
+    WriteBasicSetting(UISettings::values.multiplayer_room_description);
+
+    // Write ban list
+    qt_config->beginWriteArray(QStringLiteral("username_ban_list"));
+    for (std::size_t i = 0; i < UISettings::values.multiplayer_ban_list.first.size(); ++i) {
+        qt_config->setArrayIndex(static_cast<int>(i));
+        WriteSetting(QStringLiteral("username"),
+                     QString::fromStdString(UISettings::values.multiplayer_ban_list.first[i]));
+    }
+    qt_config->endArray();
+    qt_config->beginWriteArray(QStringLiteral("ip_ban_list"));
+    for (std::size_t i = 0; i < UISettings::values.multiplayer_ban_list.second.size(); ++i) {
+        qt_config->setArrayIndex(static_cast<int>(i));
+        WriteSetting(QStringLiteral("ip"),
+                     QString::fromStdString(UISettings::values.multiplayer_ban_list.second[i]));
+    }
+    qt_config->endArray();
+
+    qt_config->endGroup();
+}
+
 QVariant Config::ReadSetting(const QString& name) const {
     return qt_config->value(name);
 }
diff --git a/src/yuzu/multiplayer/chat_room.cpp b/src/yuzu/multiplayer/chat_room.cpp
index 6dd4bc36d6c4d974f2465f03800c02ca116b310c..7048ee1fceca24e034a47b1560b934371a047918 100644
--- a/src/yuzu/multiplayer/chat_room.cpp
+++ b/src/yuzu/multiplayer/chat_room.cpp
@@ -390,7 +390,7 @@ void ChatRoom::SetPlayerList(const Network::RoomMember::MemberList& member_list)
                             return;
                         QPixmap pixmap;
                         if (!pixmap.loadFromData(reinterpret_cast<const u8*>(result.data()),
-                                                 result.size()))
+                                                 static_cast<uint>(result.size())))
                             return;
                         icon_cache[avatar_url] =
                             pixmap.scaled(48, 48, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
diff --git a/src/yuzu/multiplayer/direct_connect.cpp b/src/yuzu/multiplayer/direct_connect.cpp
index 27741d657fc5b0ce815414fcc29b507cde7b4b1a..837baf85ccada87251b11a3383d3bf1d208a0826 100644
--- a/src/yuzu/multiplayer/direct_connect.cpp
+++ b/src/yuzu/multiplayer/direct_connect.cpp
@@ -32,15 +32,15 @@ DirectConnectWindow::DirectConnectWindow(QWidget* parent)
     connect(watcher, &QFutureWatcher<void>::finished, this, &DirectConnectWindow::OnConnection);
 
     ui->nickname->setValidator(validation.GetNickname());
-    ui->nickname->setText(UISettings::values.nickname);
+    ui->nickname->setText(UISettings::values.multiplayer_nickname.GetValue());
     if (ui->nickname->text().isEmpty() && !Settings::values.yuzu_username.GetValue().empty()) {
         // Use yuzu Web Service user name as nickname by default
         ui->nickname->setText(QString::fromStdString(Settings::values.yuzu_username.GetValue()));
     }
     ui->ip->setValidator(validation.GetIP());
-    ui->ip->setText(UISettings::values.ip);
+    ui->ip->setText(UISettings::values.multiplayer_ip.GetValue());
     ui->port->setValidator(validation.GetPort());
-    ui->port->setText(UISettings::values.port);
+    ui->port->setText(QString::number(UISettings::values.multiplayer_port.GetValue()));
 
     // TODO(jroweboy): Show or hide the connection options based on the current value of the combo
     // box. Add this back in when the traversal server support is added.
@@ -86,16 +86,18 @@ void DirectConnectWindow::Connect() {
     }
 
     // Store settings
-    UISettings::values.nickname = ui->nickname->text();
-    UISettings::values.ip = ui->ip->text();
-    UISettings::values.port = (ui->port->isModified() && !ui->port->text().isEmpty())
-                                  ? ui->port->text()
-                                  : UISettings::values.port;
+    UISettings::values.multiplayer_nickname = ui->nickname->text();
+    UISettings::values.multiplayer_ip = ui->ip->text();
+    if (ui->port->isModified() && !ui->port->text().isEmpty()) {
+        UISettings::values.multiplayer_port = ui->port->text().toInt();
+    } else {
+        UISettings::values.multiplayer_port = UISettings::values.multiplayer_port.GetDefault();
+    }
 
     // attempt to connect in a different thread
     QFuture<void> f = QtConcurrent::run([&] {
         if (auto room_member = Network::GetRoomMember().lock()) {
-            auto port = UISettings::values.port.toUInt();
+            auto port = UISettings::values.multiplayer_port.GetValue();
             room_member->Join(ui->nickname->text().toStdString(), "",
                               ui->ip->text().toStdString().c_str(), port, 0,
                               Network::NoPreferredMac, ui->password->text().toStdString().c_str());
diff --git a/src/yuzu/multiplayer/host_room.cpp b/src/yuzu/multiplayer/host_room.cpp
index 1b73e2bec556d0b7afc314e3db5668485b404c76..5470b8b86eb05d0e2510f3ad653daaf3c76f3067 100644
--- a/src/yuzu/multiplayer/host_room.cpp
+++ b/src/yuzu/multiplayer/host_room.cpp
@@ -51,23 +51,24 @@ HostRoomWindow::HostRoomWindow(QWidget* parent, QStandardItemModel* list,
     connect(ui->host, &QPushButton::clicked, this, &HostRoomWindow::Host);
 
     // Restore the settings:
-    ui->username->setText(UISettings::values.room_nickname);
+    ui->username->setText(UISettings::values.multiplayer_room_nickname.GetValue());
     if (ui->username->text().isEmpty() && !Settings::values.yuzu_username.GetValue().empty()) {
         // Use yuzu Web Service user name as nickname by default
         ui->username->setText(QString::fromStdString(Settings::values.yuzu_username.GetValue()));
     }
-    ui->room_name->setText(UISettings::values.room_name);
-    ui->port->setText(UISettings::values.room_port);
-    ui->max_player->setValue(UISettings::values.max_player);
-    int index = UISettings::values.host_type;
+    ui->room_name->setText(UISettings::values.multiplayer_room_name.GetValue());
+    ui->port->setText(QString::number(UISettings::values.multiplayer_room_port.GetValue()));
+    ui->max_player->setValue(UISettings::values.multiplayer_max_player.GetValue());
+    int index = UISettings::values.multiplayer_host_type.GetValue();
     if (index < ui->host_type->count()) {
         ui->host_type->setCurrentIndex(index);
     }
-    index = ui->game_list->findData(UISettings::values.game_id, GameListItemPath::ProgramIdRole);
+    index = ui->game_list->findData(UISettings::values.multiplayer_game_id.GetValue(),
+                                    GameListItemPath::ProgramIdRole);
     if (index != -1) {
         ui->game_list->setCurrentIndex(index);
     }
-    ui->room_description->setText(UISettings::values.room_description);
+    ui->room_description->setText(UISettings::values.multiplayer_room_description.GetValue());
 }
 
 HostRoomWindow::~HostRoomWindow() = default;
@@ -91,7 +92,8 @@ std::unique_ptr<Network::VerifyUser::Backend> HostRoomWindow::CreateVerifyBacken
     std::unique_ptr<Network::VerifyUser::Backend> verify_backend;
     if (use_validation) {
 #ifdef ENABLE_WEB_SERVICE
-        verify_backend = std::make_unique<WebService::VerifyUserJWT>(Settings::values.web_api_url);
+        verify_backend =
+            std::make_unique<WebService::VerifyUserJWT>(Settings::values.web_api_url.GetValue());
 #else
         verify_backend = std::make_unique<Network::VerifyUser::NullBackend>();
 #endif
@@ -137,7 +139,7 @@ void HostRoomWindow::Host() {
         const bool is_public = ui->host_type->currentIndex() == 0;
         Network::Room::BanList ban_list{};
         if (ui->load_ban_list->isChecked()) {
-            ban_list = UISettings::values.ban_list;
+            ban_list = UISettings::values.multiplayer_ban_list;
         }
         if (auto room = Network::GetRoom().lock()) {
             bool created = room->Create(
@@ -181,8 +183,9 @@ void HostRoomWindow::Host() {
         std::string token;
 #ifdef ENABLE_WEB_SERVICE
         if (is_public) {
-            WebService::Client client(Settings::values.web_api_url, Settings::values.yuzu_username,
-                                      Settings::values.yuzu_token);
+            WebService::Client client(Settings::values.web_api_url.GetValue(),
+                                      Settings::values.yuzu_username.GetValue(),
+                                      Settings::values.yuzu_token.GetValue());
             if (auto room = Network::GetRoom().lock()) {
                 token = client.GetExternalJWT(room->GetVerifyUID()).returned_data;
             }
@@ -198,17 +201,19 @@ void HostRoomWindow::Host() {
                      Network::NoPreferredMac, password, token);
 
         // Store settings
-        UISettings::values.room_nickname = ui->username->text();
-        UISettings::values.room_name = ui->room_name->text();
-        UISettings::values.game_id =
+        UISettings::values.multiplayer_room_nickname = ui->username->text();
+        UISettings::values.multiplayer_room_name = ui->room_name->text();
+        UISettings::values.multiplayer_game_id =
             ui->game_list->currentData(GameListItemPath::ProgramIdRole).toLongLong();
-        UISettings::values.max_player = ui->max_player->value();
+        UISettings::values.multiplayer_max_player = ui->max_player->value();
 
-        UISettings::values.host_type = ui->host_type->currentIndex();
-        UISettings::values.room_port = (ui->port->isModified() && !ui->port->text().isEmpty())
-                                           ? ui->port->text()
-                                           : QString::number(Network::DefaultRoomPort);
-        UISettings::values.room_description = ui->room_description->toPlainText();
+        UISettings::values.multiplayer_host_type = ui->host_type->currentIndex();
+        if (ui->port->isModified() && !ui->port->text().isEmpty()) {
+            UISettings::values.multiplayer_room_port = ui->port->text().toInt();
+        } else {
+            UISettings::values.multiplayer_room_port = Network::DefaultRoomPort;
+        }
+        UISettings::values.multiplayer_room_description = ui->room_description->toPlainText();
         ui->host->setEnabled(true);
         close();
     }
diff --git a/src/yuzu/multiplayer/lobby.cpp b/src/yuzu/multiplayer/lobby.cpp
index fcaa7b517ff8883bd71abed3e7a299d52e90f663..364b4605e658b9963811b289f1ea8c2bc90901c0 100644
--- a/src/yuzu/multiplayer/lobby.cpp
+++ b/src/yuzu/multiplayer/lobby.cpp
@@ -56,7 +56,7 @@ Lobby::Lobby(QWidget* parent, QStandardItemModel* list,
     ui->room_list->setContextMenuPolicy(Qt::CustomContextMenu);
 
     ui->nickname->setValidator(validation.GetNickname());
-    ui->nickname->setText(UISettings::values.nickname);
+    ui->nickname->setText(UISettings::values.multiplayer_nickname.GetValue());
     if (ui->nickname->text().isEmpty() && !Settings::values.yuzu_username.GetValue().empty()) {
         // Use yuzu Web Service user name as nickname by default
         ui->nickname->setText(QString::fromStdString(Settings::values.yuzu_username.GetValue()));
@@ -154,9 +154,11 @@ void Lobby::OnJoinRoom(const QModelIndex& source) {
     QFuture<void> f = QtConcurrent::run([nickname, ip, port, password, verify_UID] {
         std::string token;
 #ifdef ENABLE_WEB_SERVICE
-        if (!Settings::values.yuzu_username.empty() && !Settings::values.yuzu_token.empty()) {
-            WebService::Client client(Settings::values.web_api_url, Settings::values.yuzu_username,
-                                      Settings::values.yuzu_token);
+        if (!Settings::values.yuzu_username.GetValue().empty() &&
+            !Settings::values.yuzu_token.GetValue().empty()) {
+            WebService::Client client(Settings::values.web_api_url.GetValue(),
+                                      Settings::values.yuzu_username.GetValue(),
+                                      Settings::values.yuzu_token.GetValue());
             token = client.GetExternalJWT(verify_UID).returned_data;
             if (token.empty()) {
                 LOG_ERROR(WebService, "Could not get external JWT, verification may fail");
@@ -175,9 +177,11 @@ void Lobby::OnJoinRoom(const QModelIndex& source) {
     // TODO(jroweboy): disable widgets and display a connecting while we wait
 
     // Save settings
-    UISettings::values.nickname = ui->nickname->text();
-    UISettings::values.ip = proxy->data(connection_index, LobbyItemHost::HostIPRole).toString();
-    UISettings::values.port = proxy->data(connection_index, LobbyItemHost::HostPortRole).toString();
+    UISettings::values.multiplayer_nickname = ui->nickname->text();
+    UISettings::values.multiplayer_ip =
+        proxy->data(connection_index, LobbyItemHost::HostIPRole).toString();
+    UISettings::values.multiplayer_port =
+        proxy->data(connection_index, LobbyItemHost::HostPortRole).toInt();
 }
 
 void Lobby::ResetModel() {
diff --git a/src/yuzu/multiplayer/state.cpp b/src/yuzu/multiplayer/state.cpp
index e96b03e5df410cba1a8ee3ca0e687c30204e0b45..ee138739b2d768ec1511be7c66c9599c5d12f51c 100644
--- a/src/yuzu/multiplayer/state.cpp
+++ b/src/yuzu/multiplayer/state.cpp
@@ -232,7 +232,7 @@ bool MultiplayerState::OnCloseRoom() {
             return true;
         }
         // Save ban list
-        UISettings::values.ban_list = std::move(room->GetBanList());
+        UISettings::values.multiplayer_ban_list = std::move(room->GetBanList());
 
         room->Destroy();
         announce_multiplayer_session->Stop();
diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h
index aca1a28e1d319f03102dfe2d72eb613ec2a162ef..83a6cffa3e11602141854d51f535438d3090efe1 100644
--- a/src/yuzu/uisettings.h
+++ b/src/yuzu/uisettings.h
@@ -103,17 +103,17 @@ struct Values {
     Settings::Setting<uint32_t> callout_flags{0, "calloutFlags"};
 
     // multiplayer settings
-    QString nickname;
-    QString ip;
-    QString port;
-    QString room_nickname;
-    QString room_name;
-    quint32 max_player;
-    QString room_port;
-    uint host_type;
-    qulonglong game_id;
-    QString room_description;
-    std::pair<std::vector<std::string>, std::vector<std::string>> ban_list;
+    Settings::Setting<QString> multiplayer_nickname{QStringLiteral("yuzu"), "nickname"};
+    Settings::Setting<QString> multiplayer_ip{{}, "ip"};
+    Settings::SwitchableSetting<uint> multiplayer_port{24872, 0, 65535, "port"};
+    Settings::Setting<QString> multiplayer_room_nickname{{}, "room_nickname"};
+    Settings::Setting<QString> multiplayer_room_name{{}, "room_name"};
+    Settings::SwitchableSetting<uint> multiplayer_max_player{8, 0, 8, "max_player"};
+    Settings::SwitchableSetting<uint> multiplayer_room_port{24872, 0, 65535, "room_port"};
+    Settings::SwitchableSetting<uint> multiplayer_host_type{0, 0, 1, "host_type"};
+    Settings::Setting<qulonglong> multiplayer_game_id{{}, "game_id"};
+    Settings::Setting<QString> multiplayer_room_description{{}, "room_description"};
+    std::pair<std::vector<std::string>, std::vector<std::string>> multiplayer_ban_list;
 
     // logging
     Settings::Setting<bool> show_console{false, "showConsole"};