diff --git a/resources/static/css/style.css b/resources/static/css/style.css
index 35bfa524ab66efd353488ddd596061022bb3fc77..94aac066d5eea89dbaef6c4d9df944a96b34ffaa 100644
--- a/resources/static/css/style.css
+++ b/resources/static/css/style.css
@@ -515,30 +515,10 @@ button.delete:active {
   padding: 0;
 }
 
-#signUpForm .red {
-  color: red;
-}
-
 #signUpForm .submit {
   height: 28px;
 }
 
-#signUpForm .error {
-  margin-top: 20px;
-  color: red;
-  background-color: rgba(255,0,0,0.25);
-  -ms-filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#3fff0000,endColorstr=#3fff0000);
-  filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#3fff0000,endColorstr=#3fff0000);
-  zoom: 1;
-  padding: 5px;
-  line-height: 16px;
-
-  -webkit-border-radius: 3px;
-     -moz-border-radius: 3px;
-       -o-border-radius: 3px;
-          border-radius: 3px;
-}
-
 #signUpForm > .siteinfo {
   margin-bottom: 10px;
 }
diff --git a/resources/static/dialog/views/error.ejs b/resources/static/dialog/views/error.ejs
index 0b35cd680dc17fcb47e25adc6284ae7cce111b46..2a0ee0066700746b6c73e31818f4353ee1156976 100644
--- a/resources/static/dialog/views/error.ejs
+++ b/resources/static/dialog/views/error.ejs
@@ -14,6 +14,10 @@
       <%= gettext("Persona requires cookies") %>
     </h2>
     <%= format(gettext("Please close this window, <a %s>enable cookies</a> and try again"), [" target='_blank' href='http://support.mozilla.org/en-US/kb/Websites%20say%20cookies%20are%20blocked'"]) %>
+  <% } else if(typeof title === "string") { %>
+    <h2>
+      <span class="emphasis"><%= title %></span>
+    </h2>
   <% } else { %>
     <h2 id="defaultError">
       <%= gettext("We are very sorry.") %><span class="emphasis"> <%= gettext("There has been an error!") %></span>
diff --git a/resources/static/pages/verify_secondary_address.js b/resources/static/pages/verify_secondary_address.js
index df4561ec37b6707e3401afafd4f7c07225ba283a..5b2f7f20051e8bd9c3ce71c181ac75c2cc6c4c69 100644
--- a/resources/static/pages/verify_secondary_address.js
+++ b/resources/static/pages/verify_secondary_address.js
@@ -19,7 +19,6 @@ BrowserID.verifySecondaryAddress = (function() {
       tooltip = bid.Tooltip,
       token,
       sc,
-      needsPassword,
       mustAuth,
       verifyFunction,
       doc = document,
@@ -29,11 +28,6 @@ BrowserID.verifySecondaryAddress = (function() {
       redirectTo,
       redirectTimeout;  // set in config if available, use REDIRECT_SECONDS otw.
 
-  function showError(el, oncomplete) {
-    dom.hide(".hint,#signUpForm");
-    $(el).fadeIn(ANIMATION_TIME, oncomplete);
-  }
-
   function showRegistrationInfo(info) {
     dom.setInner("#email", info.email);
 
@@ -55,38 +49,37 @@ BrowserID.verifySecondaryAddress = (function() {
 
   function submit(oncomplete) {
     var pass = dom.getInner("#password") || undefined,
-        vpass = dom.getInner("#vpassword") || undefined,
-        inputValid = (!needsPassword ||
-                    validation.passwordAndValidationPassword(pass, vpass))
-             && (!mustAuth ||
-                    validation.password(pass));
+        inputValid = !mustAuth || validation.password(pass);
 
     if (inputValid) {
       user[verifyFunction](token, pass, function(info) {
         dom.addClass("body", "complete");
 
-        var verified = info.valid,
-            selector = verified ? "#congrats" : "#cannotcomplete";
-
-        pageHelpers.replaceFormWithNotice(selector, function() {
-          if (redirectTo && verified) {
-
-            // set the loggedIn status for the site.  This allows us to get
-            // a silent assertion without relying on the dialog to set the
-            // loggedIn status for the domain.  This is useful when the user
-            // closes the dialog OR if redirection happens before the dialog
-            // has had a chance to finish its business.
-            storage.setLoggedIn(URLParse(redirectTo).originOnly(), email);
-
-            setTimeout(function() {
-              doc.location.href = redirectTo;
+        var verified = info.valid;
+
+        if (verified) {
+          pageHelpers.replaceFormWithNotice("#congrats", function() {
+            if (redirectTo) {
+              // set the loggedIn status for the site.  This allows us to get
+              // a silent assertion without relying on the dialog to set the
+              // loggedIn status for the domain.  This is useful when the user
+              // closes the dialog OR if redirection happens before the dialog
+              // has had a chance to finish its business.
+              storage.setLoggedIn(URLParse(redirectTo).originOnly(), email);
+
+              setTimeout(function() {
+                doc.location.href = redirectTo;
+                complete(oncomplete, verified);
+              }, redirectTimeout);
+            }
+            else {
               complete(oncomplete, verified);
-            }, redirectTimeout);
-          }
-          else {
-            complete(oncomplete, verified);
-          }
-        });
+            }
+          });
+        }
+        else {
+          pageHelpers.showFailure(errors.cannotComplete, info, oncomplete);
+        }
       }, function(info) {
         if (info.network && info.network.status === 401) {
           tooltip.showTooltip("#cannot_authenticate");
@@ -103,36 +96,30 @@ BrowserID.verifySecondaryAddress = (function() {
   }
 
   function startVerification(oncomplete) {
+    var self=this;
     user.tokenInfo(token, function(info) {
       if (info) {
         redirectTo = info.returnTo;
         email = info.email;
         showRegistrationInfo(info);
 
-        needsPassword = info.needs_password;
         mustAuth = info.must_auth;
-
-        if (needsPassword) {
-          // This is a fix for legacy users who started the user creation
-          // process without setting their password in the dialog.  If the user
-          // needs a password, they must set it now.  Once all legacy users are
-          // verified or their links invalidated, this flow can be removed.
-          dom.addClass("body", "enter_password");
-          dom.addClass("body", "enter_verify_password");
-          complete(oncomplete, true);
-        }
-        else if (mustAuth) {
-          // These are users who have set their passwords inside of the dialog.
+        if (mustAuth) {
+          // These are users who are authenticating in a different browser or
+          // session than the initiator.
           dom.addClass("body", "enter_password");
           complete(oncomplete, true);
         }
         else {
-          // These are users who do not have to set their passwords at all.
+          // Easy case where user is in same browser and same session, just
+          // verify and be done with it all!
           submit(oncomplete);
         }
       }
       else {
-        showError("#cannotconfirm");
+        // renderError is used directly instead of pageHelpers.showFailure
+        // because showFailure hides the title in the extended info.
+        self.renderError("error", errors.cannotConfirm);
         complete(oncomplete, false);
       }
     }, pageHelpers.getFailure(errors.getTokenInfo, oncomplete));
@@ -140,7 +127,8 @@ BrowserID.verifySecondaryAddress = (function() {
 
   var Module = bid.Modules.PageModule.extend({
     start: function(options) {
-      this.checkRequired(options, "token", "verifyFunction");
+      var self=this;
+      self.checkRequired(options, "token", "verifyFunction");
 
       token = options.token;
       verifyFunction = options.verifyFunction;
@@ -151,9 +139,9 @@ BrowserID.verifySecondaryAddress = (function() {
         redirectTimeout = REDIRECT_SECONDS * 1000;
       }
 
-      startVerification(options.ready);
+      startVerification.call(self, options.ready);
 
-      sc.start.call(this, options);
+      sc.start.call(self, options);
     },
 
     submit: submit
diff --git a/resources/static/shared/error-messages.js b/resources/static/shared/error-messages.js
index 2ce74cfde884cc3adb5a4103cd12e30794f5be89..5b3530452890c3d112c358fdc92164a68bda9e85 100644
--- a/resources/static/shared/error-messages.js
+++ b/resources/static/shared/error-messages.js
@@ -35,6 +35,14 @@ BrowserID.Errors = (function(){
       title: "Cancelling User Account"
     },
 
+    cannotConfirm: {
+      title: gettext("There was a problem with your signup link. Has this address already been registered?")
+    },
+
+    cannotComplete: {
+      title: gettext("Error encountered trying to complete registration.")
+    },
+
     checkAuthentication: {
       title: "Checking Authentication"
     },
diff --git a/resources/static/test/cases/pages/verify_secondary_address.js b/resources/static/test/cases/pages/verify_secondary_address.js
index 0d74afe90af7dc39c853bc3f8860a11adfbac517..538915443b4307122f9bc12d21bd78327c276492 100644
--- a/resources/static/test/cases/pages/verify_secondary_address.js
+++ b/resources/static/test/cases/pages/verify_secondary_address.js
@@ -13,6 +13,7 @@
       dom = bid.DOM,
       testHelpers = bid.TestHelpers,
       testHasClass = testHelpers.testHasClass,
+      testVisible = testHelpers.testVisible,
       validToken = true,
       controller,
       config = {
@@ -56,7 +57,7 @@
   }
 
   function testCannotConfirm() {
-    ok($("#cannotconfirm").is(":visible"), "cannot confirm box is visible");
+    testHelpers.testErrorVisible();
   }
 
   test("start with missing token", function() {
@@ -70,22 +71,21 @@
     equal(error, "missing config option: token", "correct error thrown");
   });
 
-  asyncTest("no password: start with good token and site", function() {
+  asyncTest("valid token, no password necessary - verify user and show site info", function() {
     var returnTo = "https://test.domain/path";
     storage.setReturnTo(returnTo);
 
     createController(config, function() {
-      testEmail();
-      ok($(".siteinfo").is(":visible"), "siteinfo is visible when we say what it is");
-      equal($(".website:nth(0)").text(), returnTo, "website is updated");
+      testVisible("#congrats");
       testHasClass("body", "complete");
+      equal($("#congrats .website").text(), returnTo, "website is updated");
       equal(doc.location.href, returnTo, "redirection occurred to correct URL");
       equal(storage.getLoggedIn("https://test.domain"), "testuser@testuser.com", "logged in status set");
       start();
     });
   });
 
-  asyncTest("no password: start with good token and nosite", function() {
+  asyncTest("valid token, no password necessary, no saved site info - verify user but do not show site info", function() {
     createController(config, function() {
       testEmail();
       equal($(".siteinfo").is(":visible"), false, "siteinfo is not visible without having it");
@@ -94,7 +94,7 @@
     });
   });
 
-  asyncTest("no password: start with bad token", function() {
+  asyncTest("invalid token - show cannot confirm error", function() {
     xhr.useResult("invalid");
 
     createController(config, function() {
@@ -103,7 +103,7 @@
     });
   });
 
-  asyncTest("no password: start with emailForVerficationToken XHR failure", function() {
+  asyncTest("valid token with xhr error - show error screen", function() {
     xhr.useResult("ajaxError");
     createController(config, function() {
       testHelpers.testErrorVisible();
@@ -156,88 +156,4 @@
     });
   });
 
-  asyncTest("must set password, successful login", function() {
-    xhr.useResult("needsPassword");
-    createController(config, function() {
-      xhr.useResult("valid");
-
-      $("#password").val("password");
-      $("#vpassword").val("password");
-
-      testHasClass("body", "enter_password");
-      testHasClass("body", "enter_verify_password");
-
-      controller.submit(function(status) {
-        equal(status, true, "correct status");
-        testHasClass("body", "complete");
-        start();
-      });
-    });
-  });
-
-  asyncTest("must set password, too short a password", function() {
-    xhr.useResult("needsPassword");
-    createController(config, function() {
-      xhr.useResult("valid");
-
-      $("#password").val("pass");
-      $("#vpassword").val("pass");
-
-      controller.submit(function(status) {
-        equal(status, false, "correct status");
-        testHelpers.testTooltipVisible();
-        start();
-      });
-    });
-  });
-
-  asyncTest("must set password, too long a password", function() {
-    xhr.useResult("needsPassword");
-    createController(config, function() {
-      xhr.useResult("valid");
-
-      var pass = testHelpers.generateString(81);
-      $("#password").val(pass);
-      $("#vpassword").val(pass);
-
-      controller.submit(function(status) {
-        equal(status, false, "correct status");
-        testHelpers.testTooltipVisible();
-        start();
-      });
-    });
-  });
-
-  asyncTest("must set password, missing verification password", function() {
-    xhr.useResult("needsPassword");
-    createController(config, function() {
-      xhr.useResult("valid");
-
-      $("#password").val("password");
-      $("#vpassword").val("");
-
-      controller.submit(function(status) {
-        equal(status, false, "correct status");
-        testHelpers.testTooltipVisible();
-        start();
-      });
-    });
-  });
-
-  asyncTest("must set password, mismatched passwords", function() {
-    xhr.useResult("needsPassword");
-    createController(config, function() {
-      xhr.useResult("valid");
-
-      $("#password").val("password");
-      $("#vpassword").val("password1");
-
-      controller.submit(function(status) {
-        equal(status, false, "correct status");
-        testHelpers.testTooltipVisible();
-        start();
-      });
-    });
-  });
-
 }());
diff --git a/resources/static/test/testHelpers/helpers.js b/resources/static/test/testHelpers/helpers.js
index 0a7130ef5fc565d31ee50761f104cad7d28043d2..ed90066d39a1fdf4438117acbea6bcf7ce7f2823 100644
--- a/resources/static/test/testHelpers/helpers.js
+++ b/resources/static/test/testHelpers/helpers.js
@@ -221,8 +221,7 @@ BrowserID.TestHelpers = (function() {
     },
 
     testHasClass: function(selector, className, msg) {
-      ok($(selector).hasClass(className),
-          selector + " has className " + className + " - " + msg);
+      ok($(selector).hasClass(className), msg || selector + " has className: " + className);
     },
 
     testUndefined: function(toTest, msg) {
@@ -231,6 +230,10 @@ BrowserID.TestHelpers = (function() {
 
     testNotUndefined: function(toTest, msg) {
       notEqual(typeof toTest, "undefined", msg || "object is defined");
+    },
+
+    testVisible: function(selector, msg) {
+      ok($(selector).is(":visible"), msg || selector + " should be visible");
     }
 
   };
diff --git a/resources/views/add_email_address.ejs b/resources/views/add_email_address.ejs
index 9a4128aeee67fac5702ae45de569cd952d41fe4a..f56a6caf70bff61116465caf50941f13d20b2bec 100644
--- a/resources/views/add_email_address.ejs
+++ b/resources/views/add_email_address.ejs
@@ -2,15 +2,12 @@
    - 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/. -->
 
-<div id="hAlign" class="display_always">
+<div id="hAlign">
     <div id="vAlign">
-        <ul class="notifications">
-            <li class="notification error" id="cannotconfirm"><%= gettext('Error encountered while attempting to confirm your address. Have you previously verified this address?') %></li>
-            <li class="notification error" id="cannotcomplete"><%= gettext('Error encountered trying to complete registration.') %></li>
-        </ul>
-
-        <form id="signUpForm" class="cf">
-            <p class="hint siteinfo"><%= gettext('Finish signing into:') %> <strong><span class="website"></span></strong></p>
+        <form id="signUpForm" class="cf password_entry">
+            <p class="hint siteinfo">
+              <%= gettext('Finish signing into:') %> <strong class="website"></strong>
+            </p>
 
             <h1><%= gettext('Email Verification') %></h1>
 
@@ -19,7 +16,8 @@
                     <label for="email"><%= gettext('Email Address') %></label>
                     <input class="youraddress" id="email" placeholder="<%= gettext('Your Email') %>" type="email" value="" disabled="disabled" maxlength="254" />
                 </li>
-                <li class="password_entry">
+
+                <li>
                     <label for="password"><%= gettext('Password') %></label>
                     <input id="password" placeholder="<%= gettext('Your Password') %>" type="password" autofocus maxlength=80 />
 
@@ -27,35 +25,16 @@
                       <%= gettext('Password is required.') %>
                     </div>
 
-                    <div class="tooltip" id="password_length" for="password">
-                      <%= gettext('Password must be between 8 and 80 characters long.') %>
-                    </div>
-
                     <div id="cannot_authenticate" class="tooltip" for="password">
                       <%= gettext('The account cannot be verified with this username and password.') %>
                     </div>
                 </li>
-
-                <li class="password_entry" id="verify_password">
-                    <label for="vpassword"><%= gettext('Verify Password') %></label>
-                    <input id="vpassword" placeholder="<%= gettext('Repeat Password') %>" type="password" maxlength="80">
-
-                    <div id="vpassword_required" class="tooltip" 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 password_entry">
                 <button><%= gettext('finish') %></button>
             </div>
 
-
         </form>
 
         <div id="congrats">
diff --git a/resources/views/verify_email_address.ejs b/resources/views/verify_email_address.ejs
index d033b9417e2b39158d875138bb6ec24aca1a0286..118c70df793807bfb6586e04eb955624061bbe5a 100644
--- a/resources/views/verify_email_address.ejs
+++ b/resources/views/verify_email_address.ejs
@@ -2,15 +2,13 @@
       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/. */ %>
 
-<div id="hAlign" class="display_always">
+<div id="hAlign">
     <div id="vAlign">
-        <ul class="notifications">
-            <li class="notification error" id="cannotconfirm"><%= gettext('There was a problem with your signup link. Has this address already been registered?') %></li>
-            <li class="notification error" id="cannotcomplete"><%= gettext('Error encountered trying to complete registration.') %></li>
-        </ul>
+        <form id="signUpForm" class="cf password_entry">
+            <p class="hint siteinfo">
+              <%= gettext('Finish signing into:') %> <strong class="website"></strong>
+            </p>
 
-        <form id="signUpForm" class="cf">
-            <p class="hint siteinfo"><%= gettext('Finish signing into:') %> <strong><span class="website"></span></strong></p>
             <h1><%= gettext('Last step!') %></h1>
 
             <ul class="inputs">
@@ -19,7 +17,7 @@
                     <input class="youraddress" id="email" placeholder="<%= gettext('Your Email') %>" type="email" value="" disabled="disabled" maxlength="254" />
                 </li>
 
-                <li class="password_entry">
+                <li>
                     <label for="password"><%= gettext('Password') %></label>
                     <input id="password" placeholder="<%= gettext('Your Password') %>" type="password" autofocus maxlength=80 />
 
@@ -27,28 +25,10 @@
                       <%= gettext('Password is required.') %>
                     </div>
 
-                    <div class="tooltip" id="password_length" for="password">
-                      <%= gettext('Password must be between 8 and 80 characters long.') %>
-                    </div>
-
                     <div id="cannot_authenticate" class="tooltip" for="password">
                       <%= gettext('The account cannot be verified with this username and password.') %>
                     </div>
                 </li>
-
-                <li class="password_entry" id="verify_password">
-                    <label for="vpassword"><%= gettext('Verify Password') %></label>
-                    <input id="vpassword" placeholder="<%= gettext('Repeat Password') %>" type="password" maxlength="80">
-
-                    <div id="vpassword_required" class="tooltip" 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 password_entry">