diff --git a/Cargo.lock b/Cargo.lock
index 91babf35dea4ff578d3b02086eef64e08f8043fb..9e8c5de6280e447abf18f1dede22aab14bcb0d2e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1885,7 +1885,7 @@ dependencies = [
 
 [[package]]
 name = "revolt"
-version = "0.2.5"
+version = "0.2.6"
 dependencies = [
  "bcrypt",
  "bitfield",
diff --git a/Cargo.toml b/Cargo.toml
index 13e8c78b43ecf258606a0a245fd26e8ff7370409..fa70586c4d7de616d7825eb3211adb3904328f53 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "revolt"
-version = "0.2.5"
+version = "0.2.6"
 authors = ["Paul Makles <paulmakles@gmail.com>"]
 edition = "2018"
 
diff --git a/src/database/permissions.rs b/src/database/permissions.rs
index 37d35f7f8da2e37dd566adbb542c792a96e7fc34..19bdb893e59edd8af0b0adf5db902b099172f87f 100644
--- a/src/database/permissions.rs
+++ b/src/database/permissions.rs
@@ -1,8 +1,7 @@
 use super::mutual::has_mutual_connection;
 use crate::database::channel::Channel;
 use crate::database::guild::{fetch_guild, fetch_member, Guild, Member, MemberKey};
-use crate::database::user::UserRelationship;
-use crate::guards::auth::UserRef;
+use crate::database::user::{User, UserRelationship};
 
 use num_enum::TryFromPrimitive;
 
@@ -77,23 +76,23 @@ pub fn get_relationship_internal(
     Relationship::NONE
 }
 
-pub fn get_relationship(a: &UserRef, b: &UserRef) -> Relationship {
+pub fn get_relationship(a: &User, b: &User) -> Relationship {
     if a.id == b.id {
         return Relationship::SELF;
     }
 
-    get_relationship_internal(&a.id, &b.id, &a.fetch_relationships())
+    get_relationship_internal(&a.id, &b.id, &a.relations)
 }
 
 pub struct PermissionCalculator {
-    pub user: UserRef,
+    pub user: User,
     pub channel: Option<Channel>,
     pub guild: Option<Guild>,
     pub member: Option<Member>,
 }
 
 impl PermissionCalculator {
-    pub fn new(user: UserRef) -> PermissionCalculator {
+    pub fn new(user: User) -> PermissionCalculator {
         PermissionCalculator {
             user,
             channel: None,
@@ -174,9 +173,8 @@ impl PermissionCalculator {
                         }
 
                         if let Some(other) = other_user {
-                            let relationships = self.user.fetch_relationships();
                             let relationship =
-                                get_relationship_internal(&self.user.id, &other, &relationships);
+                                get_relationship_internal(&self.user.id, &other, &self.user.relations);
     
                             if relationship == Relationship::Friend {
                                 permissions = 1024 + 128 + 32 + 16 + 1;
diff --git a/src/database/user.rs b/src/database/user.rs
index 990fc5fb1844ad2cecba61d8417d522d978d90ca..96e82f97d5f838e0af9a45d14a0cf266e656e157 100644
--- a/src/database/user.rs
+++ b/src/database/user.rs
@@ -1,4 +1,11 @@
-use mongodb::bson::DateTime;
+use super::get_collection;
+
+use lru::LruCache;
+use mongodb::bson::{doc, from_bson, Bson, DateTime};
+use rocket::http::{RawStr, Status};
+use rocket::request::{self, FromParam, FromRequest, Request};
+use rocket::Outcome;
+use std::sync::{Arc, Mutex};
 use serde::{Deserialize, Serialize};
 
 #[derive(Serialize, Deserialize, Debug, Clone)]
@@ -28,3 +35,98 @@ pub struct User {
     pub email_verification: UserEmailVerification,
     pub relations: Option<Vec<UserRelationship>>,
 }
+
+lazy_static! {
+    static ref CACHE: Arc<Mutex<LruCache<String, User>>> =
+        Arc::new(Mutex::new(LruCache::new(4_000_000)));
+}
+
+pub fn fetch_user(id: &str) -> Result<Option<User>, String> {
+    {
+        if let Ok(mut cache) = CACHE.lock() {
+            let existing = cache.get(&id.to_string());
+
+            if let Some(user) = existing {
+                return Ok(Some((*user).clone()));
+            }
+        } else {
+            return Err("Failed to lock cache.".to_string());
+        }
+    }
+
+    let col = get_collection("users");
+    if let Ok(result) = col.find_one(doc! { "_id": id }, None) {
+        if let Some(doc) = result {
+            if let Ok(user) = from_bson(Bson::Document(doc)) as Result<User, _> {
+                let mut cache = CACHE.lock().unwrap();
+                cache.put(id.to_string(), user.clone());
+
+                Ok(Some(user))
+            } else {
+                Err("Failed to deserialize user!".to_string())
+            }
+        } else {
+            Ok(None)
+        }
+    } else {
+        Err("Failed to fetch user from database.".to_string())
+    }
+}
+
+#[derive(Debug)]
+pub enum AuthError {
+    Failed,
+    Missing,
+    Invalid,
+}
+
+impl<'a, 'r> FromRequest<'a, 'r> for User {
+    type Error = AuthError;
+
+    fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> {
+        let u = request.headers().get("x-user").next();
+        let t = request.headers().get("x-auth-token").next();
+
+        if let Some(uid) = u {
+            if let Some(token) = t {
+                if let Ok(result) = fetch_user(uid) {
+                    if let Some(user) = result {
+                        if let Some(access_token) = &user.access_token {
+                            if access_token == token {
+                                Outcome::Success(user)
+                            } else {
+                                Outcome::Failure((Status::Forbidden, AuthError::Invalid))
+                            }
+                        } else {
+                            Outcome::Failure((Status::Forbidden, AuthError::Invalid))
+                        }
+                    } else {
+                        Outcome::Failure((Status::Forbidden, AuthError::Invalid))
+                    }
+                } else {
+                    Outcome::Failure((Status::Forbidden, AuthError::Failed))
+                }
+            } else {
+                Outcome::Failure((Status::Forbidden, AuthError::Missing))
+            }
+        } else {
+            Outcome::Failure((Status::Forbidden, AuthError::Missing))
+        }
+    }
+}
+
+impl<'r> FromParam<'r> for User {
+    type Error = &'r RawStr;
+
+    fn from_param(param: &'r RawStr) -> Result<Self, Self::Error> {
+        if let Ok(result) = fetch_user(&param.to_string()) {
+            if let Some(user) = result {
+                Ok(user)
+            } else {
+                Err(param)
+            }
+        } else {
+            Err(param)
+        }
+    }
+}
diff --git a/src/guards/auth.rs b/src/guards/auth.rs
deleted file mode 100644
index 35e9e7ae74fa489cebe047d8742846de1462beb2..0000000000000000000000000000000000000000
--- a/src/guards/auth.rs
+++ /dev/null
@@ -1,167 +0,0 @@
-use mongodb::bson::{doc, from_bson, Bson, Document};
-use mongodb::options::FindOneOptions;
-use rocket::http::{RawStr, Status};
-use rocket::request::{self, FromParam, FromRequest, Request};
-use rocket::Outcome;
-use serde::{Deserialize, Serialize};
-
-use crate::database;
-use database::user::{User, UserRelationship};
-
-#[derive(Serialize, Deserialize, Debug, Clone)]
-pub struct UserRef {
-    pub id: String,
-    pub username: String,
-    pub display_name: String,
-    pub email_verified: bool,
-}
-
-impl UserRef {
-    pub fn from(id: String) -> Option<UserRef> {
-        match database::get_collection("users").find_one(
-            doc! { "_id": id },
-            FindOneOptions::builder()
-                .projection(doc! {
-                    "_id": 1,
-                    "username": 1,
-                    "display_name": 1,
-                    "email_verification.verified": 1,
-                })
-                .build(),
-        ) {
-            Ok(result) => match result {
-                Some(doc) => Some(UserRef {
-                    id: doc.get_str("_id").unwrap().to_string(),
-                    username: doc.get_str("username").unwrap().to_string(),
-                    display_name: doc.get_str("display_name").unwrap().to_string(),
-                    email_verified: doc
-                        .get_document("email_verification")
-                        .unwrap()
-                        .get_bool("verified")
-                        .unwrap(),
-                }),
-                None => None,
-            },
-            Err(_) => None,
-        }
-    }
-
-    pub fn fetch_data(&self, projection: Document) -> Option<Document> {
-        database::get_collection("users")
-            .find_one(
-                doc! { "_id": &self.id },
-                FindOneOptions::builder().projection(projection).build(),
-            )
-            .expect("Failed to fetch user from database.")
-    }
-
-    pub fn fetch_relationships(&self) -> Option<Vec<UserRelationship>> {
-        let user = database::get_collection("users")
-            .find_one(
-                doc! { "_id": &self.id },
-                FindOneOptions::builder()
-                    .projection(doc! { "relations": 1 })
-                    .build(),
-            )
-            .expect("Failed to fetch user relationships from database.")
-            .expect("Missing user document.");
-
-        if let Ok(arr) = user.get_array("relations") {
-            let mut relationships = vec![];
-            for item in arr {
-                relationships.push(from_bson(item.clone()).unwrap());
-            }
-
-            Some(relationships)
-        } else {
-            None
-        }
-    }
-}
-
-#[derive(Debug)]
-pub enum AuthError {
-    BadCount,
-    Missing,
-    Invalid,
-}
-
-impl<'a, 'r> FromRequest<'a, 'r> for UserRef {
-    type Error = AuthError;
-
-    fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> {
-        let keys: Vec<_> = request.headers().get("x-auth-token").collect();
-        match keys.len() {
-            0 => Outcome::Failure((Status::Forbidden, AuthError::Missing)),
-            1 => {
-                let key = keys[0];
-                let result = database::get_collection("users")
-                    .find_one(
-                        doc! { "access_token": key },
-                        FindOneOptions::builder()
-                            .projection(doc! {
-                                "_id": 1,
-                                "username": 1,
-                                "display_name": 1,
-                                "email_verification.verified": 1,
-                            })
-                            .build(),
-                    )
-                    .unwrap();
-
-                if let Some(user) = result {
-                    Outcome::Success(UserRef {
-                        id: user.get_str("_id").unwrap().to_string(),
-                        username: user.get_str("username").unwrap().to_string(),
-                        display_name: user.get_str("display_name").unwrap().to_string(),
-                        email_verified: user
-                            .get_document("email_verification")
-                            .unwrap()
-                            .get_bool("verified")
-                            .unwrap(),
-                    })
-                } else {
-                    Outcome::Failure((Status::Forbidden, AuthError::Invalid))
-                }
-            }
-            _ => Outcome::Failure((Status::BadRequest, AuthError::BadCount)),
-        }
-    }
-}
-
-impl<'a, 'r> FromRequest<'a, 'r> for User {
-    type Error = AuthError;
-
-    fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> {
-        let keys: Vec<_> = request.headers().get("x-auth-token").collect();
-        match keys.len() {
-            0 => Outcome::Failure((Status::Forbidden, AuthError::Missing)),
-            1 => {
-                let key = keys[0];
-                let col = database::get_collection("users");
-                let result = col.find_one(doc! { "access_token": key }, None).unwrap();
-
-                if let Some(user) = result {
-                    Outcome::Success(
-                        from_bson(Bson::Document(user)).expect("Failed to unwrap user."),
-                    )
-                } else {
-                    Outcome::Failure((Status::Forbidden, AuthError::Invalid))
-                }
-            }
-            _ => Outcome::Failure((Status::BadRequest, AuthError::BadCount)),
-        }
-    }
-}
-
-impl<'r> FromParam<'r> for UserRef {
-    type Error = &'r RawStr;
-
-    fn from_param(param: &'r RawStr) -> Result<Self, Self::Error> {
-        if let Some(user) = UserRef::from(param.to_string()) {
-            Ok(user)
-        } else {
-            Err(param)
-        }
-    }
-}
diff --git a/src/guards/mod.rs b/src/guards/mod.rs
deleted file mode 100644
index 0e4a05d5978fdf631991d0c4a5266089cb083bd3..0000000000000000000000000000000000000000
--- a/src/guards/mod.rs
+++ /dev/null
@@ -1 +0,0 @@
-pub mod auth;
diff --git a/src/main.rs b/src/main.rs
index 0acea35b37e6623857b37aeda16452075a29156d..b220a022712ddfe5643613187cbb1607ec89894f 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -9,11 +9,10 @@ extern crate bitfield;
 #[macro_use]
 extern crate lazy_static;
 
-pub mod database;
-pub mod email;
-pub mod guards;
 pub mod notifications;
+pub mod database;
 pub mod routes;
+pub mod email;
 pub mod util;
 
 use dotenv;
diff --git a/src/routes/channel.rs b/src/routes/channel.rs
index 5a0a7210f7f32f85ee5bb3b0b60872a860470c58..5d79050e4a96e4b1395a66fb0c085f03ff829dde 100644
--- a/src/routes/channel.rs
+++ b/src/routes/channel.rs
@@ -1,9 +1,8 @@
 use super::Response;
 use crate::database::{
     self, channel::Channel, get_relationship, get_relationship_internal, message::Message,
-    Permission, PermissionCalculator, Relationship,
+    Permission, PermissionCalculator, Relationship, user::User
 };
-use crate::guards::auth::UserRef;
 use crate::notifications::{
     self,
     events::{groups::*, guilds::ChannelDelete, message::*, Notification},
@@ -53,7 +52,7 @@ pub struct CreateGroup {
 
 /// create a new group
 #[post("/create", data = "<info>")]
-pub fn create_group(user: UserRef, info: Json<CreateGroup>) -> Response {
+pub fn create_group(user: User, info: Json<CreateGroup>) -> Response {
     let name: String = info.name.chars().take(32).collect();
     let nonce: String = info.nonce.chars().take(32).collect();
 
@@ -90,13 +89,12 @@ pub fn create_group(user: UserRef, info: Json<CreateGroup>) -> Response {
             return Response::BadRequest(json!({ "error": "Specified non-existant user(s)." }));
         }
 
-        let relationships = user.fetch_relationships();
         for item in set {
             if item == user.id {
                 continue;
             }
 
-            if get_relationship_internal(&user.id, &item, &relationships) != Relationship::Friend {
+            if get_relationship_internal(&user.id, &item, &user.relations) != Relationship::Friend {
                 return Response::BadRequest(json!({ "error": "Not friends with user(s)." }));
             }
         }
@@ -129,7 +127,7 @@ pub fn create_group(user: UserRef, info: Json<CreateGroup>) -> Response {
 
 /// fetch channel information
 #[get("/<target>")]
-pub fn channel(user: UserRef, target: Channel) -> Option<Response> {
+pub fn channel(user: User, target: Channel) -> Option<Response> {
     with_permissions!(user, target);
 
     match target.channel_type {
@@ -180,7 +178,7 @@ pub fn channel(user: UserRef, target: Channel) -> Option<Response> {
 
 /// [groups] add user to channel
 #[put("/<target>/recipients/<member>")]
-pub fn add_member(user: UserRef, target: Channel, member: UserRef) -> Option<Response> {
+pub fn add_member(user: User, target: Channel, member: User) -> Option<Response> {
     if target.channel_type != 1 {
         return Some(Response::BadRequest(json!({ "error": "Not a group DM." })));
     }
@@ -254,7 +252,7 @@ pub fn add_member(user: UserRef, target: Channel, member: UserRef) -> Option<Res
 
 /// [groups] remove user from channel
 #[delete("/<target>/recipients/<member>")]
-pub fn remove_member(user: UserRef, target: Channel, member: UserRef) -> Option<Response> {
+pub fn remove_member(user: User, target: Channel, member: User) -> Option<Response> {
     if target.channel_type != 1 {
         return Some(Response::BadRequest(json!({ "error": "Not a group DM." })));
     }
@@ -326,7 +324,7 @@ pub fn remove_member(user: UserRef, target: Channel, member: UserRef) -> Option<
 /// or leave group DM
 /// or close DM conversation
 #[delete("/<target>")]
-pub fn delete(user: UserRef, target: Channel) -> Option<Response> {
+pub fn delete(user: User, target: Channel) -> Option<Response> {
     let permissions = with_permissions!(user, target);
 
     if !permissions.get_manage_channels() {
@@ -488,7 +486,7 @@ pub struct MessageFetchOptions {
 /// fetch channel messages
 #[get("/<target>/messages?<options..>")]
 pub fn messages(
-    user: UserRef,
+    user: User,
     target: Channel,
     options: Form<MessageFetchOptions>,
 ) -> Option<Response> {
@@ -552,7 +550,7 @@ pub struct SendMessage {
 /// send a message to a channel
 #[post("/<target>/messages", data = "<message>")]
 pub fn send_message(
-    user: UserRef,
+    user: User,
     target: Channel,
     message: Json<SendMessage>,
 ) -> Option<Response> {
@@ -608,7 +606,7 @@ pub fn send_message(
 
 /// get a message
 #[get("/<target>/messages/<message>")]
-pub fn get_message(user: UserRef, target: Channel, message: Message) -> Option<Response> {
+pub fn get_message(user: User, target: Channel, message: Message) -> Option<Response> {
     let permissions = with_permissions!(user, target);
 
     if !permissions.get_read_messages() {
@@ -641,7 +639,7 @@ pub struct EditMessage {
 /// edit a message
 #[patch("/<target>/messages/<message>", data = "<edit>")]
 pub fn edit_message(
-    user: UserRef,
+    user: User,
     target: Channel,
     message: Message,
     edit: Json<EditMessage>,
@@ -699,7 +697,7 @@ pub fn edit_message(
 
 /// delete a message
 #[delete("/<target>/messages/<message>")]
-pub fn delete_message(user: UserRef, target: Channel, message: Message) -> Option<Response> {
+pub fn delete_message(user: User, target: Channel, message: Message) -> Option<Response> {
     let permissions = with_permissions!(user, target);
 
     if !permissions.get_manage_messages() {
diff --git a/src/routes/guild.rs b/src/routes/guild.rs
index 77269435725952e5a252013a35a4810cf03c71d4..cf91b3c998adbbd9c4c3eb9716ad59f470d3d105 100644
--- a/src/routes/guild.rs
+++ b/src/routes/guild.rs
@@ -2,9 +2,8 @@ use super::channel::ChannelType;
 use super::Response;
 use crate::database::guild::{fetch_member as get_member, get_invite, Guild, MemberKey};
 use crate::database::{
-    self, channel::fetch_channel, channel::Channel, Permission, PermissionCalculator,
+    self, channel::fetch_channel, channel::Channel, Permission, PermissionCalculator, user::User
 };
-use crate::guards::auth::UserRef;
 use crate::notifications::{
     self,
     events::{guilds::*, Notification},
@@ -35,7 +34,7 @@ macro_rules! with_permissions {
 
 /// fetch your guilds
 #[get("/@me")]
-pub fn my_guilds(user: UserRef) -> Response {
+pub fn my_guilds(user: User) -> Response {
     if let Ok(result) = database::get_collection("members").find(
         doc! {
             "_id.user": &user.id
@@ -93,7 +92,7 @@ pub fn my_guilds(user: UserRef) -> Response {
 
 /// fetch a guild
 #[get("/<target>")]
-pub fn guild(user: UserRef, target: Guild) -> Option<Response> {
+pub fn guild(user: User, target: Guild) -> Option<Response> {
     with_permissions!(user, target);
 
     let col = database::get_collection("channels");
@@ -134,7 +133,7 @@ pub fn guild(user: UserRef, target: Guild) -> Option<Response> {
 
 /// delete or leave a guild
 #[delete("/<target>")]
-pub fn remove_guild(user: UserRef, target: Guild) -> Option<Response> {
+pub fn remove_guild(user: User, target: Guild) -> Option<Response> {
     with_permissions!(user, target);
 
     if user.id == target.owner {
@@ -265,7 +264,7 @@ pub struct CreateChannel {
 
 /// create a new channel
 #[post("/<target>/channels", data = "<info>")]
-pub fn create_channel(user: UserRef, target: Guild, info: Json<CreateChannel>) -> Option<Response> {
+pub fn create_channel(user: User, target: Guild, info: Json<CreateChannel>) -> Option<Response> {
     let (permissions, _) = with_permissions!(user, target);
 
     if !permissions.get_manage_channels() {
@@ -338,7 +337,7 @@ pub struct InviteOptions {
 /// create a new invite
 #[post("/<target>/channels/<channel>/invite", data = "<_options>")]
 pub fn create_invite(
-    user: UserRef,
+    user: User,
     target: Guild,
     channel: Channel,
     _options: Json<InviteOptions>,
@@ -376,7 +375,7 @@ pub fn create_invite(
 
 /// remove an invite
 #[delete("/<target>/invites/<code>")]
-pub fn remove_invite(user: UserRef, target: Guild, code: String) -> Option<Response> {
+pub fn remove_invite(user: User, target: Guild, code: String) -> Option<Response> {
     let (permissions, _) = with_permissions!(user, target);
 
     if let Some((guild_id, _, invite)) = get_invite(&code, None) {
@@ -417,7 +416,7 @@ pub fn remove_invite(user: UserRef, target: Guild, code: String) -> Option<Respo
 
 /// fetch all guild invites
 #[get("/<target>/invites")]
-pub fn fetch_invites(user: UserRef, target: Guild) -> Option<Response> {
+pub fn fetch_invites(user: User, target: Guild) -> Option<Response> {
     let (permissions, _) = with_permissions!(user, target);
 
     if !permissions.get_manage_server() {
@@ -429,7 +428,7 @@ pub fn fetch_invites(user: UserRef, target: Guild) -> Option<Response> {
 
 /// view an invite before joining
 #[get("/join/<code>", rank = 1)]
-pub fn fetch_invite(user: UserRef, code: String) -> Response {
+pub fn fetch_invite(user: User, code: String) -> Response {
     if let Some((guild_id, name, invite)) = get_invite(&code, user.id) {
         match fetch_channel(&invite.channel) {
             Ok(result) => {
@@ -457,7 +456,7 @@ pub fn fetch_invite(user: UserRef, code: String) -> Response {
 
 /// join a guild using an invite
 #[post("/join/<code>", rank = 1)]
-pub fn use_invite(user: UserRef, code: String) -> Response {
+pub fn use_invite(user: User, code: String) -> Response {
     if let Some((guild_id, _, invite)) = get_invite(&code, Some(user.id.clone())) {
         if let Ok(result) = database::get_collection("members").find_one(
             doc! {
@@ -521,8 +520,8 @@ pub struct CreateGuild {
 
 /// create a new guild
 #[post("/create", data = "<info>")]
-pub fn create_guild(user: UserRef, info: Json<CreateGuild>) -> Response {
-    if !user.email_verified {
+pub fn create_guild(user: User, info: Json<CreateGuild>) -> Response {
+    if !user.email_verification.verified {
         return Response::Unauthorized(json!({ "error": "Email not verified!" }));
     }
 
@@ -611,7 +610,7 @@ pub fn create_guild(user: UserRef, info: Json<CreateGuild>) -> Response {
 
 /// fetch a guild's member
 #[get("/<target>/members")]
-pub fn fetch_members(user: UserRef, target: Guild) -> Option<Response> {
+pub fn fetch_members(user: User, target: Guild) -> Option<Response> {
     with_permissions!(user, target);
 
     if let Ok(result) =
@@ -638,7 +637,7 @@ pub fn fetch_members(user: UserRef, target: Guild) -> Option<Response> {
 
 /// fetch a guild member
 #[get("/<target>/members/<other>")]
-pub fn fetch_member(user: UserRef, target: Guild, other: String) -> Option<Response> {
+pub fn fetch_member(user: User, target: Guild, other: String) -> Option<Response> {
     with_permissions!(user, target);
 
     if let Ok(result) = get_member(MemberKey(target.id, user.id)) {
@@ -661,7 +660,7 @@ pub fn fetch_member(user: UserRef, target: Guild, other: String) -> Option<Respo
 
 /// kick a guild member
 #[delete("/<target>/members/<other>")]
-pub fn kick_member(user: UserRef, target: Guild, other: String) -> Option<Response> {
+pub fn kick_member(user: User, target: Guild, other: String) -> Option<Response> {
     let (permissions, _) = with_permissions!(user, target);
 
     if user.id == other {
@@ -720,7 +719,7 @@ pub struct BanOptions {
 /// ban a guild member
 #[put("/<target>/members/<other>/ban?<options..>")]
 pub fn ban_member(
-    user: UserRef,
+    user: User,
     target: Guild,
     other: String,
     options: Form<BanOptions>,
@@ -804,7 +803,7 @@ pub fn ban_member(
 
 /// unban a guild member
 #[delete("/<target>/members/<other>/ban")]
-pub fn unban_member(user: UserRef, target: Guild, other: String) -> Option<Response> {
+pub fn unban_member(user: User, target: Guild, other: String) -> Option<Response> {
     let (permissions, _) = with_permissions!(user, target);
 
     if user.id == other {
diff --git a/src/routes/root.rs b/src/routes/root.rs
index 3381b4d55d9a1c86824458b15f7b482f00a9bf99..2f2f03c29f14f785f58b285f5e839773d1501e08 100644
--- a/src/routes/root.rs
+++ b/src/routes/root.rs
@@ -6,7 +6,7 @@ use mongodb::bson::doc;
 #[get("/")]
 pub fn root() -> Response {
     Response::Success(json!({
-        "revolt": "0.2.5"
+        "revolt": "0.2.6"
     }))
 }
 
diff --git a/src/routes/user.rs b/src/routes/user.rs
index c9a36631a3a2347c13ff36976f87574d5eaf8f54..2c4cdb6ca36fd56fe9e846681ed922272c0f1bd2 100644
--- a/src/routes/user.rs
+++ b/src/routes/user.rs
@@ -1,6 +1,5 @@
 use super::Response;
-use crate::database::{self, get_relationship, get_relationship_internal, mutual, Relationship};
-use crate::guards::auth::UserRef;
+use crate::database::{self, get_relationship, get_relationship_internal, mutual, Relationship, user::User};
 use crate::notifications::{
     self,
     events::{users::*, Notification},
@@ -15,25 +14,19 @@ use ulid::Ulid;
 
 /// retrieve your user information
 #[get("/@me")]
-pub fn me(user: UserRef) -> Response {
-    if let Some(info) = user.fetch_data(doc! { "email": 1 }) {
-        Response::Success(json!({
-            "id": user.id,
-            "username": user.username,
-            "display_name": user.display_name,
-            "email": info.get_str("email").unwrap(),
-            "verified": user.email_verified,
-        }))
-    } else {
-        Response::InternalServerError(
-            json!({ "error": "Failed to fetch information from database." }),
-        )
-    }
+pub fn me(user: User) -> Response {
+    Response::Success(json!({
+        "id": user.id,
+        "username": user.username,
+        "display_name": user.display_name,
+        "email": user.email,
+        "verified": user.email_verification.verified,
+    }))
 }
 
 /// retrieve another user's information
 #[get("/<target>")]
-pub fn user(user: UserRef, target: UserRef) -> Response {
+pub fn user(user: User, target: User) -> Response {
     Response::Success(json!({
         "id": target.id,
         "username": target.username,
@@ -54,8 +47,7 @@ pub struct UserQuery {
 
 /// find a user by their username
 #[post("/query", data = "<query>")]
-pub fn query(user: UserRef, query: Json<UserQuery>) -> Response {
-    let relationships = user.fetch_relationships();
+pub fn query(user: User, query: Json<UserQuery>) -> Response {
     let col = database::get_collection("users");
 
     if let Ok(result) = col.find_one(
@@ -70,7 +62,7 @@ pub fn query(user: UserRef, query: Json<UserQuery>) -> Response {
                 "id": id,
                 "username": doc.get_str("username").unwrap(),
                 "display_name": doc.get_str("display_name").unwrap(),
-                "relationship": get_relationship_internal(&user.id, &id, &relationships) as i32
+                "relationship": get_relationship_internal(&user.id, &id, &user.relations) as i32
             }))
         } else {
             Response::NotFound(json!({
@@ -90,7 +82,7 @@ pub struct LookupQuery {
 /// lookup a user on Revolt
 /// currently only supports exact username searches
 #[post("/lookup", data = "<query>")]
-pub fn lookup(user: UserRef, query: Json<LookupQuery>) -> Response {
+pub fn lookup(user: User, query: Json<LookupQuery>) -> Response {
     let relationships = user.fetch_relationships();
     let col = database::get_collection("users");
 
@@ -121,7 +113,7 @@ pub fn lookup(user: UserRef, query: Json<LookupQuery>) -> Response {
 
 /// retrieve all of your DMs
 #[get("/@me/dms")]
-pub fn dms(user: UserRef) -> Response {
+pub fn dms(user: User) -> Response {
     let col = database::get_collection("channels");
 
     if let Ok(results) = col.find(
@@ -178,7 +170,7 @@ pub fn dms(user: UserRef) -> Response {
 
 /// open a DM with a user
 #[get("/<target>/dm")]
-pub fn dm(user: UserRef, target: UserRef) -> Response {
+pub fn dm(user: User, target: User) -> Response {
     let col = database::get_collection("channels");
 
     if let Ok(result) = col.find_one(
@@ -211,11 +203,9 @@ pub fn dm(user: UserRef, target: UserRef) -> Response {
 
 /// retrieve all of your friends
 #[get("/@me/friend")]
-pub fn get_friends(user: UserRef) -> Response {
-    let relationships = user.fetch_relationships();
-
+pub fn get_friends(user: User) -> Response {
     let mut results = Vec::new();
-    if let Some(arr) = relationships {
+    if let Some(arr) = user.relations {
         for item in arr {
             results.push(json!({
                 "id": item.id,
@@ -229,13 +219,13 @@ pub fn get_friends(user: UserRef) -> Response {
 
 /// retrieve friend status with user
 #[get("/<target>/friend")]
-pub fn get_friend(user: UserRef, target: UserRef) -> Response {
+pub fn get_friend(user: User, target: User) -> Response {
     Response::Success(json!({ "status": get_relationship(&user, &target) as i32 }))
 }
 
 /// create or accept a friend request
 #[put("/<target>/friend")]
-pub fn add_friend(user: UserRef, target: UserRef) -> Response {
+pub fn add_friend(user: User, target: User) -> Response {
     let col = database::get_collection("users");
 
     match get_relationship(&user, &target) {
@@ -383,7 +373,7 @@ pub fn add_friend(user: UserRef, target: UserRef) -> Response {
 
 /// remove a friend or deny a request
 #[delete("/<target>/friend")]
-pub fn remove_friend(user: UserRef, target: UserRef) -> Response {
+pub fn remove_friend(user: User, target: User) -> Response {
     let col = database::get_collection("users");
 
     match get_relationship(&user, &target) {
@@ -459,7 +449,7 @@ pub fn remove_friend(user: UserRef, target: UserRef) -> Response {
 
 /// block a user
 #[put("/<target>/block")]
-pub fn block_user(user: UserRef, target: UserRef) -> Response {
+pub fn block_user(user: User, target: User) -> Response {
     let col = database::get_collection("users");
 
     match get_relationship(&user, &target) {
@@ -631,7 +621,7 @@ pub fn block_user(user: UserRef, target: UserRef) -> Response {
 
 /// unblock a user
 #[delete("/<target>/block")]
-pub fn unblock_user(user: UserRef, target: UserRef) -> Response {
+pub fn unblock_user(user: User, target: User) -> Response {
     let col = database::get_collection("users");
 
     match get_relationship(&user, &target) {