diff --git a/src/cache.rs b/src/cache.rs
index 6c25d66d80324c5d4231a4b9d5f2c130fdb6e5aa..752fc454279b4d90582e228f850626b3b331aef4 100644
--- a/src/cache.rs
+++ b/src/cache.rs
@@ -17,8 +17,6 @@ use crate::BASE_NAME;
 
 use lazy_static::lazy_static;
 use std::collections::HashMap;
-use std::convert::From;
-use std::time::SystemTime;
 
 use libc::{geteuid, seteuid, getpwnam, uid_t};
 use std::ffi::CString;
@@ -29,100 +27,84 @@ use std::env;
 use std::fs;
 use std::io;
 use std::path::PathBuf;
-use xdg::{BaseDirectories,BaseDirectoriesError};
+use xdg::{BaseDirectories, BaseDirectoriesError};
 
-use serde::{Deserialize, Serialize};
+use serde::Serialize;
+use serde::de::DeserializeOwned;
 use serde_json;
 
 const TOKEN_DEFAULT_EXPIRES: u64 = 24 * 60 * 60;
 const USER_TOKEN_FILENAME: &str = "user_token.json";
 
-#[derive(Serialize, Deserialize)]
-struct UserToken {
-    access_token: String,
-    expires_at: u64,
-    refresh_token: Option<String>,
-}
-
-impl UserToken {
-    fn is_expired(&self) -> bool {
-        match SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) {
-            Ok(d) => d.as_secs() >= self.expires_at,
-            Err(_) => true
-        }
-    }
-}
-
-impl From<BasicTokenResponse> for UserToken {
-    fn from(response: BasicTokenResponse) -> Self {
-        UserToken {
-            access_token: response.access_token.secret().to_string(),
-            expires_at: match response.expires_in {
-                Some(duration) => duration,
-                None => TOKEN_DEFAULT_EXPIRES
-            } + SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).ok().unwrap().as_secs(),
-            refresh_token: match response.refresh_token {
-                Some(t) => Some(t.secret().to_string()),
-                None => None
-            }
-        }
-    }
-}
-
 struct Cache {
-    user_tokens: HashMap<String, UserToken>,
+    user_tokens: HashMap<String, BasicTokenResponse>,
     original_euid: uid_t,
 }
 
 impl Cache {
     pub fn new() -> Cache {
+        let euid;
+        unsafe {
+            euid = geteuid();
+        };
         Cache {
             user_tokens: HashMap::new(),
-            original_euid: geteuid()
+            original_euid: euid
         }
     }
 
-    fn drop_privileges(&self, username: String) -> Result<uid_t, String> {
-        let nam = match CString::new(username) {
+    fn drop_privileges(&self, username: &String) -> Result<uid_t, &str> {
+        let nam = match CString::new(username.as_str()) {
             Ok(nam) => nam,
-            Err(_) => return Err("Invalid username in lookup".to_string())
+            Err(_) => return Err("Invalid username in lookup")
+        };
+        let target_euid;
+        unsafe {
+            target_euid = (*getpwnam(nam.as_ptr())).pw_uid;
         };
-        let target_euid = (*getpwnam(nam.as_ptr())).pw_uid;
-
 
         if target_euid == self.original_euid {
             debug!("No need to drop privileges, already running as {}", username);
             return Ok(self.original_euid);
         } else if self.original_euid == 0 {
-            let res = seteuid(target_euid);
+            let res;
+            unsafe {
+                res = seteuid(target_euid);
+            };
             if res == 0 {
                 debug!("Successfully dropped privileges to {}", username);
                 return Ok(target_euid);
             } else {
                 error!("Could not drop privileges to {}", username);
-                return Err("Failed to drop privileges".to_string());
+                return Err("Failed to drop privileges");
             }
         }
 
         error!("Not running as root or target user, cannot drop privileges");
-        return Err("Dropping privileges not supported".to_string());
+        return Err("Dropping privileges not supported");
     }
 
     fn restore_privileges(&self) {
         debug!("Restoring privileges");
-        seteuid(self.original_euid);
+        unsafe {
+            seteuid(self.original_euid);
+        }
     }
 
-    fn get_user_xdg_base_directories(&self, username: String) -> Result<BaseDirectories, BaseDirectoriesError> {
+    fn get_user_xdg_base_directories(&self, username: &String) -> Result<BaseDirectories, BaseDirectoriesError> {
         let saved_home = env::var_os("HOME");
 
-        let nam = match CString::new(username) {
+        let nam = match CString::new(username.as_str()) {
             Ok(nam) => nam,
             Err(_) => CString::new("nobody").ok().unwrap()
         };
-        let user_home = CString::from_raw((*getpwnam(nam.as_ptr())).pw_dir).to_str().unwrap();
-        env::set_var("HOME", user_home);
-        debug!("Home directory for {} is {}", username, user_home);
+        let user_home;
+        unsafe {
+           user_home = CString::from_raw((*getpwnam(nam.as_ptr())).pw_dir);
+        };
+
+        env::set_var("HOME", user_home.to_str().unwrap());
+        debug!("Home directory for {} is {}", username, user_home.to_str().unwrap());
 
         let base_dirs = BaseDirectories::with_prefix(BASE_NAME)?;
 
@@ -150,51 +132,47 @@ impl Cache {
         return Ok(base_dirs);
     }
 
-    fn place_user_cache_file(&self, username: String, filename: &str) -> Result<PathBuf, io::Error> {
+    fn place_user_cache_file(&self, username: &String, filename: String) -> Result<PathBuf, io::Error> {
         match self.get_user_xdg_base_directories(username) {
             Ok(b) => b.place_cache_file(filename),
             Err(e) => Err(io::Error::new(io::ErrorKind::NotFound, e))
         }
     }
 
-    pub fn load_user_token(&self, owner: String) -> Option<&UserToken> {
-        let token = self.user_tokens.get(&owner);
-        if token.is_none() || token.unwrap().is_expired() {
-            debug!("No recent token for {} in memory, trying to load from file", owner);
-            self.user_tokens.remove(&owner);
+    pub fn load_user_token(&mut self, owner: &String) -> Option<&BasicTokenResponse> {
+        if !self.user_tokens.contains_key(owner) {
+            debug!("No token for {} in memory, trying to load from file", owner);
 
             self.drop_privileges(owner).ok();
-            let new_token = match self.place_user_cache_file(owner, USER_TOKEN_FILENAME) {
-                Ok(path) => match load_json::<UserToken>(path) {
-                    Ok(read_token) => {
-                        if !read_token.is_expired() {
-                            debug!("Found valid token for {} in file", owner);
-                            self.user_tokens.insert(owner, read_token);
-                            Some(&read_token)
-                        } else {
-                            debug!("Token in file for {} is expired.", owner);
-                            None
-                        }
-                    },
-                    Err(e) => None
+            let new_token = match self.place_user_cache_file(owner, USER_TOKEN_FILENAME.to_string()) {
+                Ok(path) => match load_json(path) {
+                    Ok(read_token) => Some(read_token),
+                    Err(_) => None
                 },
-                Err(e) => None
+                Err(_) => None
             };
             self.restore_privileges();
-            new_token
+
+            match new_token {
+                Some(t) => {
+                    self.user_tokens.insert(owner.to_string(), t);
+                    self.user_tokens.get(owner)
+                },
+                None => None
+            }
         } else {
-            debug!("Found valid token for {} in memory", owner);
-            token
+            debug!("Found token for {} in memory", owner);
+            self.user_tokens.get(owner)
         }
     }
 
-    pub fn save_user_token(&self, owner: String, token: UserToken) -> Result<(), io::Error> {
-        self.user_tokens.insert(owner, token);
+    pub fn save_user_token(&mut self, owner: &String, token: BasicTokenResponse) -> Result<(), io::Error> {
+        self.user_tokens.insert(owner.to_string(), token.clone());
         debug!("Saved token for {} in memory", owner);
 
         // Try to write user's token cache file
         let res = match self.drop_privileges(owner) {
-            Ok(_) => match self.place_user_cache_file(owner, USER_TOKEN_FILENAME) {
+            Ok(_) => match self.place_user_cache_file(owner, USER_TOKEN_FILENAME.to_string()) {
                 Ok(path) => {
                     debug!("Storing token for {} in cache file", owner);
                     save_json(path, token)
@@ -207,13 +185,13 @@ impl Cache {
         return res;
     }
 
-    pub fn delete_user_token(&self, owner: String) {
-        self.user_tokens.remove(&owner);
+    pub fn delete_user_token(&mut self, owner: &String) {
+        self.user_tokens.remove(owner);
         debug!("Token for {} removed from memory", owner);
 
         // Try to remove user's token cache file
         self.drop_privileges(owner).ok();
-        match self.place_user_cache_file(owner, USER_TOKEN_FILENAME) {
+        match self.place_user_cache_file(owner, USER_TOKEN_FILENAME.to_string()) {
             Ok(path) => {
                 debug!("Deleting cache file for {}", owner);
                 fs::remove_file(path)
@@ -222,22 +200,14 @@ impl Cache {
         };
         self.restore_privileges();
     }
-
-    pub fn cleanup_tokens(&self) {
-        for (owner, token) in self.user_tokens {
-            if token.is_expired() {
-                self.delete_user_token(owner);
-                debug!("Deleted expired token for {}", owner);
-            }
-        }
-    }
 }
 
-fn load_json<'de, O: Deserialize<'de>>(path: PathBuf) -> Result<O, io::Error> {
-    let json = fs::read_to_string(path)?;
-    match serde_json::from_str(&json) {
+fn load_json<O: DeserializeOwned>(path: PathBuf) -> Result<O, io::Error> {
+    let file = fs::File::open(path)?;
+    let reader = io::BufReader::new(file);
+    match serde_json::from_reader(reader) {
         Ok(o) => Ok(o),
-        Err(e) => return Err(io::Error::new(io::ErrorKind::InvalidData, e))
+        Err(e) => Err(io::Error::new(io::ErrorKind::InvalidData, e))
     }
 }
 
diff --git a/src/config.rs b/src/config.rs
index 9009b2d608ec9fd5a28eb0a66ac9182c0daf1864..ca3b3be28f4c81dbc6860f0483f86730c062c860 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -19,8 +19,6 @@ use serde::de::Deserialize;
 
 extern crate config;
 
-const DEFAULT_CONFIG_FILE: &str = ("/etc/".to_string() + BASE_NAME).as_str();
-
 pub fn get_config(conf_args: Option<config::Config>) -> config::Config {
     // Preset default configuration
     let mut conf = config::Config::default();
@@ -32,7 +30,7 @@ pub fn get_config(conf_args: Option<config::Config>) -> config::Config {
     // Determine config file from args if provided and load config file
     let config_file = match conf_args.get_str("config") {
         Ok(filename) => filename.to_string(),
-        Err(_) => DEFAULT_CONFIG_FILE.to_string(),
+        Err(_) => "/etc/".to_string() + BASE_NAME,
     };
     conf.merge(config::File::with_name(&config_file)).ok();
 
diff --git a/src/pam.rs b/src/pam.rs
index 31d5b35f8811683ba5cbab82e92df32980c9f992..32e44e58a0c9e0812c4ef4323fb9bb16eb0fb617 100644
--- a/src/pam.rs
+++ b/src/pam.rs
@@ -90,7 +90,7 @@ impl PamServiceModule for PamOidc {
             match get_access_token_password(conf, "pam", username.to_string(), password.to_string(), PamError::SERVICE_ERR, PamError::AUTH_ERR) {
                 Ok(t) => {
                     info!("Authenticated {} using Resource Owner Password Grant", username);
-                    CACHE.save_user_token(username.to_string(), t.into());
+                    CACHE.save_user_token(&username.to_string(), t.into());
                     return PamError::SUCCESS;
                 },
                 Err(e) => {