diff --git a/.gitmodules b/.gitmodules
deleted file mode 100644
index 65d99631ec153269e6407459382fcb3548d94bf1..0000000000000000000000000000000000000000
--- a/.gitmodules
+++ /dev/null
@@ -1,6 +0,0 @@
-[submodule "lib/doctest"]
-	path = lib/doctest
-	url = git@github.com:ianb/doctestjs
-[submodule "lib/jwcrypto"]
-	path = lib/jwcrypto
-	url = https://github.com/mozilla/jwcrypto.git
diff --git a/browserid/app.js b/browserid/app.js
index 35d8a4f618b09cf36dc463d396379ab2b64e472d..5cfcfe6a1fb14d22f3a8cdb7e89142f0efbbf13e 100644
--- a/browserid/app.js
+++ b/browserid/app.js
@@ -142,7 +142,7 @@ function router(app) {
 
   // vep bundle of JavaScript
   app.get("/vepbundle", function(req, res) {
-    fs.readFile(__dirname + "/../lib/jwcrypto/vepbundle.js", function(error, content) {
+    fs.readFile(__dirname + "/../node_modules/jwcrypto/vepbundle.js", function(error, content) {
       if (error) {
         res.writeHead(500);
         res.end("oops");
diff --git a/browserid/lib/ca.js b/browserid/lib/ca.js
index d6da4f979306a43d54ef6f428c72a9854b88c300..9aee7cacf8965fb8591b4bb81153bcf3b3a79b28 100644
--- a/browserid/lib/ca.js
+++ b/browserid/lib/ca.js
@@ -36,9 +36,9 @@
 
 // certificate authority
 
-var jwcert = require('../../lib/jwcrypto/jwcert'),
-    jwk = require('../../lib/jwcrypto/jwk'),
-    jws = require('../../lib/jwcrypto/jws'),
+var jwcert = require('jwcrypto/jwcert'),
+    jwk = require('jwcrypto/jwk'),
+    jws = require('jwcrypto/jws'),
     configuration = require('../../libs/configuration'),
     secrets = require('../../libs/secrets'),
     path = require("path"),
diff --git a/browserid/tests/ca-test.js b/browserid/tests/ca-test.js
index a5d5a7e356321772eefa0b08da201425136016b4..2e9bdcd54722e8c52da458090bd8a5a508c2b795 100755
--- a/browserid/tests/ca-test.js
+++ b/browserid/tests/ca-test.js
@@ -43,9 +43,9 @@ start_stop = require('./lib/start-stop.js'),
 wsapi = require('./lib/wsapi.js'),
 email = require('../lib/email.js'),
 ca = require('../lib/ca.js'),
-jwcert = require('../../lib/jwcrypto/jwcert'),
-jwk = require('../../lib/jwcrypto/jwk'),
-jws = require('../../lib/jwcrypto/jws');
+jwcert = require('jwcrypto/jwcert'),
+jwk = require('jwcrypto/jwk'),
+jws = require('jwcrypto/jws');
 
 var suite = vows.describe('ca');
 
diff --git a/browserid/tests/cert-emails-test.js b/browserid/tests/cert-emails-test.js
index 0a3241717399f5c0500d574b91d5f644061598b3..7f0d0582f3d11675e4ddee4e149c2fe84261aeb6 100755
--- a/browserid/tests/cert-emails-test.js
+++ b/browserid/tests/cert-emails-test.js
@@ -43,10 +43,10 @@ start_stop = require('./lib/start-stop.js'),
 wsapi = require('./lib/wsapi.js'),
 email = require('../lib/email.js'),
 ca = require('../lib/ca.js'),
-jwcert = require('../../lib/jwcrypto/jwcert'),
-jwk = require('../../lib/jwcrypto/jwk'),
-jws = require('../../lib/jwcrypto/jws'),
-jwt = require('../../lib/jwcrypto/jwt');
+jwcert = require('jwcrypto/jwcert'),
+jwk = require('jwcrypto/jwk'),
+jws = require('jwcrypto/jws'),
+jwt = require('jwcrypto/jwt');
 
 var suite = vows.describe('cert-emails');
 
diff --git a/lib/jwcrypto b/lib/jwcrypto
deleted file mode 160000
index eaaebbce8a32d309200f6d79c405d525b549dd68..0000000000000000000000000000000000000000
--- a/lib/jwcrypto
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit eaaebbce8a32d309200f6d79c405d525b549dd68
diff --git a/libs/secrets.js b/libs/secrets.js
index 73350d2e39f6eafdf958d3fb022bd512a6e4a54b..46ea829f270a236580a16743e92b8217c8bb3ea3 100644
--- a/libs/secrets.js
+++ b/libs/secrets.js
@@ -36,7 +36,7 @@
 const
 path = require('path'),
 fs = require('fs'),
-jwk = require('../lib/jwcrypto/jwk'),
+jwk = require('jwcrypto/jwk'),
 configuration = require("./configuration");
 
 exports.generate = function(chars) {
diff --git a/package.json b/package.json
index 8f82a3b5ff0b53c5ce605de19f16d98f02b64022..a8060d0cf47a3e73225c3aff2c3de306933606a4 100644
--- a/package.json
+++ b/package.json
@@ -25,5 +25,10 @@
     , "colors" : "0.5.0"
     , "sax" : "0.2.3"
     , "mimelib-noiconv" : "0.1.3"
+    , "jwcrypto": "https://github.com/mozilla/jwcrypto/tarball/5d8c79"
+  }
+  , "scripts": {
+    "postinstall": "./scripts/generate_ephemeral_keys.sh",
+    "test": "./scripts/run_all_tests.sh"
   }
 }
diff --git a/prepare_deps.sh b/prepare_deps.sh
deleted file mode 100755
index 90d0d69da89abb144adbe44ebffced9324949534..0000000000000000000000000000000000000000
--- a/prepare_deps.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/bash
-
-npm install
-
-echo '*** Asking for sudo to install browserify globally ***'
-sudo npm install -g browserify
-
-echo '*** Fetching and updating required submodules ***'
-git submodule init
-git submodule update
-
-cd lib/jwcrypto
-./bundle.sh
-
-echo ''
-echo '*** Generating keys and placing them into correct location ***'
-node generate-keypair.js
-
-mv key.publickey ../../var/root.publickey
-mv key.secretkey ../../var/root.secretkey
-cd ../..
-
diff --git a/scripts/generate_ephemeral_keys.sh b/scripts/generate_ephemeral_keys.sh
new file mode 100755
index 0000000000000000000000000000000000000000..a5da918124e102b516502d31871854210b5e60cd
--- /dev/null
+++ b/scripts/generate_ephemeral_keys.sh
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+SCRIPT_DIR="$( cd "$( dirname "$0" )" && pwd )"
+VAR=SCRIPT_DIR/../var
+export PATH=$PATH:$SCRIPT_DIR/../node_modules/.bin
+
+# if keys already exist, do nothing
+if [ -f $VAR/root.publickey ] ; then
+    exit 0
+fi
+
+GENERATE_KEYPAIR=`which generate-keypair 2> /dev/null`
+
+if [ ! -x "$GENERATE_KEYPAIR" ] ; then
+    echo "can't find generate-keypair from the jwcrypto package.  try: npm install"
+    exit 1
+fi
+
+echo '*** Generating ephemeral keys used for testing ***'
+$GENERATE_KEYPAIR
+mkdir -p $VAR
+mv key.publickey $VAR/root.publickey
+mv key.secretkey $VAR/root.secretkey
diff --git a/scripts/run_all_tests.sh b/scripts/run_all_tests.sh
new file mode 100755
index 0000000000000000000000000000000000000000..ed6ab62f2f1afaa86b8cfe1974258dddb0e0d0bc
--- /dev/null
+++ b/scripts/run_all_tests.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+SCRIPT_DIR="$( cd "$( dirname "$0" )" && pwd )"
+BASEDIR=$(dirname $SCRIPT_DIR)
+export PATH=$PATH:$SCRIPT_DIR/../node_modules/.bin
+
+VOWS=`which vows 2> /dev/null`
+if [ ! -x "$VOWS" ]; then
+    echo "vows not found in your path.  try:  npm install"
+    exit 1
+fi
+
+# vows hates absolute paths.  sheesh.
+cd $BASEDIR
+
+for env in test_json test_mysql ; do
+  export NODE_ENV=$env
+  $SCRIPT_DIR/test_db_connectivity.js
+  if [ $? = 0 ] ; then 
+      echo "Testing with NODE_ENV=$env"
+      for file in browserid/tests/*.js ; do
+          echo $file
+          vows $file
+          if [[ $? != 0 ]] ; then
+              exit 1
+          fi
+      done
+  else
+      echo "CANNOT TEST '$env' ENVIRONMENT: can't connect to the database"
+  fi
+done
diff --git a/test.sh b/test.sh
index 7dec3f2b6fedfd6b8b16035156f1f5ff732ac050..b41801ed1cbc80f3f397258f877b52aa5a4e0910 100755
--- a/test.sh
+++ b/test.sh
@@ -1,23 +1,3 @@
-#!/bin/bash
+#!/bin/sh
 
-VOWS=`which vows 2> /dev/null`
-if [ ! -x "$VOWS" ]; then
-    echo "vows not found in your path.  try:  npm install -g vows"
-    exit 1
-fi
-
-for env in test_json test_mysql ; do
-  export NODE_ENV=$env
-  ./scripts/test_db_connectivity.js
-  if [ $? = 0 ] ; then 
-      echo "Testing with NODE_ENV=$env"
-      for file in browserid/tests/*.js ; do
-          vows $file
-          if [[ $? != 0 ]] ; then
-              exit 1
-          fi
-      done
-  else
-      echo "CANNOT TEST '$env' ENVIRONMENT: can't connect to the database"
-  fi
-done
+npm test
diff --git a/verifier/lib/certassertion.js b/verifier/lib/certassertion.js
index bb8d2569c5625dd8abfff3e40836c1f9f221c39c..c2f88a1b81da46ea78c74687149cce1840a45451 100644
--- a/verifier/lib/certassertion.js
+++ b/verifier/lib/certassertion.js
@@ -41,10 +41,10 @@ const xml2js = require("xml2js/lib/xml2js"),
 http = require("http"),
 https = require("https"),
 url = require("url"),
-jwk = require("../../lib/jwcrypto/jwk"),
-jwt = require("../../lib/jwcrypto/jwt"),
-jwcert = require("../../lib/jwcrypto/jwcert"),
-vep = require("../../lib/jwcrypto/vep"),
+jwk = require("jwcrypto/jwk"),
+jwt = require("jwcrypto/jwt"),
+jwcert = require("jwcrypto/jwcert"),
+vep = require("jwcrypto/vep"),
 configuration = require('../../libs/configuration'),
 secrets = require('../../libs/secrets'),
 logger = require("../../libs/logging.js").logger;
diff --git a/verifier/test/certassertion-test.js b/verifier/test/certassertion-test.js
index 87d111051cbc0dde56e940fa2eca1ed7ca732426..24edbead4e003185e41a33d3f8b354f6d85eb992 100644
--- a/verifier/test/certassertion-test.js
+++ b/verifier/test/certassertion-test.js
@@ -37,10 +37,10 @@
 var vows = require("vows"),
     assert = require("assert"),
     certassertion = require("../lib/certassertion"),
-    jwk = require("../../lib/jwcrypto/jwk"),
-    jwt = require("../../lib/jwcrypto/jwt"),
-    jwcert = require("../../lib/jwcrypto/jwcert"),
-    vep = require("../../lib/jwcrypto/vep"),
+    jwk = require("jwcrypto/jwk"),
+    jwt = require("jwcrypto/jwt"),
+    jwcert = require("jwcrypto/jwcert"),
+    vep = require("jwcrypto/vep"),
     events = require("events");
 
 vows.describe('certassertion').addBatch({