diff --git a/browserid/app.js b/browserid/app.js
index c62b6a2d8ec9dc419cb9c7a3e7d0805825691083..a1389e66b44fdad9b73668720653534f2d0dc4fa 100644
--- a/browserid/app.js
+++ b/browserid/app.js
@@ -18,6 +18,7 @@ secrets = require('./lib/secrets.js'),
 db = require('./lib/db.js'),
 configuration = require('../libs/configuration.js'),
 substitution = require('../libs/substitute.js');
+logging = require("../libs/logging.js");
 
 // looks unused, see run.js
 // const STATIC_DIR = path.join(path.dirname(__dirname), "static");
@@ -40,7 +41,8 @@ function router(app) {
 
   // this should probably be an internal redirect
   // as soon as relative paths are figured out.
-  app.get('/sign_in', function(req, res, next ){
+  app.get('/sign_in', function(req, res, next ) {
+    logging.userEntry('browserid', req);
     res.render('dialog.ejs', {
       title: 'A Better Way to Sign In',
       layout: false,
diff --git a/libs/configuration.js b/libs/configuration.js
index b3cfa84f70ec3f3773e7f0e9503d555ae30db65d..2690dc1f2fa1eb02b72e072f1f0cca4e436cd439 100644
--- a/libs/configuration.js
+++ b/libs/configuration.js
@@ -25,25 +25,29 @@ const g_configs = {
     hostname: 'browserid.org',
     port: '443',
     scheme: 'https',
-    use_minified_resources: true
+    use_minified_resources: true,
+    log_path: '/home/browserid/var/'
   },
   development: {
     hostname: 'dev.diresworb.org',
     port: '443',
     scheme: 'https',
-    use_minified_resources: true
+    use_minified_resources: true,
+    log_path: '/home/browserid/var/'
   },
   beta: {
     hostname: 'diresworb.org',
     port: '443',
     scheme: 'https',
-    use_minified_resources: true
+    use_minified_resources: true,
+    log_path: '/home/browserid/var/'
   },
   local: {
     hostname: '127.0.0.1',
     port: '10002',
     scheme: 'http',
-    use_minified_resources: false
+    use_minified_resources: false,
+    log_path: './'
   }
 };
 
diff --git a/libs/logging.js b/libs/logging.js
new file mode 100644
index 0000000000000000000000000000000000000000..c34aaa0c15ad10cd60c1f1c93b3f7968fb02dc0e
--- /dev/null
+++ b/libs/logging.js
@@ -0,0 +1,52 @@
+const winston = require("winston");
+const configuration = require("./configuration");
+
+// go through the configuration and determine log location
+// for now we only log to one place
+// FIXME: separate logs depending on purpose?
+
+var log_path = configuration.get('log_path');
+var LOGGERS = [];
+
+function setupLogger(category) {
+  if (!log_path)
+    return console.log("no log path! Not logging!");
+
+  // don't create the logger if it already exists
+  if (LOGGERS[category])
+    return;
+
+  // FIXME: check if log_path is properly terminated
+  var filename = log_path + category + "-log.txt";
+
+  LOGGERS[category] = new (winston.Logger)({
+      transports: [new (winston.transports.File)({filename: filename})]
+    });
+}
+
+// entry is an object that will get JSON'ified
+exports.log = function(category, entry) {
+  // entry must have at least a type
+  if (!entry.type)
+    throw new Error("every log entry needs a type");
+
+  // setup the logger if need be
+  setupLogger(category);
+
+  // timestamp
+  entry.at = new Date().toUTCString();
+  
+  // if no logger, go to console (FIXME: do we really want to log to console?)
+  LOGGERS[category].info(JSON.stringify(entry));
+};
+
+// utility function to log a bunch of stuff at user entry point
+exports.userEntry = function(category, req) {
+  exports.log(category, {
+      type: 'signin',
+      browser: req.headers['user-agent'],
+      rp: req.headers['referer'],
+      // IP address (this probably needs to be replaced with the X-forwarded-for value
+      ip: req.connection.remoteAddress
+    });
+};
\ No newline at end of file
diff --git a/package.json b/package.json
index 78fdad42fca3a034200031b76e68b1a78cbccad4..85c35908c725152607c0677f34bc86688554478d 100644
--- a/package.json
+++ b/package.json
@@ -15,5 +15,6 @@
     , "temp": "0.2.0"
     , "express-csrf": "0.3.2"
     , "uglify-js": "1.0.6"
+    , "winston" : "0.3.3"
   }
 }
\ No newline at end of file
diff --git a/verifier/app.js b/verifier/app.js
index 2503a31be9d9a96453519c08f6a5a04623e69773..740311628d5b61c10b057ce1f4843313cd60e87d 100644
--- a/verifier/app.js
+++ b/verifier/app.js
@@ -5,6 +5,7 @@ const   path = require('path'),
  idassertion = require('./lib/idassertion.js'),
          jwt = require('./lib/jwt.js'),
      express = require('express');
+     logging = require('../libs/logging.js');
 
 // create the var directory if it doesn't exist
 var VAR_DIR = path.join(__dirname, "var");
@@ -35,6 +36,13 @@ function doVerify(req, resp, next) {
       .verify(
         audience,
         function(payload) {
+          // log it!
+          logging.log('verifier', {
+              type: 'verify',
+                result: 'success',
+                rp: payload.audience
+            });
+          
           result = {
             status : "okay",
             email : payload.email,
@@ -45,11 +53,21 @@ function doVerify(req, resp, next) {
           resp.json(result);
         },
         function(errorObj) {
+          logging.log('verifier', {
+              type: 'verify',
+                result: 'failure',
+                rp: audience
+            });
           resp.json({ status: "failure", reason: errorObj });
         }
       );
   } catch (e) {
     console.log(e.stack);
+    logging.log('verifier', {
+        type: 'verify',
+          result: 'failure',
+          rp: audience
+          });
     resp.json({ status: "failure", reason: e.toString() });
   }
 }