diff --git a/src/api/admin.rs b/src/api/admin.rs
index dcafaa06..8678e0d9 100644
--- a/src/api/admin.rs
+++ b/src/api/admin.rs
@@ -23,7 +23,7 @@ pub fn routes() -> Vec<Route> {
 
     routes![
         admin_login,
-        get_users,
+        get_users_json,
         post_admin_login,
         admin_page,
         invite_user,
@@ -36,6 +36,9 @@ pub fn routes() -> Vec<Route> {
         delete_config,
         backup_db,
         test_smtp,
+        users_overview,
+        organizations_overview,
+        diagnostics,
     ]
 }
 
@@ -118,7 +121,9 @@ fn _validate_token(token: &str) -> bool {
 struct AdminTemplateData {
     page_content: String,
     version: Option<&'static str>,
-    users: Vec<Value>,
+    users: Option<Vec<Value>>,
+    organizations: Option<Vec<Value>>,
+    diagnostics: Option<Value>,
     config: Value,
     can_backup: bool,
     logged_in: bool,
@@ -126,15 +131,59 @@ struct AdminTemplateData {
 }
 
 impl AdminTemplateData {
-    fn new(users: Vec<Value>) -> Self {
+    fn new() -> Self {
         Self {
-            page_content: String::from("admin/page"),
+            page_content: String::from("admin/settings"),
             version: VERSION,
-            users,
             config: CONFIG.prepare_json(),
             can_backup: *CAN_BACKUP,
             logged_in: true,
             urlpath: CONFIG.domain_path(),
+            users: None,
+            organizations: None,
+            diagnostics: None,
+        }
+    }
+
+    fn users(users: Vec<Value>) -> Self {
+        Self {
+            page_content: String::from("admin/users"),
+            version: VERSION,
+            users: Some(users),
+            config: CONFIG.prepare_json(),
+            can_backup: *CAN_BACKUP,
+            logged_in: true,
+            urlpath: CONFIG.domain_path(),
+            organizations: None,
+            diagnostics: None,
+        }
+    }
+
+    fn organizations(organizations: Vec<Value>) -> Self {
+        Self {
+            page_content: String::from("admin/organizations"),
+            version: VERSION,
+            organizations: Some(organizations),
+            config: CONFIG.prepare_json(),
+            can_backup: *CAN_BACKUP,
+            logged_in: true,
+            urlpath: CONFIG.domain_path(),
+            users: None,
+            diagnostics: None,
+        }
+    }
+
+    fn diagnostics(diagnostics: Value) -> Self {
+        Self {
+            page_content: String::from("admin/diagnostics"),
+            version: VERSION,
+            organizations: None,
+            config: CONFIG.prepare_json(),
+            can_backup: *CAN_BACKUP,
+            logged_in: true,
+            urlpath: CONFIG.domain_path(),
+            users: None,
+            diagnostics: Some(diagnostics),
         }
     }
 
@@ -144,11 +193,8 @@ impl AdminTemplateData {
 }
 
 #[get("/", rank = 1)]
-fn admin_page(_token: AdminToken, conn: DbConn) -> ApiResult<Html<String>> {
-    let users = User::get_all(&conn);
-    let users_json: Vec<Value> = users.iter().map(|u| u.to_json(&conn)).collect();
-
-    let text = AdminTemplateData::new(users_json).render()?;
+fn admin_page(_token: AdminToken, _conn: DbConn) -> ApiResult<Html<String>> {
+    let text = AdminTemplateData::new().render()?;
     Ok(Html(text))
 }
 
@@ -195,13 +241,29 @@ fn logout(mut cookies: Cookies) -> Result<Redirect, ()> {
 }
 
 #[get("/users")]
-fn get_users(_token: AdminToken, conn: DbConn) -> JsonResult {
+fn get_users_json(_token: AdminToken, conn: DbConn) -> JsonResult {
     let users = User::get_all(&conn);
     let users_json: Vec<Value> = users.iter().map(|u| u.to_json(&conn)).collect();
 
     Ok(Json(Value::Array(users_json)))
 }
 
+#[get("/users/overview")]
+fn users_overview(_token: AdminToken, conn: DbConn) -> ApiResult<Html<String>> {
+    let users = User::get_all(&conn);
+    let users_json: Vec<Value> = users.iter()
+    .map(|u| {
+        let mut usr = u.to_json(&conn);
+        if let Some(ciphers) = Cipher::count_owned_by_user(&u.uuid, &conn) {
+            usr["cipher_count"] = json!(ciphers);
+        };
+        usr
+    }).collect();
+
+    let text = AdminTemplateData::users(users_json).render()?;
+    Ok(Html(text))
+}
+
 #[post("/users/<uuid>/delete")]
 fn delete_user(uuid: String, _token: AdminToken, conn: DbConn) -> EmptyResult {
     let user = match User::find_by_uuid(&uuid, &conn) {
@@ -242,6 +304,50 @@ fn update_revision_users(_token: AdminToken, conn: DbConn) -> EmptyResult {
     User::update_all_revisions(&conn)
 }
 
+#[get("/organizations/overview")]
+fn organizations_overview(_token: AdminToken, conn: DbConn) -> ApiResult<Html<String>> {
+    let organizations = Organization::get_all(&conn);
+    let organizations_json: Vec<Value> = organizations.iter().map(|o| o.to_json()).collect();
+
+    let text = AdminTemplateData::organizations(organizations_json).render()?;
+    Ok(Html(text))
+}
+
+#[derive(Deserialize, Serialize, Debug)]
+#[allow(non_snake_case)]
+pub struct WebVaultVersion {
+    version: String,
+}
+
+#[get("/diagnostics")]
+fn diagnostics(_token: AdminToken, _conn: DbConn) -> ApiResult<Html<String>> {
+    use std::net::ToSocketAddrs;
+    use chrono::prelude::*;
+    use crate::util::read_file_string;
+
+    let vault_version_path = format!("{}/{}", CONFIG.web_vault_folder(), "version.json");
+    let vault_version_str = read_file_string(&vault_version_path)?;
+    let web_vault_version: WebVaultVersion = serde_json::from_str(&vault_version_str)?;
+
+    let github_ips = ("github.com", 0).to_socket_addrs().map(|mut i| i.next());
+    let dns_resolved = match github_ips {
+        Ok(Some(a)) => a.ip().to_string() ,
+        _ => "Could not resolve domain name.".to_string(),
+    };
+
+    let dt = Utc::now();
+    let server_time = dt.format("%Y-%m-%d %H:%M:%S").to_string();
+
+    let diagnostics_json = json!({
+        "dns_resolved": dns_resolved,
+        "server_time": server_time,
+        "web_vault_version": web_vault_version.version,
+    });
+
+    let text = AdminTemplateData::diagnostics(diagnostics_json).render()?;
+    Ok(Html(text))
+}
+
 #[post("/config", data = "<data>")]
 fn post_config(data: Json<ConfigBuilder>, _token: AdminToken) -> EmptyResult {
     let data: ConfigBuilder = data.into_inner();
diff --git a/src/api/web.rs b/src/api/web.rs
index 7f47ae7c..a97a1c96 100644
--- a/src/api/web.rs
+++ b/src/api/web.rs
@@ -78,6 +78,7 @@ fn static_files(filename: String) -> Result<Content<&'static [u8]>, Error> {
     match filename.as_ref() {
         "mail-github.png" => Ok(Content(ContentType::PNG, include_bytes!("../static/images/mail-github.png"))),
         "logo-gray.png" => Ok(Content(ContentType::PNG, include_bytes!("../static/images/logo-gray.png"))),
+        "shield-white.png" => Ok(Content(ContentType::PNG, include_bytes!("../static/images/shield-white.png"))),
         "error-x.svg" => Ok(Content(ContentType::SVG, include_bytes!("../static/images/error-x.svg"))),
         "hibp.png" => Ok(Content(ContentType::PNG, include_bytes!("../static/images/hibp.png"))),
 
diff --git a/src/config.rs b/src/config.rs
index 9434c39a..e5b46d37 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -700,7 +700,10 @@ where
 
     reg!("admin/base");
     reg!("admin/login");
-    reg!("admin/page");
+    reg!("admin/settings");
+    reg!("admin/users");
+    reg!("admin/organizations");
+    reg!("admin/diagnostics");
 
     // And then load user templates to overwrite the defaults
     // Use .hbs extension for the files
diff --git a/src/db/models/cipher.rs b/src/db/models/cipher.rs
index 1e717ca4..94d7d1ec 100644
--- a/src/db/models/cipher.rs
+++ b/src/db/models/cipher.rs
@@ -355,6 +355,14 @@ impl Cipher {
         .load::<Self>(&**conn).expect("Error loading ciphers")
     }
 
+    pub fn count_owned_by_user(user_uuid: &str, conn: &DbConn) -> Option<i64> {
+        ciphers::table
+        .filter(ciphers::user_uuid.eq(user_uuid))
+        .count()
+        .first::<i64>(&**conn)
+        .ok()
+    }
+
     pub fn find_by_org(org_uuid: &str, conn: &DbConn) -> Vec<Self> {
         ciphers::table
             .filter(ciphers::organization_uuid.eq(org_uuid))
diff --git a/src/db/models/organization.rs b/src/db/models/organization.rs
index 442d1969..8ce476c6 100644
--- a/src/db/models/organization.rs
+++ b/src/db/models/organization.rs
@@ -255,6 +255,10 @@ impl Organization {
             .first::<Self>(&**conn)
             .ok()
     }
+
+    pub fn get_all(conn: &DbConn) -> Vec<Self> {
+        organizations::table.load::<Self>(&**conn).expect("Error loading organizations")
+    }
 }
 
 impl UserOrganization {
diff --git a/src/static/images/logo-gray.png b/src/static/images/logo-gray.png
index b045df54..70658e18 100644
Binary files a/src/static/images/logo-gray.png and b/src/static/images/logo-gray.png differ
diff --git a/src/static/images/shield-white.png b/src/static/images/shield-white.png
new file mode 100644
index 00000000..3400efe7
Binary files /dev/null and b/src/static/images/shield-white.png differ
diff --git a/src/static/templates/admin/base.hbs b/src/static/templates/admin/base.hbs
index e3948d06..a7270b9c 100644
--- a/src/static/templates/admin/base.hbs
+++ b/src/static/templates/admin/base.hbs
@@ -29,16 +29,79 @@
             width: 48px;
             height: 48px;
         }
+
+        .navbar img {
+            height: 24px;
+            width: auto;
+        }
     </style>
+    <script>
+        function reload() { window.location.reload(); }
+        function msg(text, reload_page = true) {
+            text && alert(text);
+            reload_page && reload();
+        }
+        function identicon(email) {
+            const data = new Identicon(md5(email), { size: 48, format: 'svg' });
+            return "data:image/svg+xml;base64," + data.toString();
+        }
+        function toggleVis(input_id) {
+            const elem = document.getElementById(input_id);
+            const type = elem.getAttribute("type");
+            if (type === "text") {
+                elem.setAttribute("type", "password");
+            } else {
+                elem.setAttribute("type", "text");
+            }
+            return false;
+        }
+        function _post(url, successMsg, errMsg, body, reload_page = true) {
+            fetch(url, {
+                method: 'POST',
+                body: body,
+                mode: "same-origin",
+                credentials: "same-origin",
+                headers: { "Content-Type": "application/json" }
+            }).then( resp => {
+                if (resp.ok) { msg(successMsg, reload_page); return Promise.reject({error: false}); }
+                respStatus = resp.status;
+                respStatusText = resp.statusText;
+                return resp.text();
+            }).then( respText => {
+                try {
+                    const respJson = JSON.parse(respText);
+                    return respJson ? respJson.ErrorModel.Message : "Unknown error";
+                } catch (e) {
+                    return Promise.reject({body:respStatus + ' - ' + respStatusText, error: true});
+                }
+            }).then( apiMsg => {
+                msg(errMsg + "\n" + apiMsg, reload_page);
+            }).catch( e => {
+                if (e.error === false) { return true; }
+                else { msg(errMsg + "\n" + e.body, reload_page); }
+            });
+        }
+    </script>
+
 </head>
 
 <body class="bg-light">
-    <nav class="navbar navbar-expand-sm navbar-dark bg-dark fixed-top shadow">
-        <a class="navbar-brand" href="#">Bitwarden_rs</a>
+    <nav class="navbar navbar-expand-sm navbar-dark bg-dark fixed-top shadow mb-4">
+    <div class="container">
+        <a class="navbar-brand" href="{{urlpath}}/admin"><img class="pr-1" src="{{urlpath}}/bwrs_static/shield-white.png">Bitwarden_rs Admin</a>
         <div class="navbar-collapse">
             <ul class="navbar-nav">
-                <li class="nav-item active">
-                    <a class="nav-link" href="{{urlpath}}/admin">Admin Panel</a>
+                <li class="nav-item">
+                    <a class="nav-link" href="{{urlpath}}/admin">Settings</a>
+                </li>
+                <li class="nav-item">
+                    <a class="nav-link" href="{{urlpath}}/admin/users/overview">Users</a>
+                </li>
+                <li class="nav-item">
+                    <a class="nav-link" href="{{urlpath}}/admin/organizations/overview">Organizations</a>
+                </li>
+                <li class="nav-item">
+                    <a class="nav-link" href="{{urlpath}}/admin/diagnostics">Diagnostics</a>
                 </li>
                 <li class="nav-item">
                     <a class="nav-link" href="{{urlpath}}/">Vault</a>
@@ -54,14 +117,27 @@
             {{/if}}
 
             {{#if logged_in}}
-            <li class="nav-item">
+            <li class="nav-item rounded btn-secondary">
                 <a class="nav-link" href="{{urlpath}}/admin/logout">Log Out</a>
             </li>
             {{/if}}
         </ul>
+    </div>
     </nav>
 
     {{> (page_content) }}
+
+    <script>
+        // get current URL path and assign 'active' class to the correct nav-item
+        (function () {
+            var pathname = window.location.pathname;
+            if (pathname === "") return;
+            var navItem = document.querySelectorAll('.navbar-nav .nav-item a[href="'+pathname+'"]');
+            if (navItem.length === 1) {
+                navItem[0].parentElement.className = navItem[0].parentElement.className + ' active';
+            }
+        })();
+    </script>
 </body>
 
-</html>
+</html>
\ No newline at end of file
diff --git a/src/static/templates/admin/diagnostics.hbs b/src/static/templates/admin/diagnostics.hbs
new file mode 100644
index 00000000..dbf82c1e
--- /dev/null
+++ b/src/static/templates/admin/diagnostics.hbs
@@ -0,0 +1,73 @@
+<main class="container">
+    <div id="diagnostics-block" class="my-3 p-3 bg-white rounded shadow">
+        <h6 class="border-bottom pb-2 mb-2">Diagnostics</h6>
+
+        <h3>Version</h3>
+        <div class="row">
+            <div class="col-md">
+                <dl class="row">
+                    <dt class="col-sm-5">Server Installed</dt>
+                    <dd class="col-sm-7">
+                        <span id="server-installed">{{version}}</span>
+                    </dd>
+                    <dt class="col-sm-5">Web Installed</dt>
+                    <dd class="col-sm-7">
+                        <span id="web-installed">{{diagnostics.web_vault_version}}</span>
+                    </dd>
+                </dl>
+            </div>
+        </div>
+
+        <h3>Checks</h3>
+        <div class="row">
+            <div class="col-md">
+                <dl class="row">
+                    <dt class="col-sm-5">DNS (github.com)
+                        <span class="badge badge-success d-none" id="dns-success" title="DNS Resolving works!">Ok</span>
+                        <span class="badge badge-danger d-none" id="dns-warning" title="DNS Resolving failed. Please fix.">Error</span>
+                    </dt>
+                    <dd class="col-sm-7">
+                        <span id="dns-resolved">{{diagnostics.dns_resolved}}</span>
+                    </dd>
+
+                    <dt class="col-sm-5">Date & Time (UTC)
+                        <span class="badge badge-success d-none" id="time-success" title="Time offsets seem to be correct.">Ok</span>
+                        <span class="badge badge-danger d-none" id="time-warning" title="Time offsets are too mouch at drift.">Error</span>
+                    </dt>
+                    <dd class="col-sm-7">
+                        <span id="time-server" class="d-block"><b>Server:</b> <span id="time-server-string">{{diagnostics.server_time}}</span></span>
+                        <span id="time-browser" class="d-block"><b>Browser:</b> <span id="time-browser-string"></span></span>
+                    </dd>
+                </dl>
+            </div>
+        </div>
+    </div>
+</main>
+
+<script>
+    const d = new Date();
+    const year = d.getUTCFullYear();
+    const month = String((d.getUTCMonth()+1)).padStart(2, '0');
+    const day = String(d.getUTCDate()).padStart(2, '0');
+    const hour = String(d.getUTCHours()).padStart(2, '0');
+    const minute = String(d.getUTCMinutes()).padStart(2, '0');
+    const seconds = String(d.getUTCSeconds()).padStart(2, '0');
+    const browserUTC = year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + seconds;
+    document.getElementById("time-browser-string").innerText = browserUTC;
+
+    const serverUTC = document.getElementById("time-server-string").innerText;
+    const timeDrift = (Date.parse(serverUTC) - Date.parse(browserUTC)) / 1000;
+    if (timeDrift > 30 || timeDrift < -30) {
+        document.getElementById('time-warning').classList.remove('d-none');
+    } else {
+        document.getElementById('time-success').classList.remove('d-none');
+    }
+
+    // Check if the output is a valid IP
+    const isValidIp = value => (/^(?:(?:^|\.)(?:2(?:5[0-5]|[0-4]\d)|1?\d?\d)){4}$/.test(value) ? true : false);
+    if (isValidIp(document.getElementById('dns-resolved').innerText)) {
+        document.getElementById('dns-success').classList.remove('d-none');
+    } else {
+        document.getElementById('dns-warning').classList.remove('d-none');
+    }
+</script>
\ No newline at end of file
diff --git a/src/static/templates/admin/organizations.hbs b/src/static/templates/admin/organizations.hbs
new file mode 100644
index 00000000..6dbcbbbf
--- /dev/null
+++ b/src/static/templates/admin/organizations.hbs
@@ -0,0 +1,30 @@
+<main class="container">
+    <div id="organizations-block" class="my-3 p-3 bg-white rounded shadow">
+        <h6 class="border-bottom pb-2 mb-0">Organizations</h6>
+
+        <div id="organizations-list">
+            {{#each organizations}}
+            <div class="media pt-3">
+                <img class="mr-2 rounded identicon" data-src="{{Name}}_{{BillingEmail}}">
+                <div class="media-body pb-3 mb-0 small border-bottom">
+                    <div class="row justify-content-between">
+                        <div class="col">
+                            <strong>{{Name}}</strong>
+                            {{#if Id}}
+                            <span class="badge badge-success ml-2">{{Id}}</span>
+                            {{/if}}
+                            <span class="d-block">{{BillingEmail}}</span>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            {{/each}}
+        </div>
+    </div>
+</main>
+
+<script>
+    document.querySelectorAll("img.identicon").forEach(function (e, i) {
+        e.src = identicon(e.dataset.src);
+    });
+</script>
\ No newline at end of file
diff --git a/src/static/templates/admin/page.hbs b/src/static/templates/admin/settings.hbs
similarity index 60%
rename from src/static/templates/admin/page.hbs
rename to src/static/templates/admin/settings.hbs
index 0560bde5..eb3c74e3 100644
--- a/src/static/templates/admin/page.hbs
+++ b/src/static/templates/admin/settings.hbs
@@ -1,68 +1,4 @@
 <main class="container">
-    <div id="users-block" class="my-3 p-3 bg-white rounded shadow">
-        <h6 class="border-bottom pb-2 mb-0">Registered Users</h6>
-
-        <div id="users-list">
-            {{#each users}}
-            <div class="media pt-3">
-                <img class="mr-2 rounded identicon" data-src="{{Email}}">
-                <div class="media-body pb-3 mb-0 small border-bottom">
-                    <div class="row justify-content-between">
-                        <div class="col">
-                            <strong>{{Name}}</strong>
-                            {{#if TwoFactorEnabled}}
-                            <span class="badge badge-success ml-2">2FA</span>
-                            {{/if}}
-                            {{#case _Status 1}}
-                            <span class="badge badge-warning ml-2">Invited</span>
-                            {{/case}}
-                            <span class="d-block">{{Email}}</span>
-                        </div>
-                        <div class="col">
-                            <strong> Organizations: </strong>
-                            <span class="d-block">
-                                {{#each Organizations}}
-                                <span class="badge badge-primary" data-orgtype="{{Type}}">{{Name}}</span>
-                                {{/each}}
-                            </span>
-                        </div>
-                        <div style="flex: 0 0 300px; font-size: 90%; text-align: right; padding-right: 15px">
-                            {{#if TwoFactorEnabled}}
-                            <a class="mr-2" href="#" onclick='remove2fa({{jsesc Id}})'>Remove all 2FA</a>
-                            {{/if}}
-
-                            <a class="mr-2" href="#" onclick='deauthUser({{jsesc Id}})'>Deauthorize sessions</a>
-                            <a class="mr-2" href="#" onclick='deleteUser({{jsesc Id}}, {{jsesc Email}})'>Delete User</a>
-                        </div>
-                    </div>
-                </div>
-            </div>
-            {{/each}}
-
-        </div>
-
-        <div class="mt-3">
-            <button type="button" class="btn btn-sm btn-link" onclick="updateRevisions();"
-                title="Force all clients to fetch new data next time they connect. Useful after restoring a backup to remove any stale data.">
-                Force clients to resync
-            </button>
-
-            <button type="button" class="btn btn-sm btn-primary float-right" onclick="reload();">Reload users</button>
-        </div>
-    </div>
-
-    <div id="invite-form-block" class="align-items-center p-3 mb-3 text-white-50 bg-secondary rounded shadow">
-        <div>
-            <h6 class="mb-0 text-white">Invite User</h6>
-            <small>Email:</small>
-
-            <form class="form-inline" id="invite-form" onsubmit="inviteUser(); return false;">
-                <input type="email" class="form-control w-50 mr-2" id="email-invite" placeholder="Enter email">
-                <button type="submit" class="btn btn-primary">Invite</button>
-            </form>
-        </div>
-    </div>
-
     <div id="config-block" class="align-items-center p-3 mb-3 bg-secondary rounded shadow">
         <div>
             <h6 class="text-white mb-3">Configuration</h6>
@@ -202,90 +138,6 @@
 </style>
 
 <script>
-    function reload() { window.location.reload(); }
-    function msg(text, reload_page = true) {
-        text && alert(text);
-        reload_page && reload();
-    }
-    function identicon(email) {
-        const data = new Identicon(md5(email), { size: 48, format: 'svg' });
-        return "data:image/svg+xml;base64," + data.toString();
-    }
-    function toggleVis(input_id) {
-        const elem = document.getElementById(input_id);
-        const type = elem.getAttribute("type");
-        if (type === "text") {
-            elem.setAttribute("type", "password");
-        } else {
-            elem.setAttribute("type", "text");
-        }
-        return false;
-    }
-    function _post(url, successMsg, errMsg, body, reload_page = true) {
-        fetch(url, {
-            method: 'POST',
-            body: body,
-            mode: "same-origin",
-            credentials: "same-origin",
-            headers: { "Content-Type": "application/json" }
-        }).then( resp => {
-            if (resp.ok) { msg(successMsg, reload_page); return Promise.reject({error: false}); }
-            respStatus = resp.status;
-            respStatusText = resp.statusText;
-            return resp.text();
-        }).then( respText => {
-            try {
-                const respJson = JSON.parse(respText);
-                return respJson ? respJson.ErrorModel.Message : "Unknown error";
-            } catch (e) {
-                return Promise.reject({body:respStatus + ' - ' + respStatusText, error: true});
-            }
-        }).then( apiMsg => {
-            msg(errMsg + "\n" + apiMsg, reload_page);
-        }).catch( e => {
-            if (e.error === false) { return true; }
-            else { msg(errMsg + "\n" + e.body, reload_page); }
-        });
-    }
-    function deleteUser(id, mail) {
-        var input_mail = prompt("To delete user '" + mail + "', please type the email below")
-        if (input_mail != null) {
-            if (input_mail == mail) {
-                _post("{{urlpath}}/admin/users/" + id + "/delete",
-                    "User deleted correctly",
-                    "Error deleting user");
-            } else {
-                alert("Wrong email, please try again")
-            }
-        }
-        return false;
-    }
-    function remove2fa(id) {
-        _post("{{urlpath}}/admin/users/" + id + "/remove-2fa",
-            "2FA removed correctly",
-            "Error removing 2FA");
-        return false;
-    }
-    function deauthUser(id) {
-        _post("{{urlpath}}/admin/users/" + id + "/deauth",
-            "Sessions deauthorized correctly",
-            "Error deauthorizing sessions");
-        return false;
-    }
-    function updateRevisions() {
-        _post("{{urlpath}}/admin/users/update_revision",
-            "Success, clients will sync next time they connect",
-            "Error forcing clients to sync");
-        return false;
-    }
-    function inviteUser() {
-        inv = document.getElementById("email-invite");
-        data = JSON.stringify({ "email": inv.value });
-        inv.value = "";
-        _post("{{urlpath}}/admin/invite/", "User invited correctly",
-            "Error inviting user", data);
-        return false;
-    }
     function smtpTest() {
         test_email = document.getElementById("smtp-test-email");
         data = JSON.stringify({ "email": test_email.value });
@@ -348,23 +200,6 @@
         onChange(); // Trigger the event initially
         checkbox.addEventListener("change", onChange);
     }
-    let OrgTypes = {
-        "0": { "name": "Owner", "color": "orange" },
-        "1": { "name": "Admin", "color": "blueviolet" },
-        "2": { "name": "User", "color": "blue" },
-        "3": { "name": "Manager", "color": "green" },
-    };
-
-    document.querySelectorAll("img.identicon").forEach(function (e, i) {
-        e.src = identicon(e.dataset.src);
-    });
-
-    document.querySelectorAll("[data-orgtype]").forEach(function (e, i) {
-        let orgtype = OrgTypes[e.dataset.orgtype];
-        e.style.backgroundColor = orgtype.color;
-        e.title = orgtype.name;
-    });
-
     // These are formatted because otherwise the
     // VSCode formatter breaks But they still work
     // {{#each config}} {{#if grouptoggle}}
diff --git a/src/static/templates/admin/users.hbs b/src/static/templates/admin/users.hbs
new file mode 100644
index 00000000..d3e12f78
--- /dev/null
+++ b/src/static/templates/admin/users.hbs
@@ -0,0 +1,134 @@
+<main class="container">
+    <div id="users-block" class="my-3 p-3 bg-white rounded shadow">
+        <h6 class="border-bottom pb-2 mb-0">Registered Users</h6>
+
+        <div id="users-list">
+            {{#each users}}
+            <div class="media pt-3">
+                <img class="mr-2 rounded identicon" data-src="{{Email}}">
+                <div class="media-body pb-3 mb-0 small border-bottom">
+                    <div class="row justify-content-between">
+                        <div class="col">
+                            <strong>{{Name}}</strong>
+                            {{#if TwoFactorEnabled}}
+                            <span class="badge badge-success ml-2">2FA</span>
+                            {{/if}}
+                            {{#case _Status 1}}
+                            <span class="badge badge-warning ml-2">Invited</span>
+                            {{/case}}
+                            <span class="d-block">{{Email}}
+                                {{#if EmailVerified}}
+                                <span class="badge badge-success ml-2">Verified</span>
+                                {{/if}}
+                            </span>
+                        </div>
+                        <div class="col">
+                            <strong> Personal Items: </strong>
+                            <span class="d-block">
+                                {{cipher_count}}
+                            </span>
+                        </div>
+                        <div class="col-4">
+                            <strong> Organizations: </strong>
+                            <span class="d-block">
+                                {{#each Organizations}}
+                                <span class="badge badge-primary" data-orgtype="{{Type}}">{{Name}}</span>
+                                {{/each}}
+                            </span>
+                        </div>
+                        <div class="col" style="font-size: 90%; text-align: right; padding-right: 15px">
+                            {{#if TwoFactorEnabled}}
+                            <a class="mr-2" href="#" onclick='remove2fa({{jsesc Id}})'>Remove all 2FA</a>
+                            {{/if}}
+
+                            <a class="mr-2" href="#" onclick='deauthUser({{jsesc Id}})'>Deauthorize sessions</a>
+                            <a class="mr-2" href="#" onclick='deleteUser({{jsesc Id}}, {{jsesc Email}})'>Delete User</a>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            {{/each}}
+
+        </div>
+
+        <div class="mt-3">
+            <button type="button" class="btn btn-sm btn-link" onclick="updateRevisions();"
+                title="Force all clients to fetch new data next time they connect. Useful after restoring a backup to remove any stale data.">
+                Force clients to resync
+            </button>
+
+            <button type="button" class="btn btn-sm btn-primary float-right" onclick="reload();">Reload users</button>
+        </div>
+    </div>
+
+    <div id="invite-form-block" class="align-items-center p-3 mb-3 text-white-50 bg-secondary rounded shadow">
+        <div>
+            <h6 class="mb-0 text-white">Invite User</h6>
+            <small>Email:</small>
+
+            <form class="form-inline" id="invite-form" onsubmit="inviteUser(); return false;">
+                <input type="email" class="form-control w-50 mr-2" id="email-invite" placeholder="Enter email">
+                <button type="submit" class="btn btn-primary">Invite</button>
+            </form>
+        </div>
+    </div>
+</main>
+
+<script>
+    function deleteUser(id, mail) {
+        var input_mail = prompt("To delete user '" + mail + "', please type the email below")
+        if (input_mail != null) {
+            if (input_mail == mail) {
+                _post("{{urlpath}}/admin/users/" + id + "/delete",
+                    "User deleted correctly",
+                    "Error deleting user");
+            } else {
+                alert("Wrong email, please try again")
+            }
+        }
+        return false;
+    }
+    function remove2fa(id) {
+        _post("{{urlpath}}/admin/users/" + id + "/remove-2fa",
+            "2FA removed correctly",
+            "Error removing 2FA");
+        return false;
+    }
+    function deauthUser(id) {
+        _post("{{urlpath}}/admin/users/" + id + "/deauth",
+            "Sessions deauthorized correctly",
+            "Error deauthorizing sessions");
+        return false;
+    }
+    function updateRevisions() {
+        _post("{{urlpath}}/admin/users/update_revision",
+            "Success, clients will sync next time they connect",
+            "Error forcing clients to sync");
+        return false;
+    }
+    function inviteUser() {
+        inv = document.getElementById("email-invite");
+        data = JSON.stringify({ "email": inv.value });
+        inv.value = "";
+        _post("{{urlpath}}/admin/invite/", "User invited correctly",
+            "Error inviting user", data);
+        return false;
+    }
+
+    let OrgTypes = {
+        "0": { "name": "Owner", "color": "orange" },
+        "1": { "name": "Admin", "color": "blueviolet" },
+        "2": { "name": "User", "color": "blue" },
+        "3": { "name": "Manager", "color": "green" },
+    };
+
+    document.querySelectorAll("img.identicon").forEach(function (e, i) {
+        e.src = identicon(e.dataset.src);
+    });
+
+    document.querySelectorAll("[data-orgtype]").forEach(function (e, i) {
+        let orgtype = OrgTypes[e.dataset.orgtype];
+        e.style.backgroundColor = orgtype.color;
+        e.title = orgtype.name;
+    });
+</script>
\ No newline at end of file