incremental
diff --git a/include/token_authorization_middleware.hpp b/include/token_authorization_middleware.hpp
index 214fd93..d333e6c 100644
--- a/include/token_authorization_middleware.hpp
+++ b/include/token_authorization_middleware.hpp
@@ -4,25 +4,145 @@
 #include <crow/http_response.h>
 #include <boost/container/flat_set.hpp>
 
+#include <base64.hpp>
+
+#include <pam_authenticate.hpp>
+
 namespace crow {
 
 struct User {};
 
-struct TokenAuthorizationMiddleware {
+using random_bytes_engine =
+    std::independent_bits_engine<std::default_random_engine, CHAR_BIT,
+                                 unsigned char>;
+
+template <class AuthenticationFunction>
+struct TokenAuthorization {
   // TODO(ed) auth_token shouldn't really be passed to the context
   // it opens the possibility of exposure by and endpoint.
   // instead we should only pass some kind of "user" struct
   struct context {
-    //std::string auth_token;
+    // std::string auth_token;
   };
 
-  TokenAuthorizationMiddleware();
+  TokenAuthorization(){};
 
-  void before_handle(crow::request& req, response& res, context& ctx);
+  void before_handle(crow::request& req, response& res, context& ctx) {
+    auto return_unauthorized = [&req, &res]() {
+      res.code = 401;
+      res.end();
+    };
 
-  void after_handle(request& req, response& res, context& ctx);
+    auto return_bad_request = [&req, &res]() {
+      res.code = 400;
+      res.end();
+    };
+
+    auto return_internal_error = [&req, &res]() {
+      res.code = 500;
+      res.end();
+    };
+
+    if (req.url == "/" || boost::starts_with(req.url, "/static/")) {
+      // 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 for based page
+      // that didn't
+      // load the full angular UI until after login
+      return;
+    }
+
+    if (req.url == "/login") {
+      if (req.method != HTTPMethod::POST) {
+        return_unauthorized();
+        return;
+      } else {
+        auto login_credentials = crow::json::load(req.body);
+        if (!login_credentials) {
+          return_bad_request();
+          return;
+        }
+        if (!login_credentials.has("username") ||
+            !login_credentials.has("password")) {
+          return_bad_request();
+          return;
+        }
+        auto username = login_credentials["username"].s();
+        auto password = login_credentials["password"].s();
+        auto p = AuthenticationFunction();
+        if (p.authenticate(username, password)) {
+          crow::json::wvalue x;
+
+          // TODO(ed) the RNG should be initialized at start, not every time we
+          // want a token
+          std::random_device rand;
+          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
+          std::generate(std::begin(token), std::end(token), std::ref(rbe));  // NOLINT
+          std::string encoded_token;
+          base64::base64_encode(token, encoded_token);
+          // ctx.auth_token = encoded_token;
+          this->auth_token2.insert(encoded_token);
+
+          x["token"] = encoded_token;
+
+          res.write(json::dump(x));
+          res.add_header("Content-Type", "application/json");
+          res.end();
+        } else {
+          return_unauthorized();
+          return;
+        }
+      }
+
+    } else {  // Normal, non login, non static file request
+      // Check to make sure we're logged in
+      if (this->auth_token2.empty()) {
+        return_unauthorized();
+        return;
+      }
+      // Check for an authorization header, reject if not present
+      if (req.headers.count("Authorization") != 1) {
+        return_unauthorized();
+        return;
+      }
+
+      std::string auth_header = req.get_header_value("Authorization");
+      // If the user is attempting any kind of auth other than token, reject
+      if (!boost::starts_with(auth_header, "Token ")) {
+        return_unauthorized();
+        return;
+      }
+      std::string auth_key = auth_header.substr(6);
+      // TODO(ed), use span here instead of constructing a new string
+      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 after_handle(request& req, response& res, context& ctx) {
+    // Do nothing
+  }
 
  private:
   boost::container::flat_set<std::string> auth_token2;
 };
+
+using TokenAuthorizationMiddleware = TokenAuthorization<PamAuthenticator>;
 }
\ No newline at end of file