diff --git a/resources/static/dialog/controllers/pick_email.js b/resources/static/dialog/controllers/pick_email.js
index b57933026038d0c3e1c9508d579016fda9d53538..61e65c469480a0f29a03415f979895d3506b5abf 100644
--- a/resources/static/dialog/controllers/pick_email.js
+++ b/resources/static/dialog/controllers/pick_email.js
@@ -27,14 +27,14 @@ BrowserID.Modules.PickEmail = (function() {
   }
 
   function addEmail() {
-    this.close("add_email");
+    this.publish("add_email");
   }
 
   function checkEmail(email) {
     var identity = user.getStoredEmailKeypair(email);
     if (!identity) {
       alert(gettext("The selected email is invalid or has been deleted."));
-      this.close("assertion_generated", {
+      this.publish("assertion_generated", {
         assertion: null
       });
     }
@@ -76,6 +76,10 @@ BrowserID.Modules.PickEmail = (function() {
     }
   }
 
+  function notMe() {
+    this.publish("notme");
+  }
+
   var Module = bid.Modules.PageModule.extend({
     start: function(options) {
       var origin = user.getOrigin(),
@@ -104,6 +108,7 @@ BrowserID.Modules.PickEmail = (function() {
       // is needed for the label handler so that the correct radio button is
       // selected.
       self.bind("#selectEmail label", "click", proxyEventToInput);
+      self.click("#thisIsNotMe", notMe);
 
       sc.start.call(self, options);
 
@@ -118,7 +123,8 @@ BrowserID.Modules.PickEmail = (function() {
     // BEGIN TESTING API
     ,
     signIn: signIn,
-    addEmail: addEmail
+    addEmail: addEmail,
+    notMe: notMe
     // END TESTING API
   });
 
diff --git a/resources/static/dialog/resources/helpers.js b/resources/static/dialog/resources/helpers.js
index f6997994ae2f59fbcc45bb8f5cf712a92791be4d..5065a994c952b0f0c67dbca6a8ee4c73aab82a6a 100644
--- a/resources/static/dialog/resources/helpers.js
+++ b/resources/static/dialog/resources/helpers.js
@@ -97,7 +97,7 @@
       complete(callback, false);
     }
     else {
-      BrowserID.User.addressInfo(email, function(info) {
+      user.addressInfo(email, function(info) {
         if (info.type === "primary") {
           var info = _.extend(info, { email: email, add: true });
           self.publish("primary_user", info, info);
diff --git a/resources/static/pages/forgot.js b/resources/static/pages/forgot.js
index 4b3d086977b7d1d8a58a45f343692b40a1e57eff..5d7c9385355f1dbc1eca1ff0bf85b826b867997e 100644
--- a/resources/static/pages/forgot.js
+++ b/resources/static/pages/forgot.js
@@ -9,6 +9,8 @@ BrowserID.forgot = (function() {
   var bid = BrowserID,
       user = bid.User,
       helpers = bid.Helpers,
+      complete = helpers.complete,
+      validation = bid.Validation,
       pageHelpers = bid.PageHelpers,
       cancelEvent = pageHelpers.cancelEvent,
       dom = bid.DOM,
@@ -18,21 +20,24 @@ BrowserID.forgot = (function() {
     // GET RID OF THIS HIDE CRAP AND USE CSS!
     $(".notifications .notification").hide();
 
-    var email = helpers.getAndValidateEmail("#email");
+    var email = helpers.getAndValidateEmail("#email"),
+        pass = dom.getInner("#password"),
+        vpass = dom.getInner("#vpassword"),
+        validPass = email && validation.passwordAndValidationPassword(pass, vpass);
 
-    if (email) {
-      // XXX TODO - the fake password is to make tests pass.
-      user.requestPasswordReset(email, "XXX_FAKE_PASSWORD", function onSuccess(info) {
+    if (email && validPass) {
+      user.requestPasswordReset(email, pass, function onSuccess(info) {
         if (info.success) {
           pageHelpers.emailSent(oncomplete);
         }
         else {
           var tooltipEl = info.reason === "throttle" ? "#could_not_add" : "#not_registered";
-          tooltip.showTooltip(tooltipEl, oncomplete);
+          tooltip.showTooltip(tooltipEl);
+          complete(oncomplete);
         }
       }, pageHelpers.getFailure(bid.Errors.requestPasswordReset, oncomplete));
     } else {
-      oncomplete && oncomplete();
+      complete(oncomplete);
     }
   };
 
diff --git a/resources/static/shared/modules/page_module.js b/resources/static/shared/modules/page_module.js
index 1de6032ac423feae10a1fd7454ff3f429331dbf0..48faf9b8442c6c09f409bf802f59c5cbb3d69965 100644
--- a/resources/static/shared/modules/page_module.js
+++ b/resources/static/shared/modules/page_module.js
@@ -54,8 +54,6 @@ BrowserID.Modules.PageModule = (function() {
       self.options = options || {};
 
       self.bind("form", "submit", cancelEvent(onSubmit));
-      // TODO - why is this here and not in pick_email?
-      self.click("#thisIsNotMe", self.close.bind(self, "notme"));
     },
 
     stop: function() {
diff --git a/resources/static/test/cases/controllers/authenticate.js b/resources/static/test/cases/controllers/authenticate.js
index 653a7bd19256038e177a3a18644a5724230d38b4..e410de5e57adfa512fbdd34e96339a1528a49930 100644
--- a/resources/static/test/cases/controllers/authenticate.js
+++ b/resources/static/test/cases/controllers/authenticate.js
@@ -190,37 +190,5 @@
     });
   });
 
-  /*
-  asyncTest("createUser with valid email but throttling", function() {
-    $("#email").val("unregistered@testuser.com");
-
-    var handlerCalled = false;
-    register("new_user", function(msg, info) {
-      handlerCalled = true;
-    });
-
-    xhr.useResult("throttle");
-    controller.createUser(function() {
-      equal(handlerCalled, false, "bad jiji, new_user should not have been called with throttling");
-      equal(bid.Tooltip.shown, true, "tooltip is shown");
-      start();
-    });
-  });
-
-  asyncTest("createUser with valid email, XHR error", function() {
-    $("#email").val("unregistered@testuser.com");
-
-    var handlerCalled = false;
-    register("new_user", function(msg, info) {
-      handlerCalled = true;
-    });
-
-    xhr.useResult("ajaxError");
-    controller.createUser(function() {
-      equal(handlerCalled, false, "bad jiji, new_user should not have been called with XHR error");
-      start();
-    });
-  });
-*/
 }());
 
diff --git a/resources/static/test/cases/controllers/pick_email.js b/resources/static/test/cases/controllers/pick_email.js
index 7b560c6b5e4df29a3990cb0ee95b857bc849af4e..555d2f4631c63ae0c9949339feab0e389c180e2c 100644
--- a/resources/static/test/cases/controllers/pick_email.js
+++ b/resources/static/test/cases/controllers/pick_email.js
@@ -137,5 +137,16 @@
     equal($("#email_0").is(":checked"), true, "radio button is correctly selected");
   });
 
+  asyncTest("click on not me button - trigger notme message", function() {
+    createController();
+
+    register("notme", function(msg, info) {
+      ok(true, "notme triggered");
+      start();
+    });
+
+    $("#thisIsNotMe").click();
+  });
+
 }());
 
diff --git a/resources/static/test/cases/pages/forgot.js b/resources/static/test/cases/pages/forgot.js
index 22491ef900b829917dda7841d34b89671b0a492f..d1b1466193204d8a576cd6fc0a99bdc23ab57b39 100644
--- a/resources/static/test/cases/pages/forgot.js
+++ b/resources/static/test/cases/pages/forgot.js
@@ -24,60 +24,99 @@
     }
   });
 
-  function testEmailNotSent(extraTests) {
+  function testEmailNotSent(config) {
+    config = config || {};
     bid.forgot.submit(function() {
       equal($(".emailsent").is(":visible"), false, "email not sent");
-      if (extraTests) extraTests();
+      if(config.checkTooltip !== false) testHelpers.testTooltipVisible();
+      if (config.ready) config.ready();
       else start();
     });
   }
 
   asyncTest("requestPasswordReset with invalid email", function() {
     $("#email").val("invalid");
+    $("#password,#vpassword").val("password");
 
     xhr.useResult("invalid");
 
     testEmailNotSent();
   });
 
-  asyncTest("requestPasswordReset with known email", function() {
+  asyncTest("requestPasswordReset with known email, happy case - show email sent notice", function() {
     $("#email").val("registered@testuser.com");
+    $("#password,#vpassword").val("password");
+
     bid.forgot.submit(function() {
       ok($(".emailsent").is(":visible"), "email sent successfully");
       start();
     });
   });
 
-  asyncTest("requestPasswordReset with known email with leading/trailing whitespace", function() {
+  asyncTest("requestPasswordReset with known email with leading/trailing whitespace - show email sent notice", function() {
     $("#email").val("   registered@testuser.com  ");
+    $("#password,#vpassword").val("password");
+
     bid.forgot.submit(function() {
       ok($(".emailsent").is(":visible"), "email sent successfully");
       start();
     });
   });
 
+  asyncTest("requestPasswordReset with missing password", function() {
+    $("#email").val("unregistered@testuser.com");
+    $("#vpassword").val("password");
+
+    testEmailNotSent();
+  });
+
+  asyncTest("requestPasswordReset with too short of a password", function() {
+    $("#email").val("unregistered@testuser.com");
+    $("#password,#vpassword").val("fail");
+
+    testEmailNotSent();
+  });
+
+  asyncTest("requestPasswordReset with too long of a password", function() {
+    $("#email").val("unregistered@testuser.com");
+    $("#password,#vpassword").val(testHelpers.generateString(81));
+
+    testEmailNotSent();
+  });
+
+  asyncTest("requestPasswordReset with missing vpassword", function() {
+    $("#email").val("unregistered@testuser.com");
+    $("#password").val("password");
+
+    testEmailNotSent();
+  });
+
   asyncTest("requestPasswordReset with unknown email", function() {
     $("#email").val("unregistered@testuser.com");
+    $("#password,#vpassword").val("password");
 
     testEmailNotSent();
   });
 
   asyncTest("requestPasswordReset with throttling", function() {
-    xhr.useResult("throttle");
-
-    $("#email").val("throttled@testuser.com");
+    $("#email").val("registered@testuser.com");
+    $("#password,#vpassword").val("password");
 
+    xhr.useResult("throttle");
     testEmailNotSent();
   });
 
   asyncTest("requestPasswordReset with XHR Error", function() {
-    xhr.useResult("ajaxError");
-
     $("#email").val("testuser@testuser.com");
+    $("#password,#vpassword").val("password");
 
-    testEmailNotSent(function() {
-      testHelpers.testErrorVisible();
-      start();
+    xhr.useResult("ajaxError");
+    testEmailNotSent({
+      ready: function() {
+        testHelpers.testErrorVisible();
+        start();
+      },
+      checkTooltip: false
     });
   });
 
diff --git a/resources/views/forgot.ejs b/resources/views/forgot.ejs
index f249dc610c694a19aaf15ed8c894aab0b6cad483..fea0f0c37a75d4f66421a65586bebf887bb0756c 100644
--- a/resources/views/forgot.ejs
+++ b/resources/views/forgot.ejs
@@ -46,6 +46,36 @@
                     </div>
                 </li>
 
+                <li>
+                    <label class="serif" for="password">Password</label>
+                    <input class="sans" id="password" placeholder="Password" type="password" maxlength="80">
+
+                    <div id="password_required" class="tooltip" for="password">
+                        Password is required.
+                    </div>
+
+                    <div class="tooltip" id="password_length" for="password">
+                        Password must be between 8 and 80 characters long.
+                    </div>
+
+                    <div id="could_not_add" class="tooltip" for="password">
+                        We just sent an email to that address! If you really want to send another, wait a minute or two and try again.
+                    </div>
+                </li>
+
+                <li>
+                    <label class="serif" for="vpassword">Verify Password</label>
+                    <input class="sans" id="vpassword" placeholder="Repeat Password" type="password" maxlength="80">
+
+                    <div id="password_required" class="tooltip" for="vpassword">
+                      Verification password is required.
+                    </div>
+
+                    <div class="tooltip" id="passwords_no_match" for="vpassword">
+                      Passwords do not match.
+                    </div>
+
+                </li>
 
             </ul>