diff --git a/src/auth/models.cpp b/src/auth/models.cpp
index 8485685dc..90740a752 100644
--- a/src/auth/models.cpp
+++ b/src/auth/models.cpp
@@ -101,6 +101,35 @@ std::string PermissionLevelToString(PermissionLevel level) {
   }
 }
 
+FineGrainedPermission PermissionToFineGrainedPermission(const uint64_t permission) {
+  if (permission & FineGrainedPermission::CREATE_DELETE) {
+    return FineGrainedPermission::CREATE_DELETE;
+  }
+
+  if (permission & FineGrainedPermission::UPDATE) {
+    return FineGrainedPermission::UPDATE;
+  }
+
+  if (permission & FineGrainedPermission::READ) {
+    return FineGrainedPermission::READ;
+  }
+
+  return FineGrainedPermission::NO_PERMISSION;
+}
+
+std::string FineGrainedPermissionToString(const FineGrainedPermission level) {
+  switch (level) {
+    case FineGrainedPermission::CREATE_DELETE:
+      return "CREATE_DELETE";
+    case FineGrainedPermission::UPDATE:
+      return "UPDATE";
+    case FineGrainedPermission::READ:
+      return "READ";
+    case FineGrainedPermission::NO_PERMISSION:
+      return "NO_PERMISSION";
+  }
+}
+
 FineGrainedAccessPermissions Merge(const FineGrainedAccessPermissions &first,
                                    const FineGrainedAccessPermissions &second) {
   std::unordered_map<std::string, uint64_t> permissions{first.GetPermissions()};
@@ -370,6 +399,14 @@ Permissions &Role::permissions() { return permissions_; }
 const FineGrainedAccessHandler &Role::fine_grained_access_handler() const { return fine_grained_access_handler_; }
 FineGrainedAccessHandler &Role::fine_grained_access_handler() { return fine_grained_access_handler_; }
 
+const FineGrainedAccessPermissions &Role::GetFineGrainedAccessLabelPermissions() const {
+  return fine_grained_access_handler_.label_permissions();
+}
+
+const FineGrainedAccessPermissions &Role::GetFineGrainedAccessEdgeTypePermissions() const {
+  return fine_grained_access_handler_.edge_type_permissions();
+}
+
 nlohmann::json Role::Serialize() const {
   nlohmann::json data = nlohmann::json::object();
   data["rolename"] = rolename_;
diff --git a/src/auth/models.hpp b/src/auth/models.hpp
index 3a9ec3260..6de0b40fb 100644
--- a/src/auth/models.hpp
+++ b/src/auth/models.hpp
@@ -46,6 +46,7 @@ enum class Permission : uint64_t {
 
 // clang-format off
 enum class FineGrainedPermission : uint64_t {
+  NO_PERMISSION = 0,
   READ          = 1,
   UPDATE          = 1U << 1U,
   CREATE_DELETE = 1U << 2U
@@ -79,6 +80,12 @@ enum class PermissionLevel : uint8_t { GRANT, NEUTRAL, DENY };
 // Function that converts a permission level to its string representation.
 std::string PermissionLevelToString(PermissionLevel level);
 
+// Function that converts a label permission level to its string representation.
+std::string FineGrainedPermissionToString(FineGrainedPermission level);
+
+// Constructs a label permission from a permission
+FineGrainedPermission PermissionToFineGrainedPermission(uint64_t permission);
+
 class Permissions final {
  public:
   explicit Permissions(uint64_t grants = 0, uint64_t denies = 0);
@@ -205,6 +212,8 @@ class Role final {
   Permissions &permissions();
   const FineGrainedAccessHandler &fine_grained_access_handler() const;
   FineGrainedAccessHandler &fine_grained_access_handler();
+  const FineGrainedAccessPermissions &GetFineGrainedAccessLabelPermissions() const;
+  const FineGrainedAccessPermissions &GetFineGrainedAccessEdgeTypePermissions() const;
 
   nlohmann::json Serialize() const;
 
diff --git a/src/glue/CMakeLists.txt b/src/glue/CMakeLists.txt
index 835b7c08a..fa8a87997 100644
--- a/src/glue/CMakeLists.txt
+++ b/src/glue/CMakeLists.txt
@@ -1,4 +1,4 @@
-set(mg_glue_sources auth.cpp auth_checker.cpp communication.cpp)
+set(mg_glue_sources auth.cpp auth_checker.cpp auth_handler.cpp communication.cpp)
 
 add_library(mg-glue STATIC ${mg_glue_sources})
 target_link_libraries(mg-glue mg-query mg-auth)
diff --git a/src/glue/auth_handler.cpp b/src/glue/auth_handler.cpp
new file mode 100644
index 000000000..aaed51c66
--- /dev/null
+++ b/src/glue/auth_handler.cpp
@@ -0,0 +1,587 @@
+// Copyright 2022 Memgraph Ltd.
+//
+// Use of this software is governed by the Business Source License
+// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
+// License, and you may not use this file except in compliance with the Business Source License.
+//
+// As of the Change Date specified in that file, in accordance with
+// the Business Source License, use of this software will be governed
+// by the Apache License, Version 2.0, included in the file
+// licenses/APL.txt.
+
+#include "glue/auth_handler.hpp"
+
+#include <sstream>
+
+#include <fmt/format.h>
+
+#include "auth/models.hpp"
+#include "glue/auth.hpp"
+
+namespace {
+
+struct PermissionForPrivilegeResult {
+  std::string permission;
+  memgraph::auth::PermissionLevel permission_level;
+  std::string description;
+};
+
+struct FineGrainedPermissionForPrivilegeResult {
+  std::string permission;
+  memgraph::auth::FineGrainedPermission permission_level;
+  std::string description;
+};
+
+PermissionForPrivilegeResult GetPermissionForPrivilegeForUserOrRole(
+    const memgraph::auth::Permissions &permissions, const memgraph::query::AuthQuery::Privilege &privilege,
+    const std::string &user_or_role) {
+  PermissionForPrivilegeResult container;
+
+  const auto permission = memgraph::glue::PrivilegeToPermission(privilege);
+  container.permission = memgraph::auth::PermissionToString(permission);
+  container.permission_level = permissions.Has(permission);
+
+  switch (container.permission_level) {
+    case memgraph::auth::PermissionLevel::GRANT:
+      container.description = "GRANTED TO " + user_or_role;
+      break;
+    case memgraph::auth::PermissionLevel::DENY:
+      container.description = "DENIED TO " + user_or_role;
+      break;
+    case memgraph::auth::PermissionLevel::NEUTRAL:
+      break;
+  }
+
+  return container;
+}
+
+std::vector<std::vector<memgraph::query::TypedValue>> ConstructPrivilegesResult(
+    const std::vector<PermissionForPrivilegeResult> &privileges) {
+  std::vector<std::vector<memgraph::query::TypedValue>> grants;
+
+  grants.reserve(privileges.size());
+  for (const auto &permission : privileges) {
+    grants.push_back({memgraph::query::TypedValue(permission.permission),
+                      memgraph::query::TypedValue(memgraph::auth::PermissionLevelToString(permission.permission_level)),
+                      memgraph::query::TypedValue(permission.description)});
+  }
+
+  return grants;
+}
+
+std::vector<std::vector<memgraph::query::TypedValue>> ShowUserPrivileges(
+    const std::optional<memgraph::auth::User> &user) {
+  std::vector<PermissionForPrivilegeResult> privilege_results;
+
+  const auto &permissions = user->GetPermissions();
+  const auto &user_level_permissions = user->permissions();
+
+  for (const auto &privilege : memgraph::query::kPrivilegesAll) {
+    auto user_permission_result = GetPermissionForPrivilegeForUserOrRole(permissions, privilege, "USER");
+    auto user_only_permissions_result =
+        GetPermissionForPrivilegeForUserOrRole(user_level_permissions, privilege, "USER");
+
+    if (user_permission_result.permission_level != memgraph::auth::PermissionLevel::NEUTRAL) {
+      std::vector<std::string> full_description;
+      if (user_only_permissions_result.permission_level != memgraph::auth::PermissionLevel::NEUTRAL) {
+        full_description.emplace_back(user_only_permissions_result.description);
+      }
+
+      if (const auto *role = user->role(); role != nullptr) {
+        auto role_permission_result = GetPermissionForPrivilegeForUserOrRole(role->permissions(), privilege, "ROLE");
+        if (role_permission_result.permission_level != memgraph::auth::PermissionLevel::NEUTRAL) {
+          full_description.emplace_back(role_permission_result.description);
+        }
+      }
+
+      privilege_results.push_back(PermissionForPrivilegeResult{user_permission_result.permission,
+                                                               user_permission_result.permission_level,
+                                                               memgraph::utils::Join(full_description, ", ")});
+    }
+  }
+
+  return ConstructPrivilegesResult(privilege_results);
+}
+
+std::vector<std::vector<memgraph::query::TypedValue>> ShowRolePrivileges(
+    const std::optional<memgraph::auth::Role> &role) {
+  std::vector<PermissionForPrivilegeResult> privilege_results;
+  const auto &permissions = role->permissions();
+  for (const auto &privilege : memgraph::query::kPrivilegesAll) {
+    auto role_permission_result = GetPermissionForPrivilegeForUserOrRole(permissions, privilege, "ROLE");
+    if (role_permission_result.permission_level != memgraph::auth::PermissionLevel::NEUTRAL) {
+      privilege_results.push_back(role_permission_result);
+    }
+  }
+
+  return ConstructPrivilegesResult(privilege_results);
+}
+
+std::vector<FineGrainedPermissionForPrivilegeResult> GetFineGrainedPermissionForPrivilegeForUserOrRole(
+    const memgraph::auth::FineGrainedAccessPermissions &permissions, const std::string &permission_type,
+    const std::string &user_or_role) {
+  std::vector<FineGrainedPermissionForPrivilegeResult> fine_grained_permissions;
+  const auto global_permission = permissions.GetGlobalPermission();
+  if (global_permission.has_value()) {
+    const auto &permission_level = memgraph::auth::PermissionToFineGrainedPermission(global_permission.value());
+
+    std::stringstream permission_representation;
+    permission_representation << "ALL " << permission_type << "S";
+    const auto &permission_level_representation =
+        permission_level == memgraph::auth::FineGrainedPermission::NO_PERMISSION ? "DENIED" : "GRANTED";
+
+    const auto permission_description =
+        fmt::format("GLOBAL {0} PERMISSION {1} TO {2}", permission_type, permission_level_representation, user_or_role);
+
+    fine_grained_permissions.push_back(FineGrainedPermissionForPrivilegeResult{
+        permission_representation.str(), permission_level, permission_description});
+  }
+
+  for (const auto &[label, permission] : permissions.GetPermissions()) {
+    auto permission_level = memgraph::auth::PermissionToFineGrainedPermission(permission);
+
+    std::stringstream permission_representation;
+    permission_representation << permission_type << " :" << label;
+
+    const auto &permission_level_representation =
+        permission_level == memgraph::auth::FineGrainedPermission::NO_PERMISSION ? "DENIED" : "GRANTED";
+
+    const auto permission_description =
+        fmt::format("{0} PERMISSION {1} TO {2}", permission_type, permission_level_representation, user_or_role);
+
+    fine_grained_permissions.push_back(FineGrainedPermissionForPrivilegeResult{
+        permission_representation.str(), permission_level, permission_description});
+  }
+
+  return fine_grained_permissions;
+}
+
+std::vector<std::vector<memgraph::query::TypedValue>> ConstructFineGrainedPrivilegesResult(
+    const std::vector<FineGrainedPermissionForPrivilegeResult> &privileges) {
+  std::vector<std::vector<memgraph::query::TypedValue>> grants;
+
+  grants.reserve(privileges.size());
+  for (const auto &permission : privileges) {
+    grants.push_back(
+        {memgraph::query::TypedValue(permission.permission),
+         memgraph::query::TypedValue(memgraph::auth::FineGrainedPermissionToString(permission.permission_level)),
+         memgraph::query::TypedValue(permission.description)});
+  }
+
+  return grants;
+}
+
+std::vector<std::vector<memgraph::query::TypedValue>> ShowFineGrainedUserPrivileges(
+    const std::optional<memgraph::auth::User> &user) {
+  const auto &label_permissions = user->GetFineGrainedAccessLabelPermissions();
+  const auto &edge_type_permissions = user->GetFineGrainedAccessEdgeTypePermissions();
+
+  auto all_fine_grained_permissions =
+      GetFineGrainedPermissionForPrivilegeForUserOrRole(label_permissions, "LABEL", "USER");
+  auto edge_type_fine_grained_permissions =
+      GetFineGrainedPermissionForPrivilegeForUserOrRole(edge_type_permissions, "EDGE_TYPE", "USER");
+
+  all_fine_grained_permissions.insert(all_fine_grained_permissions.end(), edge_type_fine_grained_permissions.begin(),
+                                      edge_type_fine_grained_permissions.end());
+
+  return ConstructFineGrainedPrivilegesResult(all_fine_grained_permissions);
+}
+
+std::vector<std::vector<memgraph::query::TypedValue>> ShowFineGrainedRolePrivileges(
+    const std::optional<memgraph::auth::Role> &role) {
+  const auto &label_permissions = role->GetFineGrainedAccessLabelPermissions();
+  const auto &edge_type_permissions = role->GetFineGrainedAccessEdgeTypePermissions();
+
+  auto all_fine_grained_permissions =
+      GetFineGrainedPermissionForPrivilegeForUserOrRole(label_permissions, "LABEL", "USER");
+  auto edge_type_fine_grained_permissions =
+      GetFineGrainedPermissionForPrivilegeForUserOrRole(edge_type_permissions, "EDGE_TYPE", "USER");
+
+  all_fine_grained_permissions.insert(all_fine_grained_permissions.end(), edge_type_fine_grained_permissions.begin(),
+                                      edge_type_fine_grained_permissions.end());
+
+  return ConstructFineGrainedPrivilegesResult(all_fine_grained_permissions);
+}
+}  // namespace
+
+namespace memgraph::glue {
+
+AuthQueryHandler::AuthQueryHandler(
+    memgraph::utils::Synchronized<memgraph::auth::Auth, memgraph::utils::WritePrioritizedRWLock> *auth,
+    std::string name_regex_string)
+    : auth_(auth), name_regex_string_(std::move(name_regex_string)), name_regex_(name_regex_string_) {}
+
+bool AuthQueryHandler::CreateUser(const std::string &username, const std::optional<std::string> &password) {
+  if (name_regex_string_ != kDefaultUserRoleRegex) {
+    if (const auto license_check_result =
+            memgraph::utils::license::global_license_checker.IsValidLicense(memgraph::utils::global_settings);
+        license_check_result.HasError()) {
+      throw memgraph::auth::AuthException(
+          "Custom user/role regex is a Memgraph Enterprise feature. Please set the config "
+          "(\"--auth-user-or-role-name-regex\") to its default value (\"{}\") or remove the flag.\n{}",
+          kDefaultUserRoleRegex,
+          memgraph::utils::license::LicenseCheckErrorToString(license_check_result.GetError(), "user/role regex"));
+    }
+  }
+  if (!std::regex_match(username, name_regex_)) {
+    throw query::QueryRuntimeException("Invalid user name.");
+  }
+  try {
+    const auto [first_user, user_added] = std::invoke([&, this] {
+      auto locked_auth = auth_->Lock();
+      const auto first_user = !locked_auth->HasUsers();
+      const auto user_added = locked_auth->AddUser(username, password).has_value();
+      return std::make_pair(first_user, user_added);
+    });
+
+    if (first_user) {
+      spdlog::info("{} is first created user. Granting all privileges.", username);
+      GrantPrivilege(
+          username, memgraph::query::kPrivilegesAll,
+          {{{memgraph::query::AuthQuery::FineGrainedPrivilege::CREATE_DELETE, {memgraph::auth::kAsterisk}}}},
+          {{{memgraph::query::AuthQuery::FineGrainedPrivilege::CREATE_DELETE, {memgraph::auth::kAsterisk}}}});
+    }
+
+    return user_added;
+  } catch (const memgraph::auth::AuthException &e) {
+    throw memgraph::query::QueryRuntimeException(e.what());
+  }
+}
+
+bool AuthQueryHandler::DropUser(const std::string &username) {
+  if (!std::regex_match(username, name_regex_)) {
+    throw memgraph::query::QueryRuntimeException("Invalid user name.");
+  }
+  try {
+    auto locked_auth = auth_->Lock();
+    auto user = locked_auth->GetUser(username);
+    if (!user) return false;
+    return locked_auth->RemoveUser(username);
+  } catch (const memgraph::auth::AuthException &e) {
+    throw memgraph::query::QueryRuntimeException(e.what());
+  }
+}
+
+void AuthQueryHandler::SetPassword(const std::string &username, const std::optional<std::string> &password) {
+  if (!std::regex_match(username, name_regex_)) {
+    throw memgraph::query::QueryRuntimeException("Invalid user name.");
+  }
+  try {
+    auto locked_auth = auth_->Lock();
+    auto user = locked_auth->GetUser(username);
+    if (!user) {
+      throw memgraph::query::QueryRuntimeException("User '{}' doesn't exist.", username);
+    }
+    user->UpdatePassword(password);
+    locked_auth->SaveUser(*user);
+  } catch (const memgraph::auth::AuthException &e) {
+    throw memgraph::query::QueryRuntimeException(e.what());
+  }
+}
+
+bool AuthQueryHandler::CreateRole(const std::string &rolename) {
+  if (!std::regex_match(rolename, name_regex_)) {
+    throw memgraph::query::QueryRuntimeException("Invalid role name.");
+  }
+  try {
+    auto locked_auth = auth_->Lock();
+    return locked_auth->AddRole(rolename).has_value();
+  } catch (const memgraph::auth::AuthException &e) {
+    throw memgraph::query::QueryRuntimeException(e.what());
+  }
+}
+
+bool AuthQueryHandler::DropRole(const std::string &rolename) {
+  if (!std::regex_match(rolename, name_regex_)) {
+    throw memgraph::query::QueryRuntimeException("Invalid role name.");
+  }
+  try {
+    auto locked_auth = auth_->Lock();
+    auto role = locked_auth->GetRole(rolename);
+
+    if (!role) {
+      return false;
+    };
+
+    return locked_auth->RemoveRole(rolename);
+  } catch (const memgraph::auth::AuthException &e) {
+    throw memgraph::query::QueryRuntimeException(e.what());
+  }
+}
+
+std::vector<memgraph::query::TypedValue> AuthQueryHandler::GetUsernames() {
+  try {
+    auto locked_auth = auth_->ReadLock();
+    std::vector<memgraph::query::TypedValue> usernames;
+    const auto &users = locked_auth->AllUsers();
+    usernames.reserve(users.size());
+    for (const auto &user : users) {
+      usernames.emplace_back(user.username());
+    }
+    return usernames;
+  } catch (const memgraph::auth::AuthException &e) {
+    throw memgraph::query::QueryRuntimeException(e.what());
+  }
+}
+
+std::vector<memgraph::query::TypedValue> AuthQueryHandler::GetRolenames() {
+  try {
+    auto locked_auth = auth_->ReadLock();
+    std::vector<memgraph::query::TypedValue> rolenames;
+    const auto &roles = locked_auth->AllRoles();
+    rolenames.reserve(roles.size());
+    for (const auto &role : roles) {
+      rolenames.emplace_back(role.rolename());
+    }
+    return rolenames;
+  } catch (const memgraph::auth::AuthException &e) {
+    throw memgraph::query::QueryRuntimeException(e.what());
+  }
+}
+
+std::optional<std::string> AuthQueryHandler::GetRolenameForUser(const std::string &username) {
+  if (!std::regex_match(username, name_regex_)) {
+    throw memgraph::query::QueryRuntimeException("Invalid user name.");
+  }
+  try {
+    auto locked_auth = auth_->ReadLock();
+    auto user = locked_auth->GetUser(username);
+    if (!user) {
+      throw memgraph::query::QueryRuntimeException("User '{}' doesn't exist .", username);
+    }
+
+    if (const auto *role = user->role(); role != nullptr) {
+      return role->rolename();
+    }
+    return std::nullopt;
+  } catch (const memgraph::auth::AuthException &e) {
+    throw memgraph::query::QueryRuntimeException(e.what());
+  }
+}
+
+std::vector<memgraph::query::TypedValue> AuthQueryHandler::GetUsernamesForRole(const std::string &rolename) {
+  if (!std::regex_match(rolename, name_regex_)) {
+    throw memgraph::query::QueryRuntimeException("Invalid role name.");
+  }
+  try {
+    auto locked_auth = auth_->ReadLock();
+    auto role = locked_auth->GetRole(rolename);
+    if (!role) {
+      throw memgraph::query::QueryRuntimeException("Role '{}' doesn't exist.", rolename);
+    }
+    std::vector<memgraph::query::TypedValue> usernames;
+    const auto &users = locked_auth->AllUsersForRole(rolename);
+    usernames.reserve(users.size());
+    for (const auto &user : users) {
+      usernames.emplace_back(user.username());
+    }
+    return usernames;
+  } catch (const memgraph::auth::AuthException &e) {
+    throw memgraph::query::QueryRuntimeException(e.what());
+  }
+}
+
+void AuthQueryHandler::SetRole(const std::string &username, const std::string &rolename) {
+  if (!std::regex_match(username, name_regex_)) {
+    throw memgraph::query::QueryRuntimeException("Invalid user name.");
+  }
+  if (!std::regex_match(rolename, name_regex_)) {
+    throw memgraph::query::QueryRuntimeException("Invalid role name.");
+  }
+  try {
+    auto locked_auth = auth_->Lock();
+    auto user = locked_auth->GetUser(username);
+    if (!user) {
+      throw memgraph::query::QueryRuntimeException("User '{}' doesn't exist .", username);
+    }
+    auto role = locked_auth->GetRole(rolename);
+    if (!role) {
+      throw memgraph::query::QueryRuntimeException("Role '{}' doesn't exist .", rolename);
+    }
+    if (const auto *current_role = user->role(); current_role != nullptr) {
+      throw memgraph::query::QueryRuntimeException("User '{}' is already a member of role '{}'.", username,
+                                                   current_role->rolename());
+    }
+    user->SetRole(*role);
+    locked_auth->SaveUser(*user);
+  } catch (const memgraph::auth::AuthException &e) {
+    throw memgraph::query::QueryRuntimeException(e.what());
+  }
+}
+
+void AuthQueryHandler::ClearRole(const std::string &username) {
+  if (!std::regex_match(username, name_regex_)) {
+    throw memgraph::query::QueryRuntimeException("Invalid user name.");
+  }
+  try {
+    auto locked_auth = auth_->Lock();
+    auto user = locked_auth->GetUser(username);
+    if (!user) {
+      throw memgraph::query::QueryRuntimeException("User '{}' doesn't exist .", username);
+    }
+    user->ClearRole();
+    locked_auth->SaveUser(*user);
+  } catch (const memgraph::auth::AuthException &e) {
+    throw memgraph::query::QueryRuntimeException(e.what());
+  }
+}
+
+std::vector<std::vector<memgraph::query::TypedValue>> AuthQueryHandler::GetPrivileges(const std::string &user_or_role) {
+  if (!std::regex_match(user_or_role, name_regex_)) {
+    throw memgraph::query::QueryRuntimeException("Invalid user or role name.");
+  }
+  try {
+    auto locked_auth = auth_->ReadLock();
+    std::vector<std::vector<memgraph::query::TypedValue>> grants;
+    std::vector<std::vector<memgraph::query::TypedValue>> fine_grained_grants;
+    auto user = locked_auth->GetUser(user_or_role);
+    auto role = locked_auth->GetRole(user_or_role);
+    if (!user && !role) {
+      throw memgraph::query::QueryRuntimeException("User or role '{}' doesn't exist.", user_or_role);
+    }
+
+    if (user) {
+      grants = ShowUserPrivileges(user);
+      fine_grained_grants = ShowFineGrainedUserPrivileges(user);
+    } else {
+      grants = ShowRolePrivileges(role);
+      fine_grained_grants = ShowFineGrainedRolePrivileges(role);
+    }
+
+    grants.insert(grants.end(), fine_grained_grants.begin(), fine_grained_grants.end());
+
+    return grants;
+  } catch (const memgraph::auth::AuthException &e) {
+    throw memgraph::query::QueryRuntimeException(e.what());
+  }
+}
+
+void AuthQueryHandler::GrantPrivilege(
+    const std::string &user_or_role, const std::vector<memgraph::query::AuthQuery::Privilege> &privileges,
+    const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
+        &label_privileges,
+    const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
+        &edge_type_privileges) {
+  EditPermissions(
+      user_or_role, privileges, label_privileges, edge_type_privileges,
+      [](auto &permissions, const auto &permission) {
+        // TODO (mferencevic): should we first check that the
+        // privilege is granted/denied/revoked before
+        // unconditionally granting/denying/revoking it?
+        permissions.Grant(permission);
+      },
+      [](auto &fine_grained_permissions, const auto &privilege_collection) {
+        for (const auto &[privilege, entities] : privilege_collection) {
+          const auto &permission = memgraph::glue::FineGrainedPrivilegeToFineGrainedPermission(privilege);
+          for (const auto &entity : entities) {
+            fine_grained_permissions.Grant(entity, permission);
+          }
+        }
+      });
+}
+
+void AuthQueryHandler::DenyPrivilege(
+    const std::string &user_or_role, const std::vector<memgraph::query::AuthQuery::Privilege> &privileges,
+    const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
+        &label_privileges,
+    const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
+        &edge_type_privileges) {
+  EditPermissions(
+      user_or_role, privileges, label_privileges, edge_type_privileges,
+      [](auto &permissions, const auto &permission) {
+        // TODO (mferencevic): should we first check that the
+        // privilege is granted/denied/revoked before
+        // unconditionally granting/denying/revoking it?
+        permissions.Deny(permission);
+      },
+      [](auto &fine_grained_permissions, const auto &privilege_collection) {
+        for (const auto &[privilege, entities] : privilege_collection) {
+          const auto &permission = memgraph::glue::FineGrainedPrivilegeToFineGrainedPermission(privilege);
+          for (const auto &entity : entities) {
+            fine_grained_permissions.Deny(entity, permission);
+          }
+        }
+      });
+}
+
+void AuthQueryHandler::RevokePrivilege(
+    const std::string &user_or_role, const std::vector<memgraph::query::AuthQuery::Privilege> &privileges,
+    const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
+        &label_privileges,
+    const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
+        &edge_type_privileges) {
+  EditPermissions(
+      user_or_role, privileges, label_privileges, edge_type_privileges,
+      [](auto &permissions, const auto &permission) {
+        // TODO (mferencevic): should we first check that the
+        // privilege is granted/denied/revoked before
+        // unconditionally granting/denying/revoking it?
+        permissions.Revoke(permission);
+      },
+      [](auto &fine_grained_permissions, const auto &privilege_collection) {
+        for ([[maybe_unused]] const auto &[privilege, entities] : privilege_collection) {
+          for (const auto &entity : entities) {
+            fine_grained_permissions.Revoke(entity);
+          }
+        }
+      });
+}
+
+template <class TEditPermissionsFun, class TEditFineGrainedPermissionsFun>
+void AuthQueryHandler::EditPermissions(
+    const std::string &user_or_role, const std::vector<memgraph::query::AuthQuery::Privilege> &privileges,
+    const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
+        &label_privileges,
+    const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
+        &edge_type_privileges,
+    const TEditPermissionsFun &edit_permissions_fun,
+    const TEditFineGrainedPermissionsFun &edit_fine_grained_permissions_fun) {
+  if (!std::regex_match(user_or_role, name_regex_)) {
+    throw memgraph::query::QueryRuntimeException("Invalid user or role name.");
+  }
+  try {
+    std::vector<memgraph::auth::Permission> permissions;
+    permissions.reserve(privileges.size());
+    for (const auto &privilege : privileges) {
+      permissions.push_back(memgraph::glue::PrivilegeToPermission(privilege));
+    }
+    auto locked_auth = auth_->Lock();
+    auto user = locked_auth->GetUser(user_or_role);
+    auto role = locked_auth->GetRole(user_or_role);
+    if (!user && !role) {
+      throw memgraph::query::QueryRuntimeException("User or role '{}' doesn't exist.", user_or_role);
+    }
+    if (user) {
+      for (const auto &permission : permissions) {
+        edit_permissions_fun(user->permissions(), permission);
+      }
+      for (const auto &label_privilege_collection : label_privileges) {
+        edit_fine_grained_permissions_fun(user->fine_grained_access_handler().label_permissions(),
+                                          label_privilege_collection);
+      }
+      for (const auto &edge_type_privilege_collection : edge_type_privileges) {
+        edit_fine_grained_permissions_fun(user->fine_grained_access_handler().edge_type_permissions(),
+                                          edge_type_privilege_collection);
+      }
+
+      locked_auth->SaveUser(*user);
+    } else {
+      for (const auto &permission : permissions) {
+        edit_permissions_fun(role->permissions(), permission);
+      }
+      for (const auto &label_privilege : label_privileges) {
+        edit_fine_grained_permissions_fun(user->fine_grained_access_handler().label_permissions(), label_privilege);
+      }
+      for (const auto &edge_type_privilege : edge_type_privileges) {
+        edit_fine_grained_permissions_fun(role->fine_grained_access_handler().edge_type_permissions(),
+                                          edge_type_privilege);
+      }
+
+      locked_auth->SaveRole(*role);
+    }
+  } catch (const memgraph::auth::AuthException &e) {
+    throw memgraph::query::QueryRuntimeException(e.what());
+  }
+}
+
+}  // namespace memgraph::glue
diff --git a/src/glue/auth_handler.hpp b/src/glue/auth_handler.hpp
new file mode 100644
index 000000000..976ffb6e9
--- /dev/null
+++ b/src/glue/auth_handler.hpp
@@ -0,0 +1,91 @@
+// Copyright 2022 Memgraph Ltd.
+//
+// Use of this software is governed by the Business Source License
+// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
+// License, and you may not use this file except in compliance with the Business Source License.
+//
+// As of the Change Date specified in that file, in accordance with
+// the Business Source License, use of this software will be governed
+// by the Apache License, Version 2.0, included in the file
+// licenses/APL.txt.
+
+#pragma once
+
+#include <regex>
+
+#include "auth/auth.hpp"
+#include "glue/auth.hpp"
+#include "query/interpreter.hpp"
+#include "utils/license.hpp"
+#include "utils/string.hpp"
+
+namespace memgraph::glue {
+
+inline constexpr std::string_view kDefaultUserRoleRegex = "[a-zA-Z0-9_.+-@]+";
+
+class AuthQueryHandler final : public memgraph::query::AuthQueryHandler {
+  memgraph::utils::Synchronized<memgraph::auth::Auth, memgraph::utils::WritePrioritizedRWLock> *auth_;
+  std::string name_regex_string_;
+  std::regex name_regex_;
+
+ public:
+  AuthQueryHandler(memgraph::utils::Synchronized<memgraph::auth::Auth, memgraph::utils::WritePrioritizedRWLock> *auth,
+                   std::string name_regex_string);
+
+  bool CreateUser(const std::string &username, const std::optional<std::string> &password) override;
+
+  bool DropUser(const std::string &username) override;
+
+  void SetPassword(const std::string &username, const std::optional<std::string> &password) override;
+
+  bool CreateRole(const std::string &rolename) override;
+
+  bool DropRole(const std::string &rolename) override;
+
+  std::vector<memgraph::query::TypedValue> GetUsernames() override;
+
+  std::vector<memgraph::query::TypedValue> GetRolenames() override;
+
+  std::optional<std::string> GetRolenameForUser(const std::string &username) override;
+
+  std::vector<memgraph::query::TypedValue> GetUsernamesForRole(const std::string &rolename) override;
+
+  void SetRole(const std::string &username, const std::string &rolename) override;
+
+  void ClearRole(const std::string &username) override;
+
+  std::vector<std::vector<memgraph::query::TypedValue>> GetPrivileges(const std::string &user_or_role) override;
+
+  void GrantPrivilege(
+      const std::string &user_or_role, const std::vector<memgraph::query::AuthQuery::Privilege> &privileges,
+      const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
+          &label_privileges,
+      const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
+          &edge_type_privileges) override;
+
+  void DenyPrivilege(
+      const std::string &user_or_role, const std::vector<memgraph::query::AuthQuery::Privilege> &privileges,
+      const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
+          &label_privileges,
+      const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
+          &edge_type_privileges) override;
+
+  void RevokePrivilege(
+      const std::string &user_or_role, const std::vector<memgraph::query::AuthQuery::Privilege> &privileges,
+      const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
+          &label_privileges,
+      const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
+          &edge_type_privileges) override;
+
+ private:
+  template <class TEditPermissionsFun, class TEditFineGrainedPermissionsFun>
+  void EditPermissions(
+      const std::string &user_or_role, const std::vector<memgraph::query::AuthQuery::Privilege> &privileges,
+      const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
+          &label_privileges,
+      const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
+          &edge_type_privileges,
+      const TEditPermissionsFun &edit_permissions_fun,
+      const TEditFineGrainedPermissionsFun &edit_fine_grained_permissions_fun);
+};
+}  // namespace memgraph::glue
diff --git a/src/memgraph.cpp b/src/memgraph.cpp
index b5ceff715..bf635e531 100644
--- a/src/memgraph.cpp
+++ b/src/memgraph.cpp
@@ -38,6 +38,7 @@
 #include "communication/websocket/auth.hpp"
 #include "communication/websocket/server.hpp"
 #include "glue/auth_checker.hpp"
+#include "glue/auth_handler.hpp"
 #include "helpers.hpp"
 #include "py/py.hpp"
 #include "query/auth_checker.hpp"
@@ -469,424 +470,10 @@ struct SessionData {
 #endif
 };
 
-inline constexpr std::string_view default_user_role_regex = "[a-zA-Z0-9_.+-@]+";
 // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
-DEFINE_string(auth_user_or_role_name_regex, default_user_role_regex.data(),
+DEFINE_string(auth_user_or_role_name_regex, memgraph::glue::kDefaultUserRoleRegex.data(),
               "Set to the regular expression that each user or role name must fulfill.");
 
-class AuthQueryHandler final : public memgraph::query::AuthQueryHandler {
-  memgraph::utils::Synchronized<memgraph::auth::Auth, memgraph::utils::WritePrioritizedRWLock> *auth_;
-  std::string name_regex_string_;
-  std::regex name_regex_;
-
- public:
-  AuthQueryHandler(memgraph::utils::Synchronized<memgraph::auth::Auth, memgraph::utils::WritePrioritizedRWLock> *auth,
-                   std::string name_regex_string)
-      : auth_(auth), name_regex_string_(std::move(name_regex_string)), name_regex_(name_regex_string_) {}
-
-  bool CreateUser(const std::string &username, const std::optional<std::string> &password) override {
-    if (name_regex_string_ != default_user_role_regex) {
-      if (const auto license_check_result =
-              memgraph::utils::license::global_license_checker.IsValidLicense(memgraph::utils::global_settings);
-          license_check_result.HasError()) {
-        throw memgraph::auth::AuthException(
-            "Custom user/role regex is a Memgraph Enterprise feature. Please set the config "
-            "(\"--auth-user-or-role-name-regex\") to its default value (\"{}\") or remove the flag.\n{}",
-            default_user_role_regex,
-            memgraph::utils::license::LicenseCheckErrorToString(license_check_result.GetError(), "user/role regex"));
-      }
-    }
-    if (!std::regex_match(username, name_regex_)) {
-      throw memgraph::query::QueryRuntimeException("Invalid user name.");
-    }
-    try {
-      const auto [first_user, user_added] = std::invoke([&, this] {
-        auto locked_auth = auth_->Lock();
-        const auto first_user = !locked_auth->HasUsers();
-        const auto user_added = locked_auth->AddUser(username, password).has_value();
-        return std::make_pair(first_user, user_added);
-      });
-
-      if (first_user) {
-        spdlog::info("{} is first created user. Granting all privileges.", username);
-        GrantPrivilege(
-            username, memgraph::query::kPrivilegesAll,
-            {{{memgraph::query::AuthQuery::FineGrainedPrivilege::CREATE_DELETE, {memgraph::auth::kAsterisk}}}},
-            {{{memgraph::query::AuthQuery::FineGrainedPrivilege::CREATE_DELETE, {memgraph::auth::kAsterisk}}}});
-      }
-
-      return user_added;
-    } catch (const memgraph::auth::AuthException &e) {
-      throw memgraph::query::QueryRuntimeException(e.what());
-    }
-  }
-
-  bool DropUser(const std::string &username) override {
-    if (!std::regex_match(username, name_regex_)) {
-      throw memgraph::query::QueryRuntimeException("Invalid user name.");
-    }
-    try {
-      auto locked_auth = auth_->Lock();
-      auto user = locked_auth->GetUser(username);
-      if (!user) return false;
-      return locked_auth->RemoveUser(username);
-    } catch (const memgraph::auth::AuthException &e) {
-      throw memgraph::query::QueryRuntimeException(e.what());
-    }
-  }
-
-  void SetPassword(const std::string &username, const std::optional<std::string> &password) override {
-    if (!std::regex_match(username, name_regex_)) {
-      throw memgraph::query::QueryRuntimeException("Invalid user name.");
-    }
-    try {
-      auto locked_auth = auth_->Lock();
-      auto user = locked_auth->GetUser(username);
-      if (!user) {
-        throw memgraph::query::QueryRuntimeException("User '{}' doesn't exist.", username);
-      }
-      user->UpdatePassword(password);
-      locked_auth->SaveUser(*user);
-    } catch (const memgraph::auth::AuthException &e) {
-      throw memgraph::query::QueryRuntimeException(e.what());
-    }
-  }
-
-  bool CreateRole(const std::string &rolename) override {
-    if (!std::regex_match(rolename, name_regex_)) {
-      throw memgraph::query::QueryRuntimeException("Invalid role name.");
-    }
-    try {
-      auto locked_auth = auth_->Lock();
-      return locked_auth->AddRole(rolename).has_value();
-    } catch (const memgraph::auth::AuthException &e) {
-      throw memgraph::query::QueryRuntimeException(e.what());
-    }
-  }
-
-  bool DropRole(const std::string &rolename) override {
-    if (!std::regex_match(rolename, name_regex_)) {
-      throw memgraph::query::QueryRuntimeException("Invalid role name.");
-    }
-    try {
-      auto locked_auth = auth_->Lock();
-      auto role = locked_auth->GetRole(rolename);
-      if (!role) return false;
-      return locked_auth->RemoveRole(rolename);
-    } catch (const memgraph::auth::AuthException &e) {
-      throw memgraph::query::QueryRuntimeException(e.what());
-    }
-  }
-
-  std::vector<memgraph::query::TypedValue> GetUsernames() override {
-    try {
-      auto locked_auth = auth_->ReadLock();
-      std::vector<memgraph::query::TypedValue> usernames;
-      const auto &users = locked_auth->AllUsers();
-      usernames.reserve(users.size());
-      for (const auto &user : users) {
-        usernames.emplace_back(user.username());
-      }
-      return usernames;
-    } catch (const memgraph::auth::AuthException &e) {
-      throw memgraph::query::QueryRuntimeException(e.what());
-    }
-  }
-
-  std::vector<memgraph::query::TypedValue> GetRolenames() override {
-    try {
-      auto locked_auth = auth_->ReadLock();
-      std::vector<memgraph::query::TypedValue> rolenames;
-      const auto &roles = locked_auth->AllRoles();
-      rolenames.reserve(roles.size());
-      for (const auto &role : roles) {
-        rolenames.emplace_back(role.rolename());
-      }
-      return rolenames;
-    } catch (const memgraph::auth::AuthException &e) {
-      throw memgraph::query::QueryRuntimeException(e.what());
-    }
-  }
-
-  std::optional<std::string> GetRolenameForUser(const std::string &username) override {
-    if (!std::regex_match(username, name_regex_)) {
-      throw memgraph::query::QueryRuntimeException("Invalid user name.");
-    }
-    try {
-      auto locked_auth = auth_->ReadLock();
-      auto user = locked_auth->GetUser(username);
-      if (!user) {
-        throw memgraph::query::QueryRuntimeException("User '{}' doesn't exist .", username);
-      }
-
-      if (const auto *role = user->role(); role != nullptr) {
-        return role->rolename();
-      }
-      return std::nullopt;
-    } catch (const memgraph::auth::AuthException &e) {
-      throw memgraph::query::QueryRuntimeException(e.what());
-    }
-  }
-
-  std::vector<memgraph::query::TypedValue> GetUsernamesForRole(const std::string &rolename) override {
-    if (!std::regex_match(rolename, name_regex_)) {
-      throw memgraph::query::QueryRuntimeException("Invalid role name.");
-    }
-    try {
-      auto locked_auth = auth_->ReadLock();
-      auto role = locked_auth->GetRole(rolename);
-      if (!role) {
-        throw memgraph::query::QueryRuntimeException("Role '{}' doesn't exist.", rolename);
-      }
-      std::vector<memgraph::query::TypedValue> usernames;
-      const auto &users = locked_auth->AllUsersForRole(rolename);
-      usernames.reserve(users.size());
-      for (const auto &user : users) {
-        usernames.emplace_back(user.username());
-      }
-      return usernames;
-    } catch (const memgraph::auth::AuthException &e) {
-      throw memgraph::query::QueryRuntimeException(e.what());
-    }
-  }
-
-  void SetRole(const std::string &username, const std::string &rolename) override {
-    if (!std::regex_match(username, name_regex_)) {
-      throw memgraph::query::QueryRuntimeException("Invalid user name.");
-    }
-    if (!std::regex_match(rolename, name_regex_)) {
-      throw memgraph::query::QueryRuntimeException("Invalid role name.");
-    }
-    try {
-      auto locked_auth = auth_->Lock();
-      auto user = locked_auth->GetUser(username);
-      if (!user) {
-        throw memgraph::query::QueryRuntimeException("User '{}' doesn't exist .", username);
-      }
-      auto role = locked_auth->GetRole(rolename);
-      if (!role) {
-        throw memgraph::query::QueryRuntimeException("Role '{}' doesn't exist .", rolename);
-      }
-      if (const auto *current_role = user->role(); current_role != nullptr) {
-        throw memgraph::query::QueryRuntimeException("User '{}' is already a member of role '{}'.", username,
-                                                     current_role->rolename());
-      }
-      user->SetRole(*role);
-      locked_auth->SaveUser(*user);
-    } catch (const memgraph::auth::AuthException &e) {
-      throw memgraph::query::QueryRuntimeException(e.what());
-    }
-  }
-
-  void ClearRole(const std::string &username) override {
-    if (!std::regex_match(username, name_regex_)) {
-      throw memgraph::query::QueryRuntimeException("Invalid user name.");
-    }
-    try {
-      auto locked_auth = auth_->Lock();
-      auto user = locked_auth->GetUser(username);
-      if (!user) {
-        throw memgraph::query::QueryRuntimeException("User '{}' doesn't exist .", username);
-      }
-      user->ClearRole();
-      locked_auth->SaveUser(*user);
-    } catch (const memgraph::auth::AuthException &e) {
-      throw memgraph::query::QueryRuntimeException(e.what());
-    }
-  }
-
-  std::vector<std::vector<memgraph::query::TypedValue>> GetPrivileges(const std::string &user_or_role) override {
-    if (!std::regex_match(user_or_role, name_regex_)) {
-      throw memgraph::query::QueryRuntimeException("Invalid user or role name.");
-    }
-    try {
-      auto locked_auth = auth_->ReadLock();
-      std::vector<std::vector<memgraph::query::TypedValue>> grants;
-      auto user = locked_auth->GetUser(user_or_role);
-      auto role = locked_auth->GetRole(user_or_role);
-      if (!user && !role) {
-        throw memgraph::query::QueryRuntimeException("User or role '{}' doesn't exist.", user_or_role);
-      }
-      if (user) {
-        const auto &permissions = user->GetPermissions();
-        for (const auto &privilege : memgraph::query::kPrivilegesAll) {
-          auto permission = memgraph::glue::PrivilegeToPermission(privilege);
-          auto effective = permissions.Has(permission);
-          if (permissions.Has(permission) != memgraph::auth::PermissionLevel::NEUTRAL) {
-            std::vector<std::string> description;
-            auto user_level = user->permissions().Has(permission);
-            if (user_level == memgraph::auth::PermissionLevel::GRANT) {
-              description.emplace_back("GRANTED TO USER");
-            } else if (user_level == memgraph::auth::PermissionLevel::DENY) {
-              description.emplace_back("DENIED TO USER");
-            }
-            if (const auto *role = user->role(); role != nullptr) {
-              auto role_level = role->permissions().Has(permission);
-              if (role_level == memgraph::auth::PermissionLevel::GRANT) {
-                description.emplace_back("GRANTED TO ROLE");
-              } else if (role_level == memgraph::auth::PermissionLevel::DENY) {
-                description.emplace_back("DENIED TO ROLE");
-              }
-            }
-            grants.push_back({memgraph::query::TypedValue(memgraph::auth::PermissionToString(permission)),
-                              memgraph::query::TypedValue(memgraph::auth::PermissionLevelToString(effective)),
-                              memgraph::query::TypedValue(memgraph::utils::Join(description, ", "))});
-          }
-        }
-      } else {
-        const auto &permissions = role->permissions();
-        for (const auto &privilege : memgraph::query::kPrivilegesAll) {
-          auto permission = memgraph::glue::PrivilegeToPermission(privilege);
-          auto effective = permissions.Has(permission);
-          if (effective != memgraph::auth::PermissionLevel::NEUTRAL) {
-            std::string description;
-            if (effective == memgraph::auth::PermissionLevel::GRANT) {
-              description = "GRANTED TO ROLE";
-            } else if (effective == memgraph::auth::PermissionLevel::DENY) {
-              description = "DENIED TO ROLE";
-            }
-            grants.push_back({memgraph::query::TypedValue(memgraph::auth::PermissionToString(permission)),
-                              memgraph::query::TypedValue(memgraph::auth::PermissionLevelToString(effective)),
-                              memgraph::query::TypedValue(description)});
-          }
-        }
-      }
-      return grants;
-    } catch (const memgraph::auth::AuthException &e) {
-      throw memgraph::query::QueryRuntimeException(e.what());
-    }
-  }
-
-  void GrantPrivilege(
-      const std::string &user_or_role, const std::vector<memgraph::query::AuthQuery::Privilege> &privileges,
-      const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
-          &label_privileges,
-      const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
-          &edge_type_privileges) override {
-    EditPermissions(
-        user_or_role, privileges, label_privileges, edge_type_privileges,
-        [](auto &permissions, const auto &permission) {
-          // TODO (mferencevic): should we first check that the
-          // privilege is granted/denied/revoked before
-          // unconditionally granting/denying/revoking it?
-          permissions.Grant(permission);
-        },
-        [](auto &fine_grained_permissions, const auto &privilege_collection) {
-          for (const auto &[privilege, entities] : privilege_collection) {
-            const auto &permission = memgraph::glue::FineGrainedPrivilegeToFineGrainedPermission(privilege);
-            for (const auto &entity : entities) {
-              fine_grained_permissions.Grant(entity, permission);
-            }
-          }
-        });
-  }
-
-  void DenyPrivilege(
-      const std::string &user_or_role, const std::vector<memgraph::query::AuthQuery::Privilege> &privileges,
-      const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
-          &label_privileges,
-      const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
-          &edge_type_privileges) override {
-    EditPermissions(
-        user_or_role, privileges, label_privileges, edge_type_privileges,
-        [](auto &permissions, const auto &permission) {
-          // TODO (mferencevic): should we first check that the
-          // privilege is granted/denied/revoked before
-          // unconditionally granting/denying/revoking it?
-          permissions.Deny(permission);
-        },
-        [](auto &fine_grained_permissions, const auto &privilege_collection) {
-          for (const auto &[privilege, entities] : privilege_collection) {
-            const auto &permission = memgraph::glue::FineGrainedPrivilegeToFineGrainedPermission(privilege);
-            for (const auto &entity : entities) {
-              fine_grained_permissions.Deny(entity, permission);
-            }
-          }
-        });
-  }
-
-  void RevokePrivilege(
-      const std::string &user_or_role, const std::vector<memgraph::query::AuthQuery::Privilege> &privileges,
-      const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
-          &label_privileges,
-      const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
-          &edge_type_privileges) override {
-    EditPermissions(
-        user_or_role, privileges, label_privileges, edge_type_privileges,
-        [](auto &permissions, const auto &permission) {
-          // TODO (mferencevic): should we first check that the
-          // privilege is granted/denied/revoked before
-          // unconditionally granting/denying/revoking it?
-          permissions.Revoke(permission);
-        },
-        [](auto &fine_grained_permissions, const auto &privilege_collection) {
-          for ([[maybe_unused]] const auto &[privilege, entities] : privilege_collection) {
-            for (const auto &entity : entities) {
-              fine_grained_permissions.Revoke(entity);
-            }
-          }
-        });
-  }
-
- private:
-  template <class TEditPermissionsFun, class TEditFineGrainedPermissionsFun>
-  void EditPermissions(
-      const std::string &user_or_role, const std::vector<memgraph::query::AuthQuery::Privilege> &privileges,
-      const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
-          &label_privileges,
-      const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
-          &edge_type_privileges,
-      const TEditPermissionsFun &edit_permissions_fun,
-      const TEditFineGrainedPermissionsFun &edit_fine_grained_permissions_fun) {
-    if (!std::regex_match(user_or_role, name_regex_)) {
-      throw memgraph::query::QueryRuntimeException("Invalid user or role name.");
-    }
-    try {
-      std::vector<memgraph::auth::Permission> permissions;
-      permissions.reserve(privileges.size());
-      for (const auto &privilege : privileges) {
-        permissions.push_back(memgraph::glue::PrivilegeToPermission(privilege));
-      }
-      auto locked_auth = auth_->Lock();
-      auto user = locked_auth->GetUser(user_or_role);
-      auto role = locked_auth->GetRole(user_or_role);
-      if (!user && !role) {
-        throw memgraph::query::QueryRuntimeException("User or role '{}' doesn't exist.", user_or_role);
-      }
-      if (user) {
-        for (const auto &permission : permissions) {
-          edit_permissions_fun(user->permissions(), permission);
-        }
-        for (const auto &label_privilege_collection : label_privileges) {
-          edit_fine_grained_permissions_fun(user->fine_grained_access_handler().label_permissions(),
-                                            label_privilege_collection);
-        }
-        for (const auto &edge_type_privilege_collection : edge_type_privileges) {
-          edit_fine_grained_permissions_fun(user->fine_grained_access_handler().edge_type_permissions(),
-                                            edge_type_privilege_collection);
-        }
-
-        locked_auth->SaveUser(*user);
-      } else {
-        for (const auto &permission : permissions) {
-          edit_permissions_fun(role->permissions(), permission);
-        }
-        for (const auto &label_privilege : label_privileges) {
-          edit_fine_grained_permissions_fun(user->fine_grained_access_handler().label_permissions(), label_privilege);
-        }
-        for (const auto &edge_type_privilege : edge_type_privileges) {
-          edit_fine_grained_permissions_fun(role->fine_grained_access_handler().edge_type_permissions(),
-                                            edge_type_privilege);
-        }
-
-        locked_auth->SaveRole(*role);
-      }
-    } catch (const memgraph::auth::AuthException &e) {
-      throw memgraph::query::QueryRuntimeException(e.what());
-    }
-  }
-};
-
 class BoltSession final : public memgraph::communication::bolt::Session<memgraph::communication::v2::InputStream,
                                                                         memgraph::communication::v2::OutputStream> {
  public:
@@ -1277,7 +864,7 @@ int main(int argc, char **argv) {
   memgraph::query::procedure::gModuleRegistry.SetModulesDirectory(query_modules_directories, FLAGS_data_directory);
   memgraph::query::procedure::gModuleRegistry.UnloadAndLoadModulesFromDirectories();
 
-  AuthQueryHandler auth_handler(&auth, FLAGS_auth_user_or_role_name_regex);
+  memgraph::glue::AuthQueryHandler auth_handler(&auth, FLAGS_auth_user_or_role_name_regex);
   memgraph::glue::AuthChecker auth_checker{&auth};
   interpreter_context.auth = &auth_handler;
   interpreter_context.auth_checker = &auth_checker;
diff --git a/tests/e2e/lba_procedures/CMakeLists.txt b/tests/e2e/lba_procedures/CMakeLists.txt
index 485b51cbe..f1d4e852b 100644
--- a/tests/e2e/lba_procedures/CMakeLists.txt
+++ b/tests/e2e/lba_procedures/CMakeLists.txt
@@ -4,5 +4,6 @@ endfunction()
 
 copy_lba_procedures_e2e_python_files(common.py)
 copy_lba_procedures_e2e_python_files(lba_procedures.py)
+copy_lba_procedures_e2e_python_files(show_privileges.py)
 
 add_subdirectory(procedures)
diff --git a/tests/e2e/lba_procedures/show_privileges.py b/tests/e2e/lba_procedures/show_privileges.py
new file mode 100644
index 000000000..ddd84d065
--- /dev/null
+++ b/tests/e2e/lba_procedures/show_privileges.py
@@ -0,0 +1,117 @@
+# Copyright 2022 Memgraph Ltd.
+#
+# Use of this software is governed by the Business Source License
+# included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
+# License, and you may not use this file except in compliance with the Business Source License.
+#
+# As of the Change Date specified in that file, in accordance with
+# the Business Source License, use of this software will be governed
+# by the Apache License, Version 2.0, included in the file
+# licenses/APL.txt.
+
+import sys
+import pytest
+from common import connect, execute_and_fetch_all
+
+BASIC_PRIVILEGES = [
+    "CREATE",
+    "DELETE",
+    "MATCH",
+    "MERGE",
+    "SET",
+    "REMOVE",
+    "INDEX",
+    "STATS",
+    "AUTH",
+    "REPLICATION",
+    "READ_FILE",
+    "DURABILITY",
+    "FREE_MEMORY",
+    "TRIGGER",
+    "STREAM",
+    "CONFIG",
+    "CONSTRAINT",
+    "DUMP",
+    "MODULE_READ",
+    "WEBSOCKET",
+    "MODULE_WRITE",
+]
+
+
+def test_lba_procedures_show_privileges_first_user():
+    expected_assertions_josip = [
+        ("ALL LABELS", "CREATE_DELETE", "GLOBAL LABEL PERMISSION GRANTED TO USER"),
+        (
+            "ALL EDGE_TYPES",
+            "CREATE_DELETE",
+            "GLOBAL EDGE_TYPE PERMISSION GRANTED TO USER",
+        ),
+        ("LABEL :Label1", "READ", "LABEL PERMISSION GRANTED TO USER"),
+        ("LABEL :Label2", "NO_PERMISSION", "LABEL PERMISSION DENIED TO USER"),
+        ("LABEL :Label3", "UPDATE", "LABEL PERMISSION GRANTED TO USER"),
+        ("LABEL :Label4", "READ", "LABEL PERMISSION GRANTED TO USER"),
+        ("LABEL :Label5", "CREATE_DELETE", "LABEL PERMISSION GRANTED TO USER"),
+        ("LABEL :Label6", "UPDATE", "LABEL PERMISSION GRANTED TO USER"),
+        ("LABEL :Label7", "NO_PERMISSION", "LABEL PERMISSION DENIED TO USER"),
+    ]
+
+    cursor = connect(username="Josip", password="").cursor()
+    result = execute_and_fetch_all(cursor, "SHOW PRIVILEGES FOR Josip;")
+
+    assert len(result) == 30
+
+    fine_privilege_results = [res for res in result if res[0] not in BASIC_PRIVILEGES]
+
+    assert len(fine_privilege_results) == len(expected_assertions_josip)
+    assert set(expected_assertions_josip) == set(fine_privilege_results)
+
+
+def test_lba_procedures_show_privileges_second_user():
+    expected_assertions_boris = [
+        ("AUTH", "GRANT", "GRANTED TO USER"),
+        ("LABEL :Label1", "READ", "LABEL PERMISSION GRANTED TO USER"),
+        ("LABEL :Label2", "NO_PERMISSION", "LABEL PERMISSION DENIED TO USER"),
+        ("LABEL :Label3", "UPDATE", "LABEL PERMISSION GRANTED TO USER"),
+        ("LABEL :Label4", "READ", "LABEL PERMISSION GRANTED TO USER"),
+        ("LABEL :Label5", "CREATE_DELETE", "LABEL PERMISSION GRANTED TO USER"),
+        ("LABEL :Label6", "UPDATE", "LABEL PERMISSION GRANTED TO USER"),
+        ("LABEL :Label7", "NO_PERMISSION", "LABEL PERMISSION DENIED TO USER"),
+    ]
+
+    cursor = connect(username="Boris", password="").cursor()
+    result = execute_and_fetch_all(cursor, "SHOW PRIVILEGES FOR Boris;")
+
+    assert len(result) == len(expected_assertions_boris)
+    assert set(result) == set(expected_assertions_boris)
+
+
+def test_lba_procedures_show_privileges_third_user():
+    expected_assertions_niko = [
+        ("AUTH", "GRANT", "GRANTED TO USER"),
+        ("ALL LABELS", "READ", "GLOBAL LABEL PERMISSION GRANTED TO USER"),
+    ]
+
+    cursor = connect(username="Niko", password="").cursor()
+    result = execute_and_fetch_all(cursor, "SHOW PRIVILEGES FOR Niko;")
+
+    assert len(result) == len(expected_assertions_niko)
+    assert set(result) == set(expected_assertions_niko)
+
+
+def test_lba_procedures_show_privileges_fourth_user():
+    expected_assertions_bruno = [
+        ("AUTH", "GRANT", "GRANTED TO USER"),
+        ("ALL LABELS", "UPDATE", "GLOBAL LABEL PERMISSION GRANTED TO USER"),
+    ]
+
+    # TODO: Revisit behaviour of this test
+
+    cursor = connect(username="Bruno", password="").cursor()
+    result = execute_and_fetch_all(cursor, "SHOW PRIVILEGES FOR Bruno;")
+
+    assert len(result) == len(expected_assertions_bruno)
+    assert set(result) == set(expected_assertions_bruno)
+
+
+if __name__ == "__main__":
+    sys.exit(pytest.main([__file__, "-rA"]))
diff --git a/tests/e2e/lba_procedures/workloads.yaml b/tests/e2e/lba_procedures/workloads.yaml
index 046a28397..353001d5f 100644
--- a/tests/e2e/lba_procedures/workloads.yaml
+++ b/tests/e2e/lba_procedures/workloads.yaml
@@ -20,9 +20,52 @@ template_cluster: &template_cluster
       ]
       validation_queries: []
 
+show_privileges_cluster: &show_privileges_cluster
+  cluster:
+    main:
+      args: ["--bolt-port", "7687", "--log-level=TRACE"]
+      log_file: "lba-e2e.log"
+      setup_queries: [
+        "Create User Josip;",
+        "Grant Read On Labels :Label1 to Josip;",
+        "Deny Read On Labels :Label2 to Josip;",
+        "Grant Update On Labels :Label3 to Josip;",
+        "Deny Update On Labels :Label4 to Josip;",
+        "Grant Create_Delete On Labels :Label5 to Josip;",
+        "Deny Create_Delete On Labels :Label6 to Josip;",
+        "Grant Create_Delete On Labels :Label7 to Josip;",
+        "Deny Read On Labels :Label7 to Josip;",
+
+        "Create User Boris;",
+        "Grant Auth to Boris;",
+        "Grant Read On Labels :Label1 to Boris;",
+        "Deny Read On Labels :Label2 to Boris;",
+        "Grant Update On Labels :Label3 to Boris;",
+        "Deny Update On Labels :Label4 to Boris;",
+        "Grant Create_Delete On Labels :Label5 to Boris;",
+        "Deny Create_Delete On Labels :Label6 to Boris;",
+        "Grant Create_Delete On Labels :Label7 to Boris;",
+        "Deny Read On Labels :Label7 to Boris;",
+
+        "Create User Niko;",
+        "Grant Auth to Niko;",
+        "Grant Create_Delete On Labels * to Niko",
+        "Deny Update On Labels * to Niko",
+
+        "Create User Bruno;",
+        "Grant Auth to Bruno;",
+        "Deny Create_Delete On Labels * to Bruno"
+      ]
+
 workloads:
   - name: "Label-based auth"
     binary: "tests/e2e/pytest_runner.sh"
     proc: "tests/e2e/lba_procedures/procedures/"
     args: ["lba_procedures/lba_procedures.py"]
     <<: *template_cluster
+
+  - name: "show-privileges"
+    binary: "tests/e2e/pytest_runner.sh"
+    proc: "tests/e2e/lba_procedures/procedures/"
+    args: ["lba_procedures/show_privileges.py"]
+    <<: *show_privileges_cluster
diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt
index a474ff3de..420406c4e 100644
--- a/tests/unit/CMakeLists.txt
+++ b/tests/unit/CMakeLists.txt
@@ -324,6 +324,9 @@ target_link_libraries(${test_prefix}replication_persistence_helper mg-storage-v2
 add_unit_test(auth_checker.cpp)
 target_link_libraries(${test_prefix}auth_checker mg-glue mg-auth)
 
+add_unit_test(auth_handler.cpp)
+target_link_libraries(${test_prefix}auth_handler mg-glue mg-auth)
+
 # Test mg-auth
 if(MG_ENTERPRISE)
   add_unit_test(auth.cpp)
diff --git a/tests/unit/auth_handler.cpp b/tests/unit/auth_handler.cpp
new file mode 100644
index 000000000..06c69c7e9
--- /dev/null
+++ b/tests/unit/auth_handler.cpp
@@ -0,0 +1,724 @@
+// Copyright 2022 Memgraph Ltd.
+//
+// Use of this software is governed by the Business Source License
+// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
+// License, and you may not use this file except in compliance with the Business Source License.
+//
+// As of the Change Date specified in that file, in accordance with
+// the Business Source License, use of this software will be governed
+// by the Apache License, Version 2.0, included in the file
+// licenses/APL.txt.
+
+#include <gflags/gflags.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "auth/auth.hpp"
+#include "auth/models.hpp"
+#include "glue/auth_handler.hpp"
+#include "query/typed_value.hpp"
+#include "utils/file.hpp"
+#include "utils/rw_lock.hpp"
+#include "utils/synchronized.hpp"
+
+class AuthQueryHandlerFixture : public testing::Test {
+ protected:
+  std::filesystem::path test_folder_{std::filesystem::temp_directory_path() / "MG_tests_unit_auth_handler"};
+  memgraph::utils::Synchronized<memgraph::auth::Auth, memgraph::utils::WritePrioritizedRWLock> auth{
+      test_folder_ / ("unit_auth_handler_test_" + std::to_string(static_cast<int>(getpid())))};
+  memgraph::glue::AuthQueryHandler auth_handler{&auth, memgraph::glue::kDefaultUserRoleRegex.data()};
+
+  std::string user_name = "Mate";
+  std::string edge_type_repr = "EdgeType1";
+  std::string label_repr = "Label1";
+  memgraph::auth::Permissions perms{};
+  memgraph::auth::FineGrainedAccessHandler handler{};
+
+  virtual void SetUp() {
+    memgraph::utils::EnsureDir(test_folder_);
+    memgraph::utils::license::global_license_checker.EnableTesting();
+  }
+
+  virtual void TearDown() {
+    std::filesystem::remove_all(test_folder_);
+    perms = memgraph::auth::Permissions{};
+    handler = memgraph::auth::FineGrainedAccessHandler{};
+  }
+};
+
+TEST_F(AuthQueryHandlerFixture, GivenAuthQueryHandlerWhenInitializedHaveNoUsernamesOrRolenames) {
+  ASSERT_EQ(auth_handler.GetUsernames().size(), 0);
+  ASSERT_EQ(auth_handler.GetRolenames().size(), 0);
+}
+
+TEST_F(AuthQueryHandlerFixture, GivenUserWhenNoDeniesOrGrantsThenNothingIsReturned) {
+  memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
+  auth->SaveUser(user);
+
+  { ASSERT_EQ(auth_handler.GetUsernames().size(), 1); }
+
+  {
+    auto privileges = auth_handler.GetPrivileges(user_name);
+
+    ASSERT_EQ(privileges.size(), 0);
+  }
+}
+
+TEST_F(AuthQueryHandlerFixture, GivenUserWhenAddedGrantPermissionThenItIsReturned) {
+  perms.Grant(memgraph::auth::Permission::MATCH);
+  memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
+  auth->SaveUser(user);
+
+  auto privileges = auth_handler.GetPrivileges(user_name);
+  ASSERT_EQ(privileges.size(), 1);
+
+  auto result = *privileges.begin();
+  ASSERT_EQ(result.size(), 3);
+
+  ASSERT_TRUE(result[0].IsString());
+  ASSERT_EQ(result[0].ValueString(), "MATCH");
+
+  ASSERT_TRUE(result[1].IsString());
+  ASSERT_EQ(result[1].ValueString(), "GRANT");
+
+  ASSERT_TRUE(result[2].IsString());
+  ASSERT_EQ(result[2].ValueString(), "GRANTED TO USER");
+}
+
+TEST_F(AuthQueryHandlerFixture, GivenUserWhenAddedDenyPermissionThenItIsReturned) {
+  perms.Deny(memgraph::auth::Permission::MATCH);
+  memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
+  auth->SaveUser(user);
+
+  auto privileges = auth_handler.GetPrivileges(user_name);
+  ASSERT_EQ(privileges.size(), 1);
+
+  auto result = *privileges.begin();
+  ASSERT_EQ(result.size(), 3);
+
+  ASSERT_TRUE(result[0].IsString());
+  ASSERT_EQ(result[0].ValueString(), "MATCH");
+
+  ASSERT_TRUE(result[1].IsString());
+  ASSERT_EQ(result[1].ValueString(), "DENY");
+
+  ASSERT_TRUE(result[2].IsString());
+  ASSERT_EQ(result[2].ValueString(), "DENIED TO USER");
+}
+
+TEST_F(AuthQueryHandlerFixture, GivenUserWhenPrivilegeRevokedThenNothingIsReturned) {
+  perms.Deny(memgraph::auth::Permission::MATCH);
+  perms.Revoke(memgraph::auth::Permission::MATCH);
+  memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
+  auth->SaveUser(user);
+
+  auto privileges = auth_handler.GetPrivileges(user_name);
+  ASSERT_EQ(privileges.size(), 0);
+}
+
+TEST_F(AuthQueryHandlerFixture, GivenRoleWhenPrivilegeGrantedThenItIsReturned) {
+  perms.Grant(memgraph::auth::Permission::MATCH);
+  memgraph::auth::Role role = memgraph::auth::Role{"Mates_role", perms, handler};
+  auth->SaveRole(role);
+
+  { ASSERT_EQ(auth_handler.GetRolenames().size(), 1); }
+
+  {
+    auto privileges = auth_handler.GetPrivileges("Mates_role");
+    ASSERT_EQ(privileges.size(), 1);
+
+    auto result = *privileges.begin();
+    ASSERT_EQ(result.size(), 3);
+
+    ASSERT_TRUE(result[0].IsString());
+    ASSERT_EQ(result[0].ValueString(), "MATCH");
+
+    ASSERT_TRUE(result[1].IsString());
+    ASSERT_EQ(result[1].ValueString(), "GRANT");
+
+    ASSERT_TRUE(result[2].IsString());
+    ASSERT_EQ(result[2].ValueString(), "GRANTED TO ROLE");
+  }
+}
+
+TEST_F(AuthQueryHandlerFixture, GivenRoleWhenPrivilegeDeniedThenItIsReturned) {
+  perms.Deny(memgraph::auth::Permission::MATCH);
+  memgraph::auth::Role role = memgraph::auth::Role{"Mates_role", perms, handler};
+  auth->SaveRole(role);
+
+  auto privileges = auth_handler.GetPrivileges("Mates_role");
+  ASSERT_EQ(privileges.size(), 1);
+
+  auto result = *privileges.begin();
+  ASSERT_EQ(result.size(), 3);
+
+  ASSERT_TRUE(result[0].IsString());
+  ASSERT_EQ(result[0].ValueString(), "MATCH");
+
+  ASSERT_TRUE(result[1].IsString());
+  ASSERT_EQ(result[1].ValueString(), "DENY");
+
+  ASSERT_TRUE(result[2].IsString());
+  ASSERT_EQ(result[2].ValueString(), "DENIED TO ROLE");
+}
+
+TEST_F(AuthQueryHandlerFixture, GivenRoleWhenPrivilegeRevokedThenNothingIsReturned) {
+  perms.Deny(memgraph::auth::Permission::MATCH);
+  perms.Revoke(memgraph::auth::Permission::MATCH);
+  memgraph::auth::Role role = memgraph::auth::Role{"Mates_role", perms, handler};
+  auth->SaveRole(role);
+
+  auto privileges = auth_handler.GetPrivileges("Mates_role");
+  ASSERT_EQ(privileges.size(), 0);
+}
+
+TEST_F(AuthQueryHandlerFixture, GivenUserWhenGrantedTwoPrivilegesThenBothAreReturned) {
+  perms.Grant(memgraph::auth::Permission::MATCH);
+  perms.Grant(memgraph::auth::Permission::CREATE);
+  memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
+  auth->SaveUser(user);
+
+  auto privileges = auth_handler.GetPrivileges(user_name);
+  ASSERT_EQ(privileges.size(), 2);
+}
+
+TEST_F(AuthQueryHandlerFixture, GivenUserAndRoleWhenOneGrantedAndOtherGrantedThenBothArePrinted) {
+  perms.Grant(memgraph::auth::Permission::MATCH);
+  memgraph::auth::Role role = memgraph::auth::Role{"Mates_role", perms, handler};
+  auth->SaveRole(role);
+  memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
+  user.SetRole(role);
+  auth->SaveUser(user);
+
+  auto privileges = auth_handler.GetPrivileges(user_name);
+  ASSERT_EQ(privileges.size(), 1);
+
+  auto result = *privileges.begin();
+  ASSERT_EQ(result.size(), 3);
+
+  ASSERT_TRUE(result[0].IsString());
+  ASSERT_EQ(result[0].ValueString(), "MATCH");
+
+  ASSERT_TRUE(result[1].IsString());
+  ASSERT_EQ(result[1].ValueString(), "GRANT");
+
+  ASSERT_TRUE(result[2].IsString());
+  ASSERT_EQ(result[2].ValueString(), "GRANTED TO USER, GRANTED TO ROLE");
+}
+
+TEST_F(AuthQueryHandlerFixture, GivenUserAndRoleWhenOneDeniedAndOtherDeniedThenBothArePrinted) {
+  perms.Deny(memgraph::auth::Permission::MATCH);
+  memgraph::auth::Role role = memgraph::auth::Role{"Mates_role", perms, handler};
+  auth->SaveRole(role);
+  memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
+  user.SetRole(role);
+  auth->SaveUser(user);
+
+  auto privileges = auth_handler.GetPrivileges(user_name);
+  ASSERT_EQ(privileges.size(), 1);
+
+  auto result = *privileges.begin();
+  ASSERT_EQ(result.size(), 3);
+
+  ASSERT_TRUE(result[0].IsString());
+  ASSERT_EQ(result[0].ValueString(), "MATCH");
+
+  ASSERT_TRUE(result[1].IsString());
+  ASSERT_EQ(result[1].ValueString(), "DENY");
+
+  ASSERT_TRUE(result[2].IsString());
+  ASSERT_EQ(result[2].ValueString(), "DENIED TO USER, DENIED TO ROLE");
+}
+
+TEST_F(AuthQueryHandlerFixture, GivenUserAndRoleWhenOneGrantedAndOtherDeniedThenBothArePrinted) {
+  memgraph::auth::Permissions role_perms{};
+  role_perms.Deny(memgraph::auth::Permission::MATCH);
+  memgraph::auth::Role role = memgraph::auth::Role{"Mates_role", role_perms, handler};
+  auth->SaveRole(role);
+
+  memgraph::auth::Permissions user_perms{};
+  user_perms.Grant(memgraph::auth::Permission::MATCH);
+  memgraph::auth::User user = memgraph::auth::User{user_name, "", user_perms, handler};
+  user.SetRole(role);
+  auth->SaveUser(user);
+
+  auto privileges = auth_handler.GetPrivileges(user_name);
+  ASSERT_EQ(privileges.size(), 1);
+
+  auto result = *privileges.begin();
+  ASSERT_EQ(result.size(), 3);
+
+  ASSERT_TRUE(result[0].IsString());
+  ASSERT_EQ(result[0].ValueString(), "MATCH");
+
+  ASSERT_TRUE(result[1].IsString());
+  ASSERT_EQ(result[1].ValueString(), "DENY");
+
+  ASSERT_TRUE(result[2].IsString());
+  ASSERT_EQ(result[2].ValueString(), "GRANTED TO USER, DENIED TO ROLE");
+}
+
+TEST_F(AuthQueryHandlerFixture, GivenUserAndRoleWhenOneDeniedAndOtherGrantedThenBothArePrinted) {
+  memgraph::auth::Permissions role_perms{};
+  role_perms.Grant(memgraph::auth::Permission::MATCH);
+  memgraph::auth::Role role = memgraph::auth::Role{"Mates_role", role_perms, handler};
+  auth->SaveRole(role);
+
+  memgraph::auth::Permissions user_perms{};
+  user_perms.Deny(memgraph::auth::Permission::MATCH);
+  memgraph::auth::User user = memgraph::auth::User{user_name, "", user_perms, handler};
+  user.SetRole(role);
+  auth->SaveUser(user);
+
+  auto privileges = auth_handler.GetPrivileges(user_name);
+  ASSERT_EQ(privileges.size(), 1);
+
+  auto result = *privileges.begin();
+  ASSERT_EQ(result.size(), 3);
+
+  ASSERT_TRUE(result[0].IsString());
+  ASSERT_EQ(result[0].ValueString(), "MATCH");
+
+  ASSERT_TRUE(result[1].IsString());
+  ASSERT_EQ(result[1].ValueString(), "DENY");
+
+  ASSERT_TRUE(result[2].IsString());
+  ASSERT_EQ(result[2].ValueString(), "DENIED TO USER, GRANTED TO ROLE");
+}
+
+TEST_F(AuthQueryHandlerFixture, GivenUserWhenGrantedPrivilegeOnLabelThenIsDisplayed) {
+  auto read_permission = memgraph::auth::FineGrainedAccessPermissions();
+  read_permission.Grant(label_repr, memgraph::auth::FineGrainedPermission::READ);
+
+  handler = memgraph::auth::FineGrainedAccessHandler{
+      memgraph::auth::FineGrainedAccessPermissions{read_permission},
+      memgraph::auth::FineGrainedAccessPermissions{},
+  };
+
+  memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
+  auth->SaveUser(user);
+
+  auto privileges = auth_handler.GetPrivileges(user_name);
+  ASSERT_EQ(privileges.size(), 1);
+
+  auto result = *privileges.begin();
+  ASSERT_EQ(result.size(), 3);
+
+  ASSERT_TRUE(result[0].IsString());
+  ASSERT_EQ(result[0].ValueString(), "LABEL :Label1");
+
+  ASSERT_TRUE(result[1].IsString());
+  ASSERT_EQ(result[1].ValueString(), "READ");
+
+  ASSERT_TRUE(result[2].IsString());
+  ASSERT_EQ(result[2].ValueString(), "LABEL PERMISSION GRANTED TO USER");
+}
+
+TEST_F(AuthQueryHandlerFixture, GivenUserWhenGrantedMultiplePrivilegesOnLabelThenTopOneIsDisplayed) {
+  auto read_permission = memgraph::auth::FineGrainedAccessPermissions();
+  read_permission.Grant(label_repr, memgraph::auth::FineGrainedPermission::READ);
+  read_permission.Grant(label_repr, memgraph::auth::FineGrainedPermission::UPDATE);
+
+  handler = memgraph::auth::FineGrainedAccessHandler{
+      memgraph::auth::FineGrainedAccessPermissions{read_permission},
+      memgraph::auth::FineGrainedAccessPermissions{},
+  };
+
+  memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
+  auth->SaveUser(user);
+
+  auto privileges = auth_handler.GetPrivileges(user_name);
+  ASSERT_EQ(privileges.size(), 1);
+
+  auto result = *privileges.begin();
+  ASSERT_EQ(result.size(), 3);
+
+  ASSERT_TRUE(result[0].IsString());
+  ASSERT_EQ(result[0].ValueString(), "LABEL :Label1");
+
+  ASSERT_TRUE(result[1].IsString());
+  ASSERT_EQ(result[1].ValueString(), "UPDATE");
+
+  ASSERT_TRUE(result[2].IsString());
+  ASSERT_EQ(result[2].ValueString(), "LABEL PERMISSION GRANTED TO USER");
+}
+
+TEST_F(AuthQueryHandlerFixture, GivenUserWhenGrantedAllPrivilegesOnLabelThenTopOneIsDisplayed) {
+  auto read_permission = memgraph::auth::FineGrainedAccessPermissions();
+  read_permission.Grant(label_repr, memgraph::auth::FineGrainedPermission::READ);
+  read_permission.Grant(label_repr, memgraph::auth::FineGrainedPermission::UPDATE);
+  read_permission.Grant(label_repr, memgraph::auth::FineGrainedPermission::CREATE_DELETE);
+
+  handler = memgraph::auth::FineGrainedAccessHandler{
+      memgraph::auth::FineGrainedAccessPermissions{read_permission},
+      memgraph::auth::FineGrainedAccessPermissions{},
+  };
+
+  memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
+  auth->SaveUser(user);
+
+  auto privileges = auth_handler.GetPrivileges(user_name);
+  ASSERT_EQ(privileges.size(), 1);
+
+  auto result = *privileges.begin();
+  ASSERT_EQ(result.size(), 3);
+
+  ASSERT_TRUE(result[0].IsString());
+  ASSERT_EQ(result[0].ValueString(), "LABEL :Label1");
+
+  ASSERT_TRUE(result[1].IsString());
+  ASSERT_EQ(result[1].ValueString(), "CREATE_DELETE");
+
+  ASSERT_TRUE(result[2].IsString());
+  ASSERT_EQ(result[2].ValueString(), "LABEL PERMISSION GRANTED TO USER");
+}
+
+TEST_F(AuthQueryHandlerFixture, GivenUserWhenGrantedGlobalPrivilegeOnLabelThenIsDisplayed) {
+  auto read_permission = memgraph::auth::FineGrainedAccessPermissions();
+  read_permission.Grant("*", memgraph::auth::FineGrainedPermission::READ);
+
+  handler = memgraph::auth::FineGrainedAccessHandler{
+      memgraph::auth::FineGrainedAccessPermissions{read_permission},
+      memgraph::auth::FineGrainedAccessPermissions{},
+  };
+
+  memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
+  auth->SaveUser(user);
+
+  auto privileges = auth_handler.GetPrivileges(user_name);
+  ASSERT_EQ(privileges.size(), 1);
+
+  auto result = *privileges.begin();
+  ASSERT_EQ(result.size(), 3);
+
+  ASSERT_TRUE(result[0].IsString());
+  ASSERT_EQ(result[0].ValueString(), "ALL LABELS");
+
+  ASSERT_TRUE(result[1].IsString());
+  ASSERT_EQ(result[1].ValueString(), "READ");
+
+  ASSERT_TRUE(result[2].IsString());
+  ASSERT_EQ(result[2].ValueString(), "GLOBAL LABEL PERMISSION GRANTED TO USER");
+}
+
+TEST_F(AuthQueryHandlerFixture, GivenUserWhenGrantedGlobalMultiplePrivilegesOnLabelThenTopOneIsDisplayed) {
+  auto read_permission = memgraph::auth::FineGrainedAccessPermissions();
+  read_permission.Grant("*", memgraph::auth::FineGrainedPermission::READ);
+  read_permission.Grant("*", memgraph::auth::FineGrainedPermission::UPDATE);
+
+  handler = memgraph::auth::FineGrainedAccessHandler{
+      memgraph::auth::FineGrainedAccessPermissions{read_permission},
+      memgraph::auth::FineGrainedAccessPermissions{},
+  };
+
+  memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
+  auth->SaveUser(user);
+
+  auto privileges = auth_handler.GetPrivileges(user_name);
+  ASSERT_EQ(privileges.size(), 1);
+
+  auto result = *privileges.begin();
+  ASSERT_EQ(result.size(), 3);
+
+  ASSERT_TRUE(result[0].IsString());
+  ASSERT_EQ(result[0].ValueString(), "ALL LABELS");
+
+  ASSERT_TRUE(result[1].IsString());
+  ASSERT_EQ(result[1].ValueString(), "UPDATE");
+
+  ASSERT_TRUE(result[2].IsString());
+  ASSERT_EQ(result[2].ValueString(), "GLOBAL LABEL PERMISSION GRANTED TO USER");
+}
+
+TEST_F(AuthQueryHandlerFixture, GivenUserWhenGrantedGlobalAllPrivilegesOnLabelThenTopOneIsDisplayed) {
+  auto read_permission = memgraph::auth::FineGrainedAccessPermissions();
+  read_permission.Grant("*", memgraph::auth::FineGrainedPermission::READ);
+  read_permission.Grant("*", memgraph::auth::FineGrainedPermission::UPDATE);
+  read_permission.Grant("*", memgraph::auth::FineGrainedPermission::CREATE_DELETE);
+
+  handler = memgraph::auth::FineGrainedAccessHandler{
+      memgraph::auth::FineGrainedAccessPermissions{read_permission},
+      memgraph::auth::FineGrainedAccessPermissions{},
+  };
+
+  memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
+  auth->SaveUser(user);
+
+  auto privileges = auth_handler.GetPrivileges(user_name);
+  ASSERT_EQ(privileges.size(), 1);
+
+  auto result = *privileges.begin();
+  ASSERT_EQ(result.size(), 3);
+
+  ASSERT_TRUE(result[0].IsString());
+  ASSERT_EQ(result[0].ValueString(), "ALL LABELS");
+
+  ASSERT_TRUE(result[1].IsString());
+  ASSERT_EQ(result[1].ValueString(), "CREATE_DELETE");
+
+  ASSERT_TRUE(result[2].IsString());
+  ASSERT_EQ(result[2].ValueString(), "GLOBAL LABEL PERMISSION GRANTED TO USER");
+}
+
+// EDGE_TYPES
+TEST_F(AuthQueryHandlerFixture, GivenUserWhenGrantedPrivilegeOnEdgeTypeThenIsDisplayed) {
+  auto read_permission = memgraph::auth::FineGrainedAccessPermissions();
+  read_permission.Grant(edge_type_repr, memgraph::auth::FineGrainedPermission::READ);
+
+  handler = memgraph::auth::FineGrainedAccessHandler{
+      memgraph::auth::FineGrainedAccessPermissions{},
+      memgraph::auth::FineGrainedAccessPermissions{read_permission},
+  };
+
+  memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
+  auth->SaveUser(user);
+
+  auto privileges = auth_handler.GetPrivileges(user_name);
+  ASSERT_EQ(privileges.size(), 1);
+
+  auto result = *privileges.begin();
+  ASSERT_EQ(result.size(), 3);
+
+  ASSERT_TRUE(result[0].IsString());
+  ASSERT_EQ(result[0].ValueString(), "EDGE_TYPE :EdgeType1");
+
+  ASSERT_TRUE(result[1].IsString());
+  ASSERT_EQ(result[1].ValueString(), "READ");
+
+  ASSERT_TRUE(result[2].IsString());
+  ASSERT_EQ(result[2].ValueString(), "EDGE_TYPE PERMISSION GRANTED TO USER");
+}
+
+TEST_F(AuthQueryHandlerFixture, GivenUserWhenGrantedMultiplePrivilegesOnEdgeTypeThenTopOneIsDisplayed) {
+  auto read_permission = memgraph::auth::FineGrainedAccessPermissions();
+  read_permission.Grant(edge_type_repr, memgraph::auth::FineGrainedPermission::READ);
+  read_permission.Grant(edge_type_repr, memgraph::auth::FineGrainedPermission::UPDATE);
+
+  handler = memgraph::auth::FineGrainedAccessHandler{
+      memgraph::auth::FineGrainedAccessPermissions{},
+      memgraph::auth::FineGrainedAccessPermissions{read_permission},
+  };
+
+  memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
+  auth->SaveUser(user);
+
+  auto privileges = auth_handler.GetPrivileges(user_name);
+  ASSERT_EQ(privileges.size(), 1);
+
+  auto result = *privileges.begin();
+  ASSERT_EQ(result.size(), 3);
+
+  ASSERT_TRUE(result[0].IsString());
+  ASSERT_EQ(result[0].ValueString(), "EDGE_TYPE :EdgeType1");
+
+  ASSERT_TRUE(result[1].IsString());
+  ASSERT_EQ(result[1].ValueString(), "UPDATE");
+
+  ASSERT_TRUE(result[2].IsString());
+  ASSERT_EQ(result[2].ValueString(), "EDGE_TYPE PERMISSION GRANTED TO USER");
+}
+
+TEST_F(AuthQueryHandlerFixture, GivenUserWhenGrantedAllPrivilegesOnEdgeTypeThenTopOneIsDisplayed) {
+  auto read_permission = memgraph::auth::FineGrainedAccessPermissions();
+  read_permission.Grant(edge_type_repr, memgraph::auth::FineGrainedPermission::READ);
+  read_permission.Grant(edge_type_repr, memgraph::auth::FineGrainedPermission::UPDATE);
+  read_permission.Grant(edge_type_repr, memgraph::auth::FineGrainedPermission::CREATE_DELETE);
+
+  handler = memgraph::auth::FineGrainedAccessHandler{
+      memgraph::auth::FineGrainedAccessPermissions{},
+      memgraph::auth::FineGrainedAccessPermissions{read_permission},
+  };
+
+  memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
+  auth->SaveUser(user);
+
+  auto privileges = auth_handler.GetPrivileges(user_name);
+  ASSERT_EQ(privileges.size(), 1);
+
+  auto result = *privileges.begin();
+  ASSERT_EQ(result.size(), 3);
+
+  ASSERT_TRUE(result[0].IsString());
+  ASSERT_EQ(result[0].ValueString(), "EDGE_TYPE :EdgeType1");
+
+  ASSERT_TRUE(result[1].IsString());
+  ASSERT_EQ(result[1].ValueString(), "CREATE_DELETE");
+
+  ASSERT_TRUE(result[2].IsString());
+  ASSERT_EQ(result[2].ValueString(), "EDGE_TYPE PERMISSION GRANTED TO USER");
+}
+
+TEST_F(AuthQueryHandlerFixture, GivenUserWhenGrantedGlobalPrivilegeOnEdgeTypeThenIsDisplayed) {
+  auto read_permission = memgraph::auth::FineGrainedAccessPermissions();
+  read_permission.Grant("*", memgraph::auth::FineGrainedPermission::READ);
+
+  handler = memgraph::auth::FineGrainedAccessHandler{
+      memgraph::auth::FineGrainedAccessPermissions{},
+      memgraph::auth::FineGrainedAccessPermissions{read_permission},
+  };
+
+  memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
+  auth->SaveUser(user);
+
+  auto privileges = auth_handler.GetPrivileges(user_name);
+  ASSERT_EQ(privileges.size(), 1);
+
+  auto result = *privileges.begin();
+  ASSERT_EQ(result.size(), 3);
+
+  ASSERT_TRUE(result[0].IsString());
+  ASSERT_EQ(result[0].ValueString(), "ALL EDGE_TYPES");
+
+  ASSERT_TRUE(result[1].IsString());
+  ASSERT_EQ(result[1].ValueString(), "READ");
+
+  ASSERT_TRUE(result[2].IsString());
+  ASSERT_EQ(result[2].ValueString(), "GLOBAL EDGE_TYPE PERMISSION GRANTED TO USER");
+}
+
+TEST_F(AuthQueryHandlerFixture, GivenUserWhenGrantedGlobalMultiplePrivilegesOnEdgeTypeThenTopOneIsDisplayed) {
+  auto read_permission = memgraph::auth::FineGrainedAccessPermissions();
+  read_permission.Grant("*", memgraph::auth::FineGrainedPermission::READ);
+  read_permission.Grant("*", memgraph::auth::FineGrainedPermission::UPDATE);
+
+  handler = memgraph::auth::FineGrainedAccessHandler{
+      memgraph::auth::FineGrainedAccessPermissions{},
+      memgraph::auth::FineGrainedAccessPermissions{read_permission},
+
+  };
+
+  memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
+  auth->SaveUser(user);
+
+  auto privileges = auth_handler.GetPrivileges(user_name);
+  ASSERT_EQ(privileges.size(), 1);
+
+  auto result = *privileges.begin();
+  ASSERT_EQ(result.size(), 3);
+
+  ASSERT_TRUE(result[0].IsString());
+  ASSERT_EQ(result[0].ValueString(), "ALL EDGE_TYPES");
+
+  ASSERT_TRUE(result[1].IsString());
+  ASSERT_EQ(result[1].ValueString(), "UPDATE");
+
+  ASSERT_TRUE(result[2].IsString());
+  ASSERT_EQ(result[2].ValueString(), "GLOBAL EDGE_TYPE PERMISSION GRANTED TO USER");
+}
+
+TEST_F(AuthQueryHandlerFixture, GivenUserWhenGrantedGlobalAllPrivilegesOnEdgeTypeThenTopOneIsDisplayed) {
+  auto read_permission = memgraph::auth::FineGrainedAccessPermissions();
+  read_permission.Grant("*", memgraph::auth::FineGrainedPermission::READ);
+  read_permission.Grant("*", memgraph::auth::FineGrainedPermission::UPDATE);
+  read_permission.Grant("*", memgraph::auth::FineGrainedPermission::CREATE_DELETE);
+
+  handler = memgraph::auth::FineGrainedAccessHandler{
+      memgraph::auth::FineGrainedAccessPermissions{},
+      memgraph::auth::FineGrainedAccessPermissions{read_permission},
+  };
+
+  memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
+  auth->SaveUser(user);
+
+  auto privileges = auth_handler.GetPrivileges(user_name);
+  ASSERT_EQ(privileges.size(), 1);
+
+  auto result = *privileges.begin();
+  ASSERT_EQ(result.size(), 3);
+
+  ASSERT_TRUE(result[0].IsString());
+  ASSERT_EQ(result[0].ValueString(), "ALL EDGE_TYPES");
+
+  ASSERT_TRUE(result[1].IsString());
+  ASSERT_EQ(result[1].ValueString(), "CREATE_DELETE");
+
+  ASSERT_TRUE(result[2].IsString());
+  ASSERT_EQ(result[2].ValueString(), "GLOBAL EDGE_TYPE PERMISSION GRANTED TO USER");
+}
+
+TEST_F(AuthQueryHandlerFixture, GivenUserWhenGrantedAndDeniedOnLabelThenNoPermission) {
+  auto read_permission = memgraph::auth::FineGrainedAccessPermissions();
+  read_permission.Grant(label_repr, memgraph::auth::FineGrainedPermission::READ);
+  read_permission.Deny(label_repr, memgraph::auth::FineGrainedPermission::READ);
+
+  handler = memgraph::auth::FineGrainedAccessHandler{
+      memgraph::auth::FineGrainedAccessPermissions{read_permission},
+      memgraph::auth::FineGrainedAccessPermissions{},
+  };
+
+  memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
+  auth->SaveUser(user);
+
+  auto privileges = auth_handler.GetPrivileges(user_name);
+  ASSERT_EQ(privileges.size(), 1);
+
+  auto result = *privileges.begin();
+  ASSERT_EQ(result.size(), 3);
+
+  ASSERT_TRUE(result[0].IsString());
+  ASSERT_EQ(result[0].ValueString(), "LABEL :Label1");
+
+  ASSERT_TRUE(result[1].IsString());
+  ASSERT_EQ(result[1].ValueString(), "NO_PERMISSION");
+
+  ASSERT_TRUE(result[2].IsString());
+  ASSERT_EQ(result[2].ValueString(), "LABEL PERMISSION DENIED TO USER");
+}
+
+TEST_F(AuthQueryHandlerFixture, GivenUserWhenGrantedAndDeniedOnEdgeTypeThenNoPermission) {
+  auto read_permission = memgraph::auth::FineGrainedAccessPermissions();
+  read_permission.Grant(edge_type_repr, memgraph::auth::FineGrainedPermission::READ);
+  read_permission.Deny(edge_type_repr, memgraph::auth::FineGrainedPermission::READ);
+
+  handler = memgraph::auth::FineGrainedAccessHandler{
+      memgraph::auth::FineGrainedAccessPermissions{},
+      memgraph::auth::FineGrainedAccessPermissions{read_permission},
+  };
+
+  memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
+  auth->SaveUser(user);
+
+  auto privileges = auth_handler.GetPrivileges(user_name);
+  ASSERT_EQ(privileges.size(), 1);
+
+  auto result = *privileges.begin();
+  ASSERT_EQ(result.size(), 3);
+
+  ASSERT_TRUE(result[0].IsString());
+  ASSERT_EQ(result[0].ValueString(), "EDGE_TYPE :EdgeType1");
+
+  ASSERT_TRUE(result[1].IsString());
+  ASSERT_EQ(result[1].ValueString(), "NO_PERMISSION");
+
+  ASSERT_TRUE(result[2].IsString());
+  ASSERT_EQ(result[2].ValueString(), "EDGE_TYPE PERMISSION DENIED TO USER");
+}
+
+TEST_F(AuthQueryHandlerFixture, GivenUserWhenGrantedReadAndDeniedUpdateThenOneIsDisplayed) {
+  auto read_permission = memgraph::auth::FineGrainedAccessPermissions();
+  read_permission.Grant(edge_type_repr, memgraph::auth::FineGrainedPermission::READ);
+  read_permission.Deny(edge_type_repr, memgraph::auth::FineGrainedPermission::UPDATE);
+
+  handler = memgraph::auth::FineGrainedAccessHandler{
+      memgraph::auth::FineGrainedAccessPermissions{},
+      memgraph::auth::FineGrainedAccessPermissions{read_permission},
+  };
+
+  memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
+  auth->SaveUser(user);
+
+  auto privileges = auth_handler.GetPrivileges(user_name);
+  ASSERT_EQ(privileges.size(), 1);
+
+  auto result = *privileges.begin();
+  ASSERT_EQ(result.size(), 3);
+
+  ASSERT_TRUE(result[0].IsString());
+  ASSERT_EQ(result[0].ValueString(), "EDGE_TYPE :EdgeType1");
+
+  ASSERT_TRUE(result[1].IsString());
+  ASSERT_EQ(result[1].ValueString(), "READ");
+
+  ASSERT_TRUE(result[2].IsString());
+  ASSERT_EQ(result[2].ValueString(), "EDGE_TYPE PERMISSION GRANTED TO USER");
+}