diff --git a/resources/static/dialog/controllers/required_email.js b/resources/static/dialog/controllers/required_email.js
index c3f2bd2d982a2afc8faa459096aff52b5bcd0512..84cc4e18b592359661eec599de20ec159ab16dc2 100644
--- a/resources/static/dialog/controllers/required_email.js
+++ b/resources/static/dialog/controllers/required_email.js
@@ -50,21 +50,32 @@ BrowserID.Modules.RequiredEmail = (function() {
       authenticated,
       primaryInfo;
 
+  function closePrimaryUser(callback) {
+    this.close("primary_user", _.extend(primaryInfo, {
+      email: email,
+      requiredEmail: true,
+      add: authenticated
+    }));
+
+    callback && callback();
+  }
+
   function signIn(callback) {
     var self = this;
 
     // If the user is already authenticated and they own this address, sign
     // them in.
     if (authenticated) {
-      dialogHelpers.getAssertion.call(self, email, callback);
+      if(primaryInfo) {
+        closePrimaryUser.call(self, callback);
+      }
+      else {
+        dialogHelpers.getAssertion.call(self, email, callback);
+      }
     }
     else {
       if(primaryInfo) {
-        self.close("primary_user", _.extend(primaryInfo, {
-          email: email,
-          requiredEmail: true
-        }));
-        callback && callback();
+        closePrimaryUser.call(self, callback);
       }
       else {
         // If the user is not already authenticated, but they potentially own
@@ -78,7 +89,7 @@ BrowserID.Modules.RequiredEmail = (function() {
               // assertion for the email we care about.
               user.syncEmailKeypair(email, function() {
                 dialogHelpers.getAssertion.call(self, email, callback);
-              }, self.getErrorDialog(errors.syncEmailKeypair));
+              }, self.getErrorDialog(errors.syncEmailKeypair, callback));
             }
             else {
               callback && callback();
@@ -143,12 +154,25 @@ BrowserID.Modules.RequiredEmail = (function() {
           if(emailInfo.type === "secondary" || emailInfo.cert) {
             // secondary user or cert is valid, user can sign in normally.
             showTemplate({ signin: true });
+            ready();
           }
           else {
-            // Uh oh, certificate is expired, take care of that.
-            self.close("primary_user", { email: email, requiredEmail: true });
+            // Uh oh, this is a primary user whose certificate is expired, take care of that.
+            user.addressInfo(email, function(info) {
+              primaryInfo = info;
+              if (info.authed) {
+                // If the user is authed with the IdP, give them the opportunity to press
+                // "signin" before passing them off to the primary user flow
+                showTemplate({ signin: true });
+              }
+              else {
+                // User is not authed with IdP, start the verification flow,
+                // add address to current user.
+                closePrimaryUser.call(self);
+              }
+              ready();
+            }, self.getErrorDialog(errors.addressInfo, ready));
           }
-          ready();
         }
         else {
           // User does not control address, time to verify.
@@ -156,36 +180,39 @@ BrowserID.Modules.RequiredEmail = (function() {
             // authenticated user who does not own primary address, make them
             // verify it.
             if(info.type === "primary") {
-              self.close("primary_user",
-                _.extend(info, { email: email, requiredEmail: true }));
+              primaryInfo = info;
+              if (info.authed) {
+                // If the user is authed with the IdP, give them the opportunity to press
+                // "signin" before passing them off to the primary user flow
+                showTemplate({ signin: true });
+              }
+              else {
+                // If user is not authed with IdP, kick them through the
+                // primary_user flow to get them verified.
+                closePrimaryUser.call(self);
+              }
             }
             else {
               showTemplate({ verify: true });
             }
             ready();
-          });
+          }, self.getErrorDialog(errors.addressInfo, ready));
         }
       }
       else {
         user.addressInfo(email, function(info) {
           if (info.type === "primary") {
-            user.isUserAuthenticatedToPrimary(email, info, function(authed) {
-              primaryInfo = info;
-              if (authed) {
-                // If the user is authenticated with their IdP, show the
-                // sign in button to give the user the chance to abort.
-                showTemplate({ signin: true, primary: true });
-              }
-              else {
-                // If the user is not authenticated with their IdP, pass them
-                // off to the primary user flow.
-                self.close("primary_user", {
-                  email: email,
-                  auth_url: primaryInfo.auth
-                });
-              }
-              ready();
-            }, self.getErrorDialog(errors.addressInfo, ready));
+            primaryInfo = info;
+            if (info.authed) {
+              // If the user is authenticated with their IdP, show the
+              // sign in button to give the user the chance to abort.
+              showTemplate({ signin: true, primary: true });
+            }
+            else {
+              // If the user is not authenticated with their IdP, pass them
+              // off to the primary user flow.
+              closePrimaryUser.call(self);
+            }
           }
           else {
             // If the current email address is registered but the user is not
@@ -197,8 +224,8 @@ BrowserID.Modules.RequiredEmail = (function() {
             else {
               showTemplate({ verify: true });
             }
-            ready();
           }
+          ready();
         }, self.getErrorDialog(errors.addressInfo, ready));
       }
 
diff --git a/resources/static/dialog/resources/state_machine.js b/resources/static/dialog/resources/state_machine.js
index a0b0e3f3c107810a92eb43183f471a33f90b71ff..e4b86b772e3eb3e3718f23f708731ba393dfe30f 100644
--- a/resources/static/dialog/resources/state_machine.js
+++ b/resources/static/dialog/resources/state_machine.js
@@ -216,13 +216,12 @@
     subscribe("email_chosen", function(msg, info) {
       var idInfo = storage.getEmail(info.email);
       if(idInfo) {
-        if(idInfo.type === "primary") {
-          // If the email is a primary, throw the user down the primary flow.
+        if(idInfo.type === "primary" && !idInfo.cert) {
+          // If the email is a primary, and their cert is not available,
+          // throw the user down the primary flow.
           // Doing so will catch cases where the primary certificate is expired
-          // and the user must re-verify with their IdP. This flow will
-          // generate its own assertion when ready.  For efficiency, we could
-          // check here whether the cert is ready, but it is early days yet and
-          // the format may change.
+          // and the user must re-verify with their IdP.  This flow will
+          // generate its own assertion when ready.
           publish("primary_user", info);
         }
         else {
diff --git a/resources/static/shared/error-messages.js b/resources/static/shared/error-messages.js
index d72a076ddaaa6834758b61c0a2e4d3dbcb30c649..dec64b4ea3478b4566c754f82e68d895cc1f048c 100644
--- a/resources/static/shared/error-messages.js
+++ b/resources/static/shared/error-messages.js
@@ -89,6 +89,10 @@ BrowserID.Errors = (function(){
       title: "Checking Email Address"
     },
 
+    isUserAuthenticatedToPrimary: {
+      title: "Checking Whether User is Authenticated with IdP"
+    },
+
     logoutUser: {
       title: "Logout Failed"
     },
diff --git a/resources/static/shared/user.js b/resources/static/shared/user.js
index a16b17b879a58c5d5a1f0f2b384c451bc81d4cef..95c714253f952268603e94c20898fdff1e832c0b 100644
--- a/resources/static/shared/user.js
+++ b/resources/static/shared/user.js
@@ -43,7 +43,8 @@ BrowserID.User = (function() {
       network = bid.Network,
       storage = bid.Storage,
       User, pollTimeout,
-      provisioning = bid.Provisioning;
+      provisioning = bid.Provisioning,
+      addressCache = {};
 
   function prepareDeps() {
     if (!jwk) {
@@ -235,6 +236,7 @@ BrowserID.User = (function() {
 
     reset: function() {
       provisioning = BrowserID.Provisioning;
+      addressCache = {};
     },
 
     /**
@@ -311,7 +313,7 @@ BrowserID.User = (function() {
     createUser: function(email, onComplete, onFailure) {
       var self=this;
 
-      network.addressInfo(email, function(info) {
+      User.addressInfo(email, function(info) {
         User.createUserWithInfo(email, info, onComplete, onFailure);
       }, onFailure);
     },
@@ -750,7 +752,27 @@ BrowserID.User = (function() {
      * @param {function} [onFailure] - Called on XHR failure.
      */
     addressInfo: function(email, onSuccess, onFailure) {
-      network.addressInfo(email, onSuccess, onFailure);
+      function success(info) {
+        addressCache[email] = info;
+        onSuccess && onSuccess(info);
+      }
+
+      if(addressCache[email]) {
+        success(addressCache[email]);
+      }
+      else {
+        network.addressInfo(email, function(info) {
+          if(info.type === "primary") {
+            User.isUserAuthenticatedToPrimary(email, info, function(authed) {
+              info.authed = authed;
+              success(info);
+            }, onFailure);
+          }
+          else {
+            success(info);
+          }
+        }, onFailure);
+      }
     },
 
     /**
@@ -927,7 +949,7 @@ BrowserID.User = (function() {
               // first we have to get the address info, then attempt
               // a provision, then if the user is provisioned, go and get an
               // assertion.
-              network.addressInfo(email, function(info) {
+              User.addressInfo(email, function(info) {
                 User.provisionPrimaryUser(email, info, function(status) {
                   if (status === "primary.verified") {
                     User.getAssertion(email, audience, onComplete, onFailure);
diff --git a/resources/static/test/index.html b/resources/static/test/index.html
index 23594e3446db5b3508fd8afd5c96f28c1e16cf75..bd29fab45834c8ea10c39a8375c131259b2ea75d 100644
--- a/resources/static/test/index.html
+++ b/resources/static/test/index.html
@@ -59,7 +59,7 @@
     <script type="text/javascript" src="/lib/underscore-min.js"></script>
     <script type="text/javascript" src="/lib/ejs.js"></script>
     <script type="text/javascript" src="/lib/vepbundle.js"></script>
-    <script type="text/javascript" src="http://testmob.org/scripts/reporter.js"></script>
+    <!--script type="text/javascript" src="http://testmob.org/scripts/reporter.js"></script-->
     <script type="text/javascript" src="/shared/browserid.js"></script>
     <script type="text/javascript" src="/lib/dom-jquery.js"></script>
     <script type="text/javascript" src="/lib/hub.js"></script>
diff --git a/resources/static/test/qunit/controllers/required_email_unit_test.js b/resources/static/test/qunit/controllers/required_email_unit_test.js
index 9dede342aa9964d56b498208f1523d2e37093ab2..e806045deacf239d1d77316c79e478c89642f972 100644
--- a/resources/static/test/qunit/controllers/required_email_unit_test.js
+++ b/resources/static/test/qunit/controllers/required_email_unit_test.js
@@ -44,16 +44,27 @@
       storage = bid.Storage,
       testHelpers = bid.TestHelpers,
       register = testHelpers.register,
-      provisioning = bid.Mocks.Provisioning;
+      provisioning = bid.Mocks.Provisioning,
+      origStart;
 
 
   module("controllers/required_email", {
     setup: function() {
+      origStart = start;
+      var count = 0;
+      start = function() {
+        if(count) {
+          throw "multiple starts in a test";
+        }
+        count++;
+        origStart();
+      };
       testHelpers.setup();
       $("#required_email").text("");
     },
 
     teardown: function() {
+      start = origStart;
       if (controller) {
         try {
           controller.destroy();
@@ -71,11 +82,19 @@
     controller.start(options);
   }
 
+  function testPasswordSection() {
+    equal($("#password_section").length, 1, "password section is there");
+  }
+
+  function testNoPasswordSection() {
+    equal($("#password_section").length, 0, "password section is not there");
+  }
+
   function testSignIn(email, cb) {
     var el = $("#required_email");
     equal(el.val() || el.text(), email, "email set correctly");
     equal($("#sign_in").length, 1, "sign in button shown");
-    equal($("#verify_address").length, 0, "verify address not shows");
+    equal($("#verify_address").length, 0, "verify address not shown");
     cb && cb();
     start();
   }
@@ -90,14 +109,6 @@
     start();
   }
 
-  function testPasswordSection() {
-    equal($("#password_section").length, 1, "password section is there");
-  }
-
-  function testNoPasswordSection() {
-    equal($("#password_section").length, 0, "password section is not there");
-  }
-
   asyncTest("known_secondary: user who is not authenticated - show password form", function() {
     var email = "registered@testuser.com";
     xhr.useResult("known_secondary");
@@ -109,7 +120,6 @@
         testSignIn(email, testPasswordSection);
       }
     });
-
   });
 
   asyncTest("unknown_secondary: user who is not authenticated - user must verify", function() {
@@ -129,6 +139,8 @@
     var email = "testuser@testuser.com";
 
     storage.addEmail(email, { type: "primary", cert: "cert" });
+    xhr.useResult("primary");
+
     createController({
       email: email,
       authenticated: true,
@@ -136,13 +148,31 @@
         testSignIn(email);
       }
     });
+  });
+
+  asyncTest("primary: user who is authenticated, owns address, cert expired or invalid, authed with IdP - sees signin screen", function() {
+    var email = "registered@testuser.com",
+        msgInfo;
 
+    xhr.useResult("primary");
+    provisioning.setStatus(provisioning.AUTHENTICATED);
+    storage.addEmail(email, { type: "primary" });
+
+    createController({
+      email: email,
+      authenticated: true,
+      ready: function() {
+        testSignIn(email);
+      }
+    });
   });
 
-  asyncTest("primary: user who is authenticated, owns address, cert expired or invalid - redirected to 'primary_user'", function() {
+  asyncTest("primary: user who is authenticated, owns address, cert expired or invalid, not authed with IdP - redirected to 'primary_user'", function() {
     var email = "registered@testuser.com",
         msgInfo;
 
+    xhr.useResult("primary");
+    provisioning.setStatus(provisioning.NOT_AUTHENTICATED);
     storage.addEmail(email, { type: "primary" });
 
     register("primary_user", function(msg, info) {
@@ -159,7 +189,23 @@
     });
   });
 
-  asyncTest("primary: user who is authenticated, does not own address - redirected to 'primary_user'", function() {
+  asyncTest("primary: user who is authenticated, does not own address, authed with IdP - user sees signin screen", function() {
+    var email = "unregistered@testuser.com",
+        msgInfo;
+
+    xhr.useResult("primary");
+    provisioning.setStatus(provisioning.AUTHENTICATED);
+
+    createController({
+      email: email,
+      authenticated: true,
+      ready: function() {
+        testSignIn(email);
+      }
+    });
+  });
+
+  asyncTest("primary: user who is authenticated, does not own address, not authed with IdP - redirected to 'primary_user'", function() {
     var email = "unregistered@testuser.com",
         msgInfo;
 
@@ -294,12 +340,15 @@
         authenticated: true
       });
 
+      var assertion;
       register("assertion_generated", function(item, info) {
-        ok(info.assertion, "we have an assertion");
-        start();
+        assertion = info.assertion;
       });
 
-      controller.signIn();
+      controller.signIn(function() {
+        ok(assertion, "we have an assertion");
+        start();
+      });
     });
   });
 
@@ -315,15 +364,18 @@
       email: email,
       authenticated: false,
       ready: function() {
+        var assertion;
         register("assertion_generated", function(item, info) {
-          ok(info.assertion, "we have an assertion");
-          start();
+          assertion = info.assertion;
         });
 
         xhr.useResult("valid");
 
         $("#password").val("password");
-        controller.signIn();
+        controller.signIn(function() {
+          ok(assertion, "we have an assertion");
+          start();
+        });
       }
     });
 
diff --git a/resources/static/test/qunit/mocks/xhr.js b/resources/static/test/qunit/mocks/xhr.js
index f4ad2c25de8f826d362f31ae8b1be924215ca5aa..f77340dc6e2867596341b02682b400a84cb9543b 100644
--- a/resources/static/test/qunit/mocks/xhr.js
+++ b/resources/static/test/qunit/mocks/xhr.js
@@ -129,6 +129,7 @@ BrowserID.Mocks.xhr = (function() {
       "get /wsapi/address_info?email=unregistered%40testuser.com throttle": { type: "secondary", known: false },
       "get /wsapi/address_info?email=unregistered%40testuser.com unknown_secondary": { type: "secondary", known: false },
       "get /wsapi/address_info?email=registered%40testuser.com known_secondary": { type: "secondary", known: true },
+      "get /wsapi/address_info?email=registered%40testuser.com primary": { type: "primary", auth: "https://auth_url", prov: "https://prov_url" },
       "get /wsapi/address_info?email=unregistered%40testuser.com primary": { type: "primary", auth: "https://auth_url", prov: "https://prov_url" },
       "get /wsapi/address_info?email=testuser%40testuser.com unknown_secondary": { type: "secondary", known: false },
       "get /wsapi/address_info?email=testuser%40testuser.com known_secondary": { type: "secondary", known: true },
diff --git a/resources/static/test/qunit/shared/user_unit_test.js b/resources/static/test/qunit/shared/user_unit_test.js
index 7e081cee2566a54ea37d0a94e7413918018fad95..dd9863e46a61ccc047f6fb547591721572e73f94 100644
--- a/resources/static/test/qunit/shared/user_unit_test.js
+++ b/resources/static/test/qunit/shared/user_unit_test.js
@@ -1094,19 +1094,12 @@ var vep = require("./vep");
       lib.syncEmails(function() {
          xhr.useResult("ajaxError");
 
-        lib.logoutUser(function() {
-          ok(false, "xhr failure should never succeed");
-          start();
-        }, function() {
-          ok(true, "xhr failure should always be a failure");
-          start();
-        });
-
-
+        lib.logoutUser(
+          testHelpers.unexpectedSuccess,
+          testHelpers.expectedXHRFailure
+        );
       }, testHelpers.unexpectedXHRFailure);
     }, testHelpers.unexpectedXHRFailure);
-
-
   });
 
   asyncTest("cancelUser", function(onSuccess) {
@@ -1114,22 +1107,15 @@ var vep = require("./vep");
       var storedIdentities = storage.getEmails();
       equal(_.size(storedIdentities), 0, "All items have been removed");
       start();
-    });
-
-
+    }, testHelpers.unexpectedXHRFailure);
   });
 
   asyncTest("cancelUser with XHR failure", function(onSuccess) {
     xhr.useResult("ajaxError");
-    lib.cancelUser(function() {
-      ok(false, "xhr failure should never succeed");
-      start();
-    }, function() {
-      ok(true, "xhr failure should always be a failure");
-      start();
-    });
-
-
+    lib.cancelUser(
+      testHelpers.unexpectedSuccess,
+      testHelpers.expectedXHRFailure
+    );
   });
 
   asyncTest("getPersistentSigninAssertion with invalid login - expect null assertion", function() {
@@ -1143,13 +1129,8 @@ var vep = require("./vep");
       lib.getPersistentSigninAssertion(function onComplete(assertion) {
         strictEqual(assertion, null, "assertion with invalid login is null");
         start();
-      }, function onFailure() {
-        ok(false, "no expected XHR failure");
-        start();
-      });
-    });
-
-
+      }, testHelpers.unexpectedXHRFailure);
+    }, testHelpers.unexpectedXHRFailure);
   });
 
   asyncTest("getPersistentSigninAssertion without email set for site - expect null assertion", function() {
@@ -1160,12 +1141,7 @@ var vep = require("./vep");
     lib.getPersistentSigninAssertion(function onComplete(assertion) {
       strictEqual(assertion, null, "assertion with no email is null");
       start();
-    }, function onFailure() {
-      ok(false, "no expected XHR failure");
-      start();
-    });
-
-
+    }, testHelpers.unexpectedXHRFailure);
   });
 
   asyncTest("getPersistentSigninAssertion without remember set for site - expect null assertion", function() {
@@ -1180,10 +1156,7 @@ var vep = require("./vep");
       lib.getPersistentSigninAssertion(function onComplete(assertion) {
         strictEqual(assertion, null, "assertion with remember=false is null");
         start();
-      }, function onFailure() {
-        ok(false, "no expected XHR failure");
-        start();
-      });
+      }, testHelpers.unexpectedXHRFailure);
     });
   });
 
@@ -1199,10 +1172,7 @@ var vep = require("./vep");
       lib.getPersistentSigninAssertion(function onComplete(assertion) {
         ok(assertion, "we have an assertion!");
         start();
-      }, function onFailure() {
-        ok(false, "no expected XHR failure");
-        start();
-      });
+      }, testHelpers.unexpectedXHRFailure);
     });
   });
 
@@ -1217,13 +1187,10 @@ var vep = require("./vep");
 
       xhr.useResult("ajaxError");
 
-      lib.getPersistentSigninAssertion(function onComplete(assertion) {
-        ok(false, "ajax error should not pass");
-        start();
-      }, function onFailure() {
-        ok(true, "ajax error should not pass");
-        start();
-      });
+      lib.getPersistentSigninAssertion(
+        testHelpers.unexpectedSuccess,
+        testHelpers.expectedXHRFailure
+      );
     });
 
 
@@ -1235,12 +1202,7 @@ var vep = require("./vep");
     lib.clearPersistentSignin(function onComplete(success) {
       strictEqual(success, false, "success with invalid login is false");
       start();
-    }, function onFailure() {
-      ok(false, "no expected XHR failure");
-      start();
-    });
-
-
+    }, testHelpers.unexpectedXHRFailure);
   });
 
   asyncTest("clearPersistentSignin with valid login with remember set to true", function() {
@@ -1251,11 +1213,27 @@ var vep = require("./vep");
       strictEqual(success, true, "success flag good");
       strictEqual(storage.site.get(testOrigin, "remember"), false, "remember flag set to false");
       start();
-    }, function onFailure() {
-      ok(false, "no expected XHR failure");
-      start();
-    });
+    }, testHelpers.unexpectedXHRFailure);
+  });
+
+  asyncTest("addressInfo with XHR Error", function() {
+    ok(false, "write some tests");
+    start();
+  });
+
+  asyncTest("addressInfo with secondary user", function() {
+    ok(false, "write some tests");
+    start();
+  });
 
+  asyncTest("addressInfo with primary authenticated user", function() {
+    ok(false, "write some tests");
+    start();
+  });
 
+  asyncTest("addressInfo with primary unauthenticated user", function() {
+    ok(false, "write some tests");
+    start();
   });
+
 }());
diff --git a/resources/static/test/qunit/testHelpers/helpers.js b/resources/static/test/qunit/testHelpers/helpers.js
index e8b84ae618d9e8fc0c441ec5456e9479fc3faa0b..f33e780047e48f61154a7af88195dd2cc1b3a42e 100644
--- a/resources/static/test/qunit/testHelpers/helpers.js
+++ b/resources/static/test/qunit/testHelpers/helpers.js
@@ -57,6 +57,7 @@
       screens.error.hide();
       tooltip.reset();
       provisioning.setStatus(provisioning.NOT_AUTHENTICATED);
+      user.reset();
       user.init({
         provisioning: provisioning
       });