diff --git a/.gitignore b/.gitignore
index b9de689..71dbae3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
 node_modules
 db
+db-auth
 logs
diff --git a/package.json b/package.json
index 26efe1a..5ffe573 100644
--- a/package.json
+++ b/package.json
@@ -3,12 +3,17 @@
   "version": "0.0.1",
   "dependencies": {
     "body-parser": "^1.12.4",
+    "connect-ensure-login": "^0.1.1",
+    "cookie-parser": "^1.4.3",
     "express": "^4.12.4",
     "express-hbs": "^0.8.4",
+    "express-session": "^1.13.0",
     "handlebars-form-helpers": "^0.1.3",
     "moment-timezone": "^0.4.0",
     "nodemailer": "^1.3.4",
     "pg": "^4.4.3",
+    "passport": "^0.3.2",
+    "passport-local": "^1.0.0",
     "serve-favicon": "^2.3.0",
     "sqlite3": "^3.0.8",
     "winston": "^2.1.1"
diff --git a/server.js b/server.js
index 700e46a..84982ee 100644
--- a/server.js
+++ b/server.js
@@ -7,6 +7,42 @@ var bodyParser = require("body-parser");
 var app = express();
 var winston = require('winston');
 winston.add(winston.transports.File, { filename: './logs/courtsopen.log', maxsize: 5000000 });  // 5MB
+var fileSystem = require('fs');
+var passport = require('passport');
+var Strategy = require('passport-local').Strategy;
+var db = require('./db-auth');  // Make this db-auth.../db already taken by PostgreSQL linnked container!!!
+
+// Configure the local strategy for use by Passport.
+// The local strategy require a `verify` function which receives the credentials
+// (`username` and `password`) submitted by the user.  The function must verify
+// that the password is correct and then invoke `cb` with a user object, which
+// will be set at `req.user` in route handlers after authentication.
+passport.use(new Strategy(
+  function(username, password, cb) {
+    db.users.findByUsername(username, function(err, user) {
+      winston.info('trying to lookup user.');
+      if (err) { winston.info('db.users.findByUsername error.'); return cb(err); }
+      if (!user) { winston.info('bad user'); return cb(null, false); }
+      if (user.password != password) { winston.info('bad pw'); return cb(null, false); }
+      return cb(null, user);
+    });
+  }));
+// Configure Passport authenticated session persistence.
+//
+// In order to restore authentication state across HTTP requests, Passport needs
+// to serialize users into and deserialize users out of the session.  The
+// typical implementation of this is as simple as supplying the user ID when
+// serializing, and querying the user record by ID from the database when
+// deserializing.
+passport.serializeUser(function(user, cb) {
+  cb(null, user.id);
+});
+passport.deserializeUser(function(id, cb) {
+  db.users.findById(id, function (err, user) {
+    if (err) { return cb(err); }
+    cb(null, user);
+  });
+});
 
 // Setup email
 var transporter = nodemailer.createTransport({
@@ -36,8 +72,25 @@ app.engine('hbs', hbs.express4({
 app.set('view engine', 'hbs');
 app.set('views', __dirname + '/views');
 var favicon = require('serve-favicon');
-app.use(favicon(__dirname + '/assets/favicon.ico'));  // Try this before setting static dir.
+app.use(favicon(__dirname + '/assets/favicon.ico'));  // Put this before setting static dir.
 app.use(express.static('assets'));
+app.use(require('cookie-parser')());
+app.use(require('express-session')({ secret: 'keyboard cat', resave: false, saveUninitialized: false }));
+
+// Initialize Passport and restore authentication state, if any, from the session.
+app.use(passport.initialize());
+app.use(passport.session());
+
+// As with any middleware it is quintessential to call next() if the user is authenticated
+var isAuthenticated = function (req, res, next) {
+    if (req.isAuthenticated()) {
+        return next();
+        res.redirect(req); // I think this is what I want, but might cause re-dir loop.
+    } else {
+        // If user NOT authenticated, redirect to login page, do not call next().
+        res.redirect('/login');
+    }
+}
 
 /*******************************************************************************************************
 With this express setup, ordering of routes matters!!! It's 1st-come-1st-served.
@@ -48,6 +101,23 @@ But, for now, order routes like this:
     - static routes, ordered more specific to less specific
     - dynamic routes, ordered more specific to less specific
 ********************************************************************************************************/
+app.get('/login', function(req, res){
+    winston.info('GET /login');
+    res.render('login');
+});
+  
+app.post('/login', 
+  passport.authenticate('local', { failureRedirect: '/login' }),
+  function(req, res) {
+    winston.info('sucessful login');
+    res.redirect('/:loc/admin'); // will this work, should it be `req`?
+});
+  
+app.get('/logout', function(req, res){
+    req.logout();
+    res.redirect('/'); // possible to go back to appropriate :loc?
+});
+
 app.get('/', function(req, res){
     winston.info("GET /");
    res.render('home', {}, function(err, html) {
@@ -105,6 +175,52 @@ app.post('/', function(req, res){
     res.status(204).send('POST received');
 });
 
+app.get('/:loc/admin', isAuthenticated,  function(req, res) {
+    var loc = req.params.loc;
+    winston.info('GET ' + loc + '/admin');
+    if (loc !== 'tt') {
+        res.status(404).send('Not found');
+    } else {
+        // TODO: load admin template
+    }
+});
+
+app.post(':loc/admin', isAuthenticated, function(req, res){
+    winston.info('POST by admin at ' + loc);
+    // possible to forward req to POST to '/'?
+});
+
+app.get('/:loc/status', function(req, res) {
+    var loc = req.params.loc;
+    if (loc !== 'tt') {
+        res.status(404).send('Not found');
+    } else {
+        winston.info('GET ' + loc + '/status');
+        // Lookup most recent status from DB and return as JSON.
+        pg.connect(conString, function(err, client, done) {
+            if(err) {
+                return winston.error('error fetching client from pool', err);
+            }
+            var mostRecentStatusQry = 
+            "select origjson " + 
+            "from alerts " + 
+            "where status in ('Open', 'Closed') " +
+            "and coreid = '300029000347343339373536' " +
+            "order by published_at desc " +
+            "limit 1"
+            client.query(mostRecentStatusQry, function(err, result) {
+                //call `done()` to release the client back to the pool
+                done();
+                if(err) {
+                    return winston.error('error running query', err);
+                }
+                res.setHeader('Content-Type', 'application/json');
+                res.send(JSON.stringify(result.rows[0].origjson));
+            });
+        });
+    }
+});
+
 app.get('/:loc', function(req, res) {
     var loc = req.params.loc;
     if (loc !== 'tt') {
@@ -148,37 +264,6 @@ app.get('/:loc', function(req, res) {
     }
 });
 
-app.get('/:loc/status', function(req, res) {
-    var loc = req.params.loc;
-    if (loc !== 'tt') {
-        res.status(404).send('Not found');
-    } else {
-        winston.info('GET ' + loc + '/status');
-        // Lookup most recent status from DB and return as JSON.
-        pg.connect(conString, function(err, client, done) {
-            if(err) {
-                return winston.error('error fetching client from pool', err);
-            }
-            var mostRecentStatusQry = 
-            "select origjson " + 
-            "from alerts " + 
-            "where status in ('Open', 'Closed') " +
-            "and coreid = '300029000347343339373536' " +
-            "order by published_at desc " +
-            "limit 1"
-            client.query(mostRecentStatusQry, function(err, result) {
-                //call `done()` to release the client back to the pool
-                done();
-                if(err) {
-                    return winston.error('error running query', err);
-                }
-                res.setHeader('Content-Type', 'application/json');
-                res.send(JSON.stringify(result.rows[0].origjson));
-            });
-        });
-    }
-});
-
 setInterval(function() {
     // Check every hour to see if GoodMorning or GoodEvening has gone missing.
     pg.connect(conString, function(err, client, done) {
diff --git a/views/admin.hbs b/views/admin.hbs
new file mode 100644
index 0000000..7ad2ce6
--- /dev/null
+++ b/views/admin.hbs
@@ -0,0 +1,6 @@
+{{!< default}}
+
+<div style="background: url(banner-bg.jpg) no-repeat center center; background-size: cover; color: #fff" class="jumbotron">
+    <h1 class="text-center">TT Tennis Courts Are...</h1>
+</div>
+
diff --git a/views/login.hbs b/views/login.hbs
new file mode 100644
index 0000000..6b88556
--- /dev/null
+++ b/views/login.hbs
@@ -0,0 +1,19 @@
+{{!< default}}
+
+<div style="background: url(banner-bg.jpg) no-repeat center center; background-size: cover; color: #fff" class="jumbotron">
+    <h1 class="text-center">TT Tennis Courts Are...</h1>
+</div>
+
+<form action="/login" method="post">
+    <div>
+    <label>Username:</label>
+    <input type="text" name="username"/><br/>
+    </div>
+    <div>
+    <label>Password:</label>
+    <input type="password" name="password"/>
+    </div>
+    <div>
+    <input type="submit" value="Submit"/>
+    </div>
+</form>