diff --git a/browserid/lib/db.js b/browserid/lib/db.js
index 482fad4c1d92afa2b94ae982959d540a6f880571..6f235b33f026154ad4e221e1316c4b5060db3db1 100644
--- a/browserid/lib/db.js
+++ b/browserid/lib/db.js
@@ -103,9 +103,12 @@ exports.emailKnown = function(email, cb) {
     });
 };
 
-// XXX: should be moved to async.
-exports.isStaged = function(email) {
-  return g_stagedEmails.hasOwnProperty(email);
+exports.isStaged = function(email, cb) {
+  if (cb) {
+    setTimeout(function() {
+      cb(g_stagedEmails.hasOwnProperty(email));
+    }, 0);
+  }
 };
 
 function generateSecret() {
@@ -174,7 +177,7 @@ exports.addKeyToEmail = function(existing_email, email, pubkey, cb) {
 }
 
 /* takes an argument object including email, password hash, and pubkey. */
-exports.stageUser = function(obj) {
+exports.stageUser = function(obj, cb) {
   var secret = generateSecret();
 
   // overwrite previously staged users
@@ -186,12 +189,11 @@ exports.stageUser = function(obj) {
   };
 
   g_stagedEmails[obj.email] = secret;
-  return secret;
+  setTimeout(function() { cb(secret); }, 0);
 };
 
 /* takes an argument object including email, pass, and pubkey. */
-// XXX: change to async
-exports.stageEmail = function(existing_email, new_email, pubkey) {
+exports.stageEmail = function(existing_email, new_email, pubkey, cb) {
   var secret = generateSecret();
   // overwrite previously staged users
   g_staged[secret] = {
@@ -201,7 +203,7 @@ exports.stageEmail = function(existing_email, new_email, pubkey) {
     pubkey: pubkey
   };
   g_stagedEmails[new_email] = secret;
-  return secret;
+  setTimeout(function() { cb(secret); }, 0);
 };
 
 /* invoked when a user clicks on a verification URL in their email */
diff --git a/browserid/lib/wsapi.js b/browserid/lib/wsapi.js
index 981d12c0f2027f1af5fa59b2afae28ec0eeb1e9f..a2a92233830ebaa4358d36e773c2850271072761 100644
--- a/browserid/lib/wsapi.js
+++ b/browserid/lib/wsapi.js
@@ -72,27 +72,26 @@ function setup(app) {
     try {
       // upon success, stage_user returns a secret (that'll get baked into a url
       // and given to the user), on failure it throws
-      var secret = db.stageUser(stageParams);
-
-      // store the email being registered in the session data
-      if (!req.session) req.session = {};
-
-      // store inside the session the details of this pending verification
-      req.session.pendingVerification = {
-        email: stageParams.email,
-        hash: stageParams.hash // we must store both email and password to handle the case where
-        // a user re-creates an account - specifically, registration status
-        // must ensure the new credentials work to properly verify that
-        // the user has clicked throught the email link. note, this salted, bcrypted
-        // representation of a user's password will get thrust into an encrypted cookie
-        // served over an encrypted (SSL) session.  guten, yah.
-      };
+      db.stageUser(stageParams, function(secret) {
+        // store the email being registered in the session data
+        if (!req.session) req.session = {};
 
-      httputils.jsonResponse(resp, true);
+        // store inside the session the details of this pending verification
+        req.session.pendingVerification = {
+          email: stageParams.email,
+          hash: stageParams.hash // we must store both email and password to handle the case where
+          // a user re-creates an account - specifically, registration status
+          // must ensure the new credentials work to properly verify that
+          // the user has clicked throught the email link. note, this salted, bcrypted
+          // representation of a user's password will get thrust into an encrypted cookie
+          // served over an encrypted (SSL) session.  guten, yah.
+        };
 
-      // let's now kick out a verification email!
-      email.sendVerificationEmail(stageParams.email, stageParams.site, secret);
+        httputils.jsonResponse(resp, true);
 
+        // let's now kick out a verification email!
+        email.sendVerificationEmail(stageParams.email, stageParams.site, secret);
+      });
     } catch(e) {
       // we should differentiate tween' 400 and 500 here.
       httputils.badRequest(resp, e.toString());
@@ -130,7 +129,6 @@ function setup(app) {
     } else {
       // this is a pending registration, let's check if the creds stored on the
       // session are good yet.
-
       var v = req.session.pendingVerification;
       db.checkAuth(v.email, function(hash) {
         if (hash === v.hash) {
@@ -162,17 +160,17 @@ function setup(app) {
 
   app.post('/wsapi/add_email', checkAuthed, checkParams(["email", "pubkey", "site"]), function (req, resp) {
     try {
-      // upon success, stage_user returns a secret (that'll get baked into a url
-      // and given to the user), on failure it throws
-      var secret = db.stageEmail(req.session.authenticatedUser, req.body.email, req.body.pubkey);
+      // on failure stageEmail may throw
+      db.stageEmail(req.session.authenticatedUser, req.body.email, req.body.pubkey, function(secret) {
 
-      // store the email being added in session data
-      req.session.pendingAddition = req.body.email;
+        // store the email being added in session data
+        req.session.pendingAddition = req.body.email;
 
-      httputils.jsonResponse(resp, true);
+        httputils.jsonResponse(resp, true);
 
-      // let's now kick out a verification email!
-      email.sendVerificationEmail(req.body.email, req.body.site, secret);
+        // let's now kick out a verification email!
+        email.sendVerificationEmail(req.body.email, req.body.site, secret);
+      });
     } catch(e) {
       // we should differentiate tween' 400 and 500 here.
       httputils.badRequest(resp, e.toString());
diff --git a/browserid/tests/db-test.js b/browserid/tests/db-test.js
index bd7afd9145bf30bb15b9d2d0f9c6a645b1c353be..04c72b350eb6e2c699d8905776e145889a3ca9e0 100755
--- a/browserid/tests/db-test.js
+++ b/browserid/tests/db-test.js
@@ -32,7 +32,7 @@ var secret = undefined;
 suite.addBatch({
   "an email address is not reported as staged before it is": {
     topic: function() {
-      return db.isStaged('lloyd@nowhe.re');
+      db.isStaged('lloyd@nowhe.re', this.callback);
     },
     "isStaged returns false": function (r) {
       assert.strictEqual(r, false);
@@ -51,13 +51,14 @@ suite.addBatch({
 suite.addBatch({
   "stage a user for creation pending verification": {
     topic: function() {
-      return secret = db.stageUser({
+      db.stageUser({
         email: 'lloyd@nowhe.re',
         pubkey: 'fakepubkey',
         hash: 'fakepasswordhash'
-      });
+      }, this.callback);
     },
     "staging returns a valid secret": function(r) {
+      secret = r;
       assert.isString(secret);
       assert.strictEqual(secret.length, 48);
     }
@@ -67,7 +68,7 @@ suite.addBatch({
 suite.addBatch({
   "an email address is reported": {
     topic: function() {
-      return db.isStaged('lloyd@nowhe.re');
+      db.isStaged('lloyd@nowhe.re', this.callback);
     },
     " as staged after it is": function (r) {
       assert.strictEqual(r, true);
@@ -97,7 +98,7 @@ suite.addBatch({
 suite.addBatch({
   "an email address is not reported": {
     topic: function() {
-      return db.isStaged('lloyd@nowhe.re');
+      db.isStaged('lloyd@nowhe.re', this.callback);
     },
     "as staged immediately after its verified": function (r) {
       assert.strictEqual(r, false);
@@ -161,30 +162,33 @@ suite.addBatch({
 suite.addBatch({
   "staging an email": {
     topic: function() {
-      return db.stageEmail('lloyd@nowhe.re', 'lloyd@somewhe.re', 'fakepubkey4');
+      db.stageEmail('lloyd@nowhe.re', 'lloyd@somewhe.re', 'fakepubkey4', this.callback);
     },
     "yields a valid secret": function(secret) {
       assert.isString(secret);
       assert.strictEqual(secret.length, 48);
     },
-    "makes email addr via isStaged": {
-      topic: function() { return db.isStaged('lloyd@somewhe.re'); },
-      "visible": function(r) { assert.isTrue(r); }
-    },
-    "and verifying it": {
+    "then": {
       topic: function(secret) {
-        db.gotVerificationSecret(secret, this.callback);
-      },
-      "returns no error": function(r) {
-        assert.isUndefined(r);
-      },
-      "makes email addr via knownEmail": {
-        topic: function() { db.emailKnown('lloyd@somewhe.re', this.callback); },
-        "visible": function(r) { assert.isTrue(r); }
+        var cb = this.callback;
+        db.isStaged('lloyd@somewhe.re', function(r) { cb(secret, r); });
       },
-      "makes email addr via isStaged": {
-        topic: function() { return db.isStaged('lloyd@somewhe.re'); },
-        "not visible": function(r) { assert.isFalse(r); }
+      "makes it visible via isStaged": function(sekret, r) { assert.isTrue(r); },
+      "and lets you verify it": {
+        topic: function(secret, r) {
+          db.gotVerificationSecret(secret, this.callback);
+        },
+        "successfully": function(r) {
+          assert.isUndefined(r);
+        },
+        "and knownEmail": {
+          topic: function() { db.emailKnown('lloyd@somewhe.re', this.callback); },
+          "returns true": function(r) { assert.isTrue(r); }
+        },
+        "and isStaged": {
+          topic: function() { db.isStaged('lloyd@somewhe.re', this.callback); },
+          "returns false": function(r) { assert.isFalse(r); }
+        }
       }
     }
   }