diff --git a/resources/static/dialog/controllers/actions.js b/resources/static/dialog/controllers/actions.js
index 9e253e9ae89924c3918bbc39caa337acf1a9a83f..bd2725383de366afee6137f3be1b4b030c3ad932 100644
--- a/resources/static/dialog/controllers/actions.js
+++ b/resources/static/dialog/controllers/actions.js
@@ -1,4 +1,4 @@
-/*jshint brgwser:true, jQuery: true, forin: true, laxbreak:true */
+/*jshint browser:true, jQuery: true, forin: true, laxbreak:true */
 /*global _: true, BrowserID: true, PageController: true */
 /* ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
@@ -168,8 +168,15 @@ BrowserID.Modules.Actions = (function() {
           authenticated: authenticated
         });
       }, self.getErrorDialog(errors.checkAuthentication));
-    }
+    },
 
+    doVerifyPrimaryUser: function(info) {
+      startService("verify_primary_user", info);
+    },
+
+    doPrimaryUserVerified: function() {
+      // XXX we've gotta do something here too.
+    }
   });
 
   sc = Module.sc;
diff --git a/resources/static/dialog/controllers/verify_primary_user.js b/resources/static/dialog/controllers/verify_primary_user.js
new file mode 100644
index 0000000000000000000000000000000000000000..2725849454c3e8531eaf96869170d93157a42614
--- /dev/null
+++ b/resources/static/dialog/controllers/verify_primary_user.js
@@ -0,0 +1,60 @@
+/*jshint browser:true, jQuery: true, forin: true, laxbreak:true */
+/*global _: true, BrowserID: true, PageController: true */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla BrowserID.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+BrowserID.Modules.VerifyPrimaryUser = (function() {
+  "use strict";
+
+  var bid = BrowserID,
+      sc;
+
+  var Module = bid.Modules.PageModule.extend({
+    start: function(data) {
+      var self=this;
+
+      data = data || {};
+
+      // XXX YEEHA!  We've gotta set some variables and redirect off to the
+      // IdPs page.
+      sc.start.call(this, data);
+    }
+
+  });
+
+  sc = Module.sc;
+
+  return Module;
+}());
+
diff --git a/resources/static/dialog/resources/helpers.js b/resources/static/dialog/resources/helpers.js
index 697146bb80f5414af717de73f9c41ee02b0987a2..4449bc51858fa427a4545521683c5e46efcf56b5 100644
--- a/resources/static/dialog/resources/helpers.js
+++ b/resources/static/dialog/resources/helpers.js
@@ -118,13 +118,13 @@
           // XXX Is this status possible?
           break;
         case "primary.verified":
-          self.close("primay_user_verified", {
+          self.close("primary_user_verified", {
             email: email
           });
           complete(true);
           break;
         case "primary.verify":
-          self.close("primay_user_verified", {
+          self.close("primary_verify_user", {
             email: email
           });
           complete(true);
diff --git a/resources/static/dialog/resources/state_machine.js b/resources/static/dialog/resources/state_machine.js
index e611a76cae8a7ffd7eee6a79d20d3eda4f324c1a..00f401da5f9927efbbaa3a4dc054b139fd4b9a6d 100644
--- a/resources/static/dialog/resources/state_machine.js
+++ b/resources/static/dialog/resources/state_machine.js
@@ -146,6 +146,14 @@
       gotoState("doEmailConfirmed");
     });
 
+    subscribe("primary_user_verified", function(msg, info) {
+      gotoState("doPrimaryUserVerified", info);
+    });
+
+    subscribe("primary_verify_user", function(msg, info) {
+      gotoState("doVerifyPrimaryUser", info);
+    });
+
     subscribe("authenticate_with_required_email", function(msg, info) {
       gotoState("doAuthenticateWithRequiredEmail", info);
     });
diff --git a/resources/static/dialog/start.js b/resources/static/dialog/start.js
index a6787584ab511e2a3559278560f33ea12aae4733..944649ef074790d16f4c2c782cbfb2bd1720e670 100644
--- a/resources/static/dialog/start.js
+++ b/resources/static/dialog/start.js
@@ -18,6 +18,7 @@
         moduleManager.register("forgot_password", modules.ForgotPassword);
         moduleManager.register("pick_email", modules.PickEmail);
         moduleManager.register("required_email", modules.RequiredEmail);
+        moduleManager.register("verify_primary_user", modules.VerifyPrimaryUser);
 
         moduleManager.start("dialog");
       }
diff --git a/resources/static/test/index.html b/resources/static/test/index.html
index b3400342e3c85824d3bc7ceb8f020eb5089c4dba..50386e33eb941857f92ac59b623fd44155900a58 100644
--- a/resources/static/test/index.html
+++ b/resources/static/test/index.html
@@ -121,6 +121,7 @@
     <script type="text/javascript" src="/dialog/controllers/authenticate.js"></script>
     <script type="text/javascript" src="/dialog/controllers/forgotpassword.js"></script>
     <script type="text/javascript" src="/dialog/controllers/required_email.js"></script>
+    <script type="text/javascript" src="/dialog/controllers/verify_primary_user.js"></script>
 
     <script type="text/javascript" src="/pages/page_helpers.js"></script>
     <script type="text/javascript" src="/pages/add_email_address.js"></script>
@@ -167,6 +168,8 @@
     <script type="text/javascript" src="qunit/controllers/authenticate_unit_test.js"></script>
     <script type="text/javascript" src="qunit/controllers/forgotpassword_unit_test.js"></script>
     <script type="text/javascript" src="qunit/controllers/required_email_unit_test.js"></script>
+    <script type="text/javascript" src="qunit/controllers/verify_primary_user_unit_test.js"></script>
+
     <!-- must go last or all other tests will fail. -->
     <script type="text/javascript" src="qunit/controllers/dialog_unit_test.js"></script>
 	</body>
diff --git a/resources/static/test/qunit/controllers/actions_unit_test.js b/resources/static/test/qunit/controllers/actions_unit_test.js
index 340c91498eeb49cf8871136a0536c6407e1592b1..5e6aee990f6d9adde622e30659599062b4f4868c 100644
--- a/resources/static/test/qunit/controllers/actions_unit_test.js
+++ b/resources/static/test/qunit/controllers/actions_unit_test.js
@@ -95,5 +95,27 @@
     });
   });
 
+  /*
+  asyncTest("doVerifyPrimaryUser does something", function() {
+    createController({
+      ready: function() {
+        controller.doVerifyPrimaryUser();
+        // XXX test something
+        start();
+      }
+    });
+  });
+
+  asyncTest("doPrimaryUserVerified does something", function() {
+    createController({
+      ready: function() {
+        controller.doPrimaryUserVerified();
+        // XXX test something
+        start();
+      }
+    });
+  });
+*/
+
 }());
 
diff --git a/resources/static/test/qunit/controllers/verify_primary_user_unit_test.js b/resources/static/test/qunit/controllers/verify_primary_user_unit_test.js
new file mode 100644
index 0000000000000000000000000000000000000000..1a9390b0530be4443392dd51ff12f26b0a03a468
--- /dev/null
+++ b/resources/static/test/qunit/controllers/verify_primary_user_unit_test.js
@@ -0,0 +1,65 @@
+/*jshint browsers:true, forin: true, laxbreak: true */
+/*global test: true, start: true, stop: true, module: true, ok: true, equal: true, BrowserID:true */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla BrowserID.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+(function() {
+  "use strict";
+
+  var bid = BrowserID,
+      controller,
+      el,
+      testHelpers = bid.TestHelpers;
+
+  function createController(config) {
+    controller = BrowserID.Modules.VerifyPrimaryUser.create();
+    controller.start(config);
+  }
+
+  module("controllers/verify_primary_user", {
+    setup: function() {
+      testHelpers.setup();
+    },
+
+    teardown: function() {
+      if(controller) {
+        controller.destroy();
+      }
+      testHelpers.teardown();
+    }
+  });
+
+  // XXX Do some tests!
+}());
+
diff --git a/resources/static/test/qunit/resources/helpers_unit_test.js b/resources/static/test/qunit/resources/helpers_unit_test.js
index 8fd76239537241b2a69469b8845755ded1e4d84a..66613847707e62012465aa9686671ff3980a5edc 100644
--- a/resources/static/test/qunit/resources/helpers_unit_test.js
+++ b/resources/static/test/qunit/resources/helpers_unit_test.js
@@ -65,7 +65,7 @@
 
   function expectedClose(message, field, value) {
     return function(m, info) {
-      ok(m, message, "correct message: " + message);
+      equal(m, message, "correct message: " + message);
 
       if(value) {
         equal(info[field], value, field + " has correct value of " + value);
diff --git a/resources/static/test/qunit/resources/state_machine_unit_test.js b/resources/static/test/qunit/resources/state_machine_unit_test.js
index e988f9351decfd052811c81832a7bac1a02329c9..9453ffb7c87c54e3e0545eeee012ca833e464cd7 100644
--- a/resources/static/test/qunit/resources/state_machine_unit_test.js
+++ b/resources/static/test/qunit/resources/state_machine_unit_test.js
@@ -102,6 +102,14 @@
 
     doError: function() {
       this.error = true;
+    },
+
+    doPrimaryUserVerified: function() {
+      this.primaryUserVerified = true;
+    },
+
+    doVerifyPrimaryUser: function() {
+      this.verifyPrimaryUser = true;
     }
   };
 
@@ -154,6 +162,18 @@
     ok(controllerMock.emailConfirmed, "user was confirmed");
   });
 
+  // XXX make these and the messages for secondary match up so there is consistency.
+  test("primary_user_verified calls doPrimaryUserVerified", function() {
+    mediator.publish("primary_user_verified");
+
+    ok(controllerMock.primaryUserVerified, "doPrimaryUserVerified called");
+  });
+
+  test("primary_verify_user calls doVerifyPrimaryUser", function() {
+    mediator.publish("primary_verify_user");
+    ok(controllerMock.verifyPrimaryUser, "doVerifyPrimaryUser called");
+  });
+
   test("authenticated", function() {
     mediator.publish("authenticated");
 
diff --git a/resources/views/dialog_layout.ejs b/resources/views/dialog_layout.ejs
index fb7412ef13a561e9eefa87e4dd3cc1f29e042749..52fa963ec241e7d4763f6b181a4940da0f1aba5f 100644
--- a/resources/views/dialog_layout.ejs
+++ b/resources/views/dialog_layout.ejs
@@ -91,6 +91,7 @@
           <script type="text/javascript" src="/dialog/controllers/pickemail.js"></script>
           <script type="text/javascript" src="/dialog/controllers/addemail.js"></script>
           <script type="text/javascript" src="/dialog/controllers/required_email.js"></script>
+          <script type="text/javascript" src="/dialog/controllers/verify_primary_user.js"></script>
           <script type="text/javascript" src="/dialog/start.js"></script>
         <% } %>
       <% } %>