incremental
diff --git a/src/token_authorization_middleware.cpp b/src/token_authorization_middleware.cpp
index 4bac9b4..508bfd9 100644
--- a/src/token_authorization_middleware.cpp
+++ b/src/token_authorization_middleware.cpp
@@ -2,6 +2,7 @@
 #include <unordered_map>
 #include <boost/algorithm/string/predicate.hpp>
 
+#include <security/pam_appl.h>
 #include <base64.hpp>
 #include <token_authorization_middleware.hpp>
 #include <crow/logging.h>
@@ -12,10 +13,67 @@
     std::independent_bits_engine<std::default_random_engine, CHAR_BIT,
                                  unsigned char>;
 
-TokenAuthorizationMiddleware::TokenAuthorizationMiddleware()
-    : auth_token2(""){
+// function used to get user input
+int pam_function_conversation(int num_msg, const struct pam_message** msg,
+                              struct pam_response** resp, void* appdata_ptr) {
+  char* pass = (char*)malloc(strlen((char*)appdata_ptr) + 1);
+  strcpy(pass, (char*)appdata_ptr);
 
-      };
+  int i;
+
+  *resp = (pam_response*)calloc(num_msg, sizeof(struct pam_response));
+
+  for (i = 0; i < num_msg; ++i) {
+    /* Ignore all PAM messages except prompting for hidden input */
+    if (msg[i]->msg_style != PAM_PROMPT_ECHO_OFF) continue;
+
+    /* Assume PAM is only prompting for the password as hidden input */
+    resp[i]->resp = pass;
+  }
+
+  return PAM_SUCCESS;
+}
+
+bool authenticate_user_pam(const std::string& username,
+                           const std::string& password) {
+  const struct pam_conv local_conversation = {pam_function_conversation,
+                                              (char*)password.c_str()};
+  pam_handle_t* local_auth_handle = NULL;  // this gets set by pam_start
+
+  int retval;
+  retval = pam_start("su", username.c_str(), &local_conversation,
+                     &local_auth_handle);
+
+  if (retval != PAM_SUCCESS) {
+    printf("pam_start returned: %d\n ", retval);
+    return false;
+  }
+
+  retval = pam_authenticate(local_auth_handle,
+                            PAM_SILENT | PAM_DISALLOW_NULL_AUTHTOK);
+
+  if (retval != PAM_SUCCESS) {
+    if (retval == PAM_AUTH_ERR) {
+      printf("Authentication failure.\n");
+    } else {
+      printf("pam_authenticate returned %d\n", retval);
+    }
+    return false;
+  }
+
+  printf("Authenticated.\n");
+  retval = pam_end(local_auth_handle, retval);
+
+  if (retval != PAM_SUCCESS) {
+    printf("pam_end returned\n");
+    return false;
+  }
+
+  return true;
+}
+
+TokenAuthorizationMiddleware::TokenAuthorizationMiddleware(){
+};
 
 void TokenAuthorizationMiddleware::before_handle(crow::request& req,
                                                  response& res, context& ctx) {
@@ -38,9 +96,10 @@
     // TODO this is total hackery to allow the login page to work before the
     // user is authenticated.  Also, it will be quite slow for all pages instead
     // of a one time hit for the whitelist entries.  Ideally, this should be
-    // done
-    // in the url router handler, with tagged routes for the whitelist entries.
-    // Another option would be to whitelist a minimal
+    // done in the url router handler, with tagged routes for the whitelist
+    // entries. Another option would be to whitelist a minimal for based page
+    // that didn't
+    // load the full angular UI until after login
     return;
   }
 
@@ -63,7 +122,7 @@
       auto password = login_credentials["password"].s();
 
       // TODO(ed) pull real passwords from PAM
-      if (username == "dude" && password == "dude") {
+      if (authenticate_user_pam(username, password)) {
         crow::json::wvalue x;
 
         // TODO(ed) the RNG should be initialized at start, not every time we
@@ -72,16 +131,14 @@
         random_bytes_engine rbe;
         std::string token('a', 20);
         // TODO(ed) for some reason clang-tidy finds a divide by zero error in
-        // cstdlibc here
-        // commented out for now.  Needs investigation
+        // cstdlibc here commented out for now.  Needs investigation
         std::generate(begin(token), end(token), std::ref(rbe));  // NOLINT
         std::string encoded_token;
         base64::base64_encode(token, encoded_token);
-        ctx.auth_token = encoded_token;
-        this->auth_token2 = encoded_token;
+        // ctx.auth_token = encoded_token;
+        this->auth_token2.insert(encoded_token);
 
-        auto auth_token = ctx.auth_token;
-        x["token"] = auth_token;
+        x["token"] = encoded_token;
 
         res.write(json::dump(x));
         res.add_header("Content-Type", "application/json");
@@ -92,10 +149,6 @@
       }
     }
 
-  } else if (req.url == "/logout") {
-    this->auth_token2 = "";
-    res.code = 200;
-    res.end();
   } else {  // Normal, non login, non static file request
     // Check to make sure we're logged in
     if (this->auth_token2.empty()) {
@@ -114,16 +167,26 @@
       return_unauthorized();
       return;
     }
-
+    std::string auth_key = auth_header.substr(6);
     // TODO(ed), use span here instead of constructing a new string
-    if (auth_header.substr(6) != this->auth_token2) {
+    if (this->auth_token2.find(auth_key) == this->auth_token2.end()) {
       return_unauthorized();
       return;
     }
+
+    if (req.url == "/logout") {
+      this->auth_token2.erase(auth_key);
+      res.code = 200;
+      res.end();
+      return;
+    }
+
     // else let the request continue unharmed
   }
 }
 
 void TokenAuthorizationMiddleware::after_handle(request& req, response& res,
-                                                context& ctx) {}
+                                                context& ctx) {
+  // Do nothing
+}
 }
diff --git a/src/webserver_main.cpp b/src/webserver_main.cpp
index f47eb79..404e15c 100644
--- a/src/webserver_main.cpp
+++ b/src/webserver_main.cpp
@@ -228,11 +228,15 @@
   g3::initializeLogging(worker.get());
   auto sink_handle = worker->addSink(std::make_unique<crow::ColorCoutSink>(),
                                      &crow::ColorCoutSink::ReceiveLogMessage);
-
+  bool enable_ssl = true;
   std::string ssl_pem_file("server.pem");
-  ensuressl::ensure_openssl_key_present_and_valid(ssl_pem_file);
 
-  crow::App<crow::TokenAuthorizationMiddleware, crow::SecurityHeadersMiddleware>
+  if (enable_ssl) {
+    ensuressl::ensure_openssl_key_present_and_valid(ssl_pem_file);
+  }
+
+  crow::App<
+      crow::TokenAuthorizationMiddleware,  crow::SecurityHeadersMiddleware>
       app;
 
   crow::webassets::request_routes(app);
@@ -309,13 +313,33 @@
 
     return j;
   });
+
+  CROW_ROUTE(app, "/intel/firmwareupload")
+      .methods("POST"_method)([](const crow::request& req) {
+        // TODO(ed) handle errors here (file exists already and is locked, ect)
+        std::ofstream out(
+            "/tmp/fw_update_image",
+            std::ofstream::out | std::ofstream::binary | std::ofstream::trunc);
+        out << req.body;
+        out.close();
+
+        crow::json::wvalue j;
+        j["status"] = "Upload Successfull";
+
+        return j;
+      });
+
   LOG(DEBUG) << "Building SSL context";
-  auto ssl_context = ensuressl::get_ssl_context(ssl_pem_file);
+
   int port = 18080;
 
   LOG(DEBUG) << "Starting webserver on port " << port;
-  app.port(port)
-      .ssl(std::move(ssl_context))
-      //.concurrency(4)
-      .run();
+  app.port(port);
+  if (enable_ssl) {
+    LOG(DEBUG) << "SSL Enabled";
+    auto ssl_context = ensuressl::get_ssl_context(ssl_pem_file);
+    app.ssl(std::move(ssl_context));
+  }
+  app.concurrency(4);
+  app.run();
 }