diff --git a/lib/static_resources.js b/lib/static_resources.js
index 8f88114a98a55ebb9388d63900121d624762dca8..26e7b85da8382394fb43fc3e25908537300ec86d 100644
--- a/lib/static_resources.js
+++ b/lib/static_resources.js
@@ -99,6 +99,7 @@ var dialog_js = und.flatten([
     '/dialog/controllers/primary_user_provisioned.js',
     '/dialog/controllers/generate_assertion.js',
     '/dialog/controllers/is_this_your_computer.js',
+    '/dialog/controllers/set_password.js',
 
     '/dialog/start.js'
   ]]);
diff --git a/resources/static/dialog/controllers/actions.js b/resources/static/dialog/controllers/actions.js
index 08239b6befc50e5b56547823020dd07a5b7ef5a1..c674f1dc972f1d3f11ded20320ce5de36f91afe6 100644
--- a/resources/static/dialog/controllers/actions.js
+++ b/resources/static/dialog/controllers/actions.js
@@ -73,6 +73,15 @@ BrowserID.Modules.Actions = (function() {
       if(onsuccess) onsuccess(null);
     },
 
+    doSetPassword: function(info) {
+      startService("set_password", info);
+    },
+
+    doStageUser: function(info) {
+      var email = info.email;
+      bid.Helpers.Dialog.createUser.call(this, email);
+    },
+
     doConfirmUser: function(info) {
       startRegCheckService.call(this, info, "waitForUserValidation", "user_confirmed");
     },
diff --git a/resources/static/dialog/controllers/authenticate.js b/resources/static/dialog/controllers/authenticate.js
index a842fecc0bc196695f8f690c90bc65903c387676..16dc1063451b9c77c2a19a95eab87b39abf7edc1 100644
--- a/resources/static/dialog/controllers/authenticate.js
+++ b/resources/static/dialog/controllers/authenticate.js
@@ -61,7 +61,8 @@ BrowserID.Modules.Authenticate = (function() {
       else if(info.known) {
         enterPasswordState.call(self);
       } else {
-        createSecondaryUserState.call(self);
+        self.close("new_user", { email: email });
+        //createSecondaryUserState.call(self);
       }
     }
   }
@@ -71,9 +72,10 @@ BrowserID.Modules.Authenticate = (function() {
         email = getEmail();
 
     if (email) {
-      dialogHelpers.createUser.call(self, email, callback);
+      self.close("new_user", { email: email });
+      //dialogHelpers.createUser.call(self, email, callback);
     } else {
-      callback && callback();
+      complete(callback);
     }
   }
 
diff --git a/resources/static/dialog/controllers/set_password.js b/resources/static/dialog/controllers/set_password.js
new file mode 100644
index 0000000000000000000000000000000000000000..334aab99ba76118eb8bae558503b1f5ec5c7f9c0
--- /dev/null
+++ b/resources/static/dialog/controllers/set_password.js
@@ -0,0 +1,47 @@
+/*jshint browser:true, jQuery: true, forin: true, laxbreak:true */
+/*global _: true, BrowserID: true, PageController: true */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+BrowserID.Modules.SetPassword = (function() {
+  "use strict";
+  var bid = BrowserID,
+      dom = bid.DOM,
+      complete = bid.Helpers.complete,
+      sc;
+
+  function submit(callback) {
+    var pass = dom.getInner("#password"),
+        vpass = dom.getInner("#vpassword");
+
+    var valid = bid.Validation.passwordAndValidationPassword(pass, vpass);
+    if(valid) {
+      this.close("password_set", { password: pass });
+    }
+
+    complete(callback, valid);
+  }
+
+  function cancel() {
+    this.close("cancel_state");
+  }
+
+  var Module = bid.Modules.PageModule.extend({
+    start: function(options) {
+      var self=this;
+
+      self.renderDialog("set_password");
+
+      self.click("#cancel", cancel);
+
+      sc.start.call(self, options);
+    },
+
+    submit: submit,
+    cancel: cancel
+  });
+
+  sc = Module.sc;
+
+  return Module;
+}());
diff --git a/resources/static/dialog/resources/state.js b/resources/static/dialog/resources/state.js
index a96d5b8881da56ca8efda4538b355de817b3cf7b..2103ffd00b9f38227dbd053641a399b0895d7657 100644
--- a/resources/static/dialog/resources/state.js
+++ b/resources/static/dialog/resources/state.js
@@ -93,6 +93,18 @@ BrowserID.State = (function() {
       startAction("doAuthenticate", info);
     });
 
+    handleState("new_user", function(msg, info) {
+      self.newUserEmail = info.email;
+      startAction("doSetPassword", info);
+    });
+
+    handleState("password_set", function(msg, info) {
+      info = info || {};
+      info.email = self.newUserEmail;
+
+      startAction("doStageUser", info);
+    });
+
     handleState("user_staged", function(msg, info) {
       self.stagedEmail = info.email;
       info.required = !!requiredEmail;
diff --git a/resources/static/dialog/start.js b/resources/static/dialog/start.js
index 45e04d4fb15c4d2f7c590eed8a4a213e9b78bfbe..14cfe1cf38a156420204ee39bf06caced07ed822 100644
--- a/resources/static/dialog/start.js
+++ b/resources/static/dialog/start.js
@@ -33,6 +33,7 @@
       moduleManager.register("generate_assertion", modules.GenerateAssertion);
       moduleManager.register("xhr_delay", modules.XHRDelay);
       moduleManager.register("xhr_disable_form", modules.XHRDisableForm);
+      moduleManager.register("set_password", modules.SetPassword);
 
       moduleManager.start("xhr_delay");
       moduleManager.start("xhr_disable_form");
diff --git a/resources/static/dialog/views/set_password.ejs b/resources/static/dialog/views/set_password.ejs
new file mode 100644
index 0000000000000000000000000000000000000000..dff785aea66004ac9f2ceb3d8b0b30740d512599
--- /dev/null
+++ b/resources/static/dialog/views/set_password.ejs
@@ -0,0 +1,45 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+  <strong><%= gettext('Welcome to BrowserID!') %></strong>
+
+  <div class="form_section" id="set_password">
+      <ul class="inputs">
+          <li>
+              <%= gettext('This email looks new, so let&#39;s get you set up.') %>
+          </li>
+
+          <li>
+              <label for="password" class="serif"><%= gettext('Password') %></label>
+              <input id="password" class="sans" type="password" maxlength="80" />
+
+              <div class="tooltip" id="password_required" for="password">
+                <%= gettext('Password is required.') %>
+              </div>
+
+              <div class="tooltip" id="password_length" for="password">
+                <%= gettext('Password must be between 8 and 80 characters long.') %>
+              </div>
+          </li>
+
+          <li>
+              <label class="serif" for="vpassword"><%= gettext('Verify Password') %></label>
+              <input class="sans" id="vpassword" placeholder="<%= gettext('Repeat Password') %>" type="password" maxlength=80 />
+
+              <div class="tooltip" id="vpassword_required" for="vpassword">
+                <%= gettext('Verification password is required.') %>
+              </div>
+
+              <div class="tooltip" id="passwords_no_match" for="vpassword">
+                <%= gettext('Passwords do not match.') %>
+              </div>
+          </li>
+
+      </ul>
+
+      <div class="submit cf">
+          <button><%= gettext('verify email') %></button>
+          <a id="cancel" href="#"><%= gettext('cancel') %></a>
+      </div>
+  </div>
diff --git a/resources/static/shared/modules/page_module.js b/resources/static/shared/modules/page_module.js
index b47ecf8ac7a2a496634f1b6c4ed87e437fb3e3d0..97936af09a65b43e68b8bd327edaf53491641973 100644
--- a/resources/static/shared/modules/page_module.js
+++ b/resources/static/shared/modules/page_module.js
@@ -52,6 +52,7 @@ BrowserID.Modules.PageModule = (function() {
     start: function(options) {
       var self=this;
       self.bind("form", "submit", cancelEvent(onSubmit));
+      // TODO - why is this here and not in pick_email?
       self.click("#thisIsNotMe", self.close.bind(self, "notme"));
     },
 
diff --git a/resources/static/test/cases/controllers/authenticate.js b/resources/static/test/cases/controllers/authenticate.js
index dedd5352ca678c405250f5e39f0be16168d3648b..e758e5a065d7f44edf661b74b44c3cf47baa5865 100644
--- a/resources/static/test/cases/controllers/authenticate.js
+++ b/resources/static/test/cases/controllers/authenticate.js
@@ -80,7 +80,7 @@
   });
 
   function testUserUnregistered() {
-    register("create_user", function() {
+    register("new_user", function() {
       ok(true, "email was valid, user not registered");
       start();
     });
@@ -88,14 +88,14 @@
     controller.checkEmail();
   }
 
-  asyncTest("checkEmail with unknown secondary email, expect 'create_user' message", function() {
+  asyncTest("checkEmail with unknown secondary email, expect 'new_user' message", function() {
     $("#email").val("unregistered@testuser.com");
     xhr.useResult("unknown_secondary");
 
     testUserUnregistered();
   });
 
-  asyncTest("checkEmail with email with leading/trailing whitespace, user not registered, expect 'create_user' message", function() {
+  asyncTest("checkEmail with email with leading/trailing whitespace, user not registered, expect 'new_user' message", function() {
     $("#email").val("    unregistered@testuser.com   ");
     xhr.useResult("unknown_secondary");
 
@@ -165,8 +165,8 @@
     $("#email").val("unregistered@testuser.com");
     xhr.useResult("unknown_secondary");
 
-    register("user_staged", function(msg, info) {
-      equal(info.email, "unregistered@testuser.com", "user_staged with correct email triggered");
+    register("new_user", function(msg, info) {
+      equal(info.email, "unregistered@testuser.com", "new_user with correct email triggered");
       start();
     });
 
@@ -177,27 +177,28 @@
     $("#email").val("unregistered");
 
     var handlerCalled = false;
-    register("user_staged", function(msg, info) {
+    register("new_user", function(msg, info) {
       handlerCalled = true;
     });
 
     controller.createUser(function() {
-      equal(handlerCalled, false, "bad jiji, user_staged should not have been called with invalid email");
+      equal(handlerCalled, false, "bad jiji, new_user should not have been called with invalid email");
       start();
     });
   });
 
+  /*
   asyncTest("createUser with valid email but throttling", function() {
     $("#email").val("unregistered@testuser.com");
 
     var handlerCalled = false;
-    register("user_staged", function(msg, info) {
+    register("new_user", function(msg, info) {
       handlerCalled = true;
     });
 
     xhr.useResult("throttle");
     controller.createUser(function() {
-      equal(handlerCalled, false, "bad jiji, user_staged should not have been called with throttling");
+      equal(handlerCalled, false, "bad jiji, new_user should not have been called with throttling");
       equal(bid.Tooltip.shown, true, "tooltip is shown");
       start();
     });
@@ -207,16 +208,16 @@
     $("#email").val("unregistered@testuser.com");
 
     var handlerCalled = false;
-    register("user_staged", function(msg, info) {
+    register("new_user", function(msg, info) {
       handlerCalled = true;
     });
 
     xhr.useResult("ajaxError");
     controller.createUser(function() {
-      equal(handlerCalled, false, "bad jiji, user_staged should not have been called with XHR error");
+      equal(handlerCalled, false, "bad jiji, new_user should not have been called with XHR error");
       start();
     });
   });
-
+*/
 }());
 
diff --git a/resources/static/test/cases/controllers/set_password.js b/resources/static/test/cases/controllers/set_password.js
new file mode 100644
index 0000000000000000000000000000000000000000..2398f3221e5d237c8c60fe8a76e7ef76da4ff395
--- /dev/null
+++ b/resources/static/test/cases/controllers/set_password.js
@@ -0,0 +1,61 @@
+/*jshint browsers:true, forin: true, laxbreak: true */
+/*global test: true, start: true, stop: true, module: true, ok: true, equal: true, BrowserID:true */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+(function() {
+  "use strict";
+
+  var controller,
+      el = $("body"),
+      bid = BrowserID,
+      testHelpers = bid.TestHelpers,
+      register = testHelpers.register,
+      controller;
+
+  function createController(options) {
+    controller = bid.Modules.SetPassword.create();
+    controller.start(options);
+  }
+
+  module("controllers/set_password", {
+    setup: function() {
+      testHelpers.setup();
+      createController();
+    },
+
+    teardown: function() {
+      controller.destroy();
+      testHelpers.teardown();
+    }
+  });
+
+
+  test("create - show correct template", function() {
+    ok($("#set_password").length, "set_password template added");
+  });
+
+  asyncTest("submit with good password/vpassword - password_set message raised", function() {
+    $("#password").val("password");
+    $("#vpassword").val("password");
+
+    var password;
+    register("password_set", function(msg, info) {
+      password = info.password;
+    });
+
+    controller.submit(function() {
+      ok(password, "password", "password_set message raised with correct password");
+      start();
+    });
+  });
+
+  asyncTest("cancel - cancel_state message raised", function() {
+    register("cancel_state", function(msg, info) {
+      ok(true, "state cancelled");
+      start();
+    });
+
+    $("#cancel").click();
+  });
+}());
diff --git a/resources/static/test/cases/resources/state.js b/resources/static/test/cases/resources/state.js
index 83e6c7cf6164e71f77b0befcd479e5a3754928ef..4ce48b1ba92e1058251a34adf57a579a97569a75 100644
--- a/resources/static/test/cases/resources/state.js
+++ b/resources/static/test/cases/resources/state.js
@@ -78,10 +78,21 @@
     equal(error, "start: controller must be specified", "creating a state machine without a controller fails");
   });
 
+  test("new_user - call doSetPassword with correct email", function() {
+    mediator.publish("new_user", { email: TEST_EMAIL });
+
+    equal(actions.info.doSetPassword.email, TEST_EMAIL, "correct email sent to doSetPassword");
+  });
+
+  test("password_set - call doStageUser with correct email", function() {
+    mediator.publish("new_user", { email: TEST_EMAIL });
+    mediator.publish("password_set");
+
+    equal(actions.info.doStageUser.email, TEST_EMAIL, "correct email sent to doStageUser");
+  });
+
   test("user_staged - call doConfirmUser", function() {
-    mediator.publish("user_staged", {
-      email: TEST_EMAIL
-    });
+    mediator.publish("user_staged", { email: TEST_EMAIL });
 
     equal(actions.info.doConfirmUser.email, TEST_EMAIL, "waiting for email confirmation for testuser@testuser.com");
   });
diff --git a/resources/views/test.ejs b/resources/views/test.ejs
index a1fb2cd58698ae93864018bbfaeee0935584d76c..a6cf9e9130619aa6d1c9cc89e90acc61cfbd2019 100644
--- a/resources/views/test.ejs
+++ b/resources/views/test.ejs
@@ -126,6 +126,7 @@
     <script src="/dialog/controllers/provision_primary_user.js"></script>
     <script src="/dialog/controllers/primary_user_provisioned.js"></script>
     <script src="/dialog/controllers/is_this_your_computer.js"></script>
+    <script src="/dialog/controllers/set_password.js"></script>
 
     <script src="/pages/page_helpers.js"></script>
     <script src="/pages/add_email_address.js"></script>
@@ -185,6 +186,7 @@
     <script src="cases/controllers/provision_primary_user.js"></script>
     <script src="cases/controllers/primary_user_provisioned.js"></script>
     <script src="cases/controllers/is_this_your_computer.js"></script>
+    <script src="cases/controllers/set_password.js"></script>
 
     <!-- must go last or all other tests will fail. -->
     <script src="cases/controllers/dialog.js"></script>