diff --git a/resources/static/dialog/controllers/actions.js b/resources/static/dialog/controllers/actions.js
index 80435e5220f6bafe3e5856ef3aeb358bc715a098..1bf05562eaca5b10870e626b9f7c4151f6362e35 100644
--- a/resources/static/dialog/controllers/actions.js
+++ b/resources/static/dialog/controllers/actions.js
@@ -58,10 +58,6 @@ BrowserID.Modules.Actions = (function() {
       if(data.ready) _.defer(data.ready);
     },
 
-    doRPInfo: function(info) {
-      startService("rp_info", info);
-    },
-
     doCancel: function() {
       if(onsuccess) onsuccess(null);
     },
@@ -157,6 +153,10 @@ BrowserID.Modules.Actions = (function() {
 
     doGenerateAssertion: function(info) {
       startService("generate_assertion", info);
+    },
+
+    doRPInfo: function(info) {
+      startService("rp_info", info);
     }
   });
 
diff --git a/resources/static/dialog/controllers/add_email.js b/resources/static/dialog/controllers/add_email.js
index c9a8c638ca85ddc7f7566fb1c80e8dd90fa85d89..924d242c1cf5390c3f88e998c00c0e0f26ac3cca 100644
--- a/resources/static/dialog/controllers/add_email.js
+++ b/resources/static/dialog/controllers/add_email.js
@@ -1,5 +1,5 @@
 /*jshint browser:true, jQuery: true, forin: true, laxbreak:true */
-/*global _: true, BrowserID: true, PageController: true */
+/*global _: true, BrowserID: true, PageController: true, gettext: 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/. */
@@ -8,6 +8,7 @@ BrowserID.Modules.AddEmail = (function() {
 
   var bid = BrowserID,
       helpers = bid.Helpers,
+      user = bid.User,
       dialogHelpers = helpers.Dialog,
       errors = bid.Errors,
       complete = helpers.complete,
@@ -33,12 +34,15 @@ BrowserID.Modules.AddEmail = (function() {
   var Module = bid.Modules.PageModule.extend({
     start: function(options) {
       var self=this,
-          templateData = helpers.extend({}, options, {
-            privacy_url: options.privacyURL || null,
-            tos_url: options.tosURL || null
-          });
+          originEmail = user.getOriginEmail();
 
-      self.renderDialog("add_email", templateData);
+      self.renderDialog("add_email", options);
+
+      // Only show the RP's TOS/PP if the user has not been to this site
+      // before.
+      if(!originEmail && options.siteTOSPP) {
+        dialogHelpers.showRPTosPP.call(self);
+      }
 
       self.click("#cancel", cancelAddEmail);
       Module.sc.start.call(self, options);
diff --git a/resources/static/dialog/controllers/authenticate.js b/resources/static/dialog/controllers/authenticate.js
index ac413aa99a82cb3fd6573580dee2a04d4e83e99c..de6a81d0bb99adb5657ee96a7d48d696bfe21ce9 100644
--- a/resources/static/dialog/controllers/authenticate.js
+++ b/resources/static/dialog/controllers/authenticate.js
@@ -18,6 +18,7 @@ BrowserID.Modules.Authenticate = (function() {
       dom = bid.DOM,
       lastEmail = "",
       addressInfo,
+      siteTOSPP,
       hints = ["returning","start","addressInfo"];
 
   function getEmail() {
@@ -33,6 +34,7 @@ BrowserID.Modules.Authenticate = (function() {
     }
     else {
       showHint("start");
+      enterEmailState.call(self);
       complete(info.ready);
     }
   }
@@ -96,7 +98,7 @@ BrowserID.Modules.Authenticate = (function() {
   function showHint(showSelector, callback) {
     _.each(hints, function(className) {
       if(className != showSelector) {
-        $("." + className).not("." + showSelector).hide();
+        dom.hide("." + className + ":not(." + showSelector + ")");
       }
     });
 
@@ -110,8 +112,8 @@ BrowserID.Modules.Authenticate = (function() {
     });
   }
 
-  function enterEmailState(el) {
-    if (!$("#email").is(":disabled")) {
+  function enterEmailState() {
+    if (!dom.is("#email", ":disabled")) {
       this.submit = checkEmail;
       showHint("start");
     }
@@ -127,6 +129,8 @@ BrowserID.Modules.Authenticate = (function() {
     showHint("returning", function() {
       dom.focus("#password");
     });
+
+
     complete(callback);
   }
 
@@ -156,12 +160,16 @@ BrowserID.Modules.Authenticate = (function() {
       var self=this;
       self.renderDialog("authenticate", {
         sitename: user.getHostname(),
-        email: lastEmail,
-        privacy_url: options.privacyURL,
-        tos_url: options.tosURL
+        email: lastEmail
       });
 
-      $(".returning,.start").hide();
+      dom.hide(".returning,.start");
+
+      // We have to show the TOS/PP agreement to *all* users here.  Users who
+      // are already authenticated to their IdP but do not have a Persona
+      // account automatically have an account created with no further
+      // interaction.
+      dom.show(".tospp");
 
       self.bind("#email", "keyup", emailKeyUp);
       self.click("#forgotPassword", forgotPassword);
diff --git a/resources/static/dialog/controllers/dialog.js b/resources/static/dialog/controllers/dialog.js
index 36e66dca60e3ccc6310246344cb029f22d637376..7fc42259b0ba29035445180d8b19808083fcd1c2 100644
--- a/resources/static/dialog/controllers/dialog.js
+++ b/resources/static/dialog/controllers/dialog.js
@@ -73,10 +73,6 @@ BrowserID.Modules.Dialog = (function() {
     channel && channel.detach();
   }
 
-  function setOrigin(origin) {
-    user.setOrigin(origin);
-  }
-
   function onWindowUnload() {
     this.publish("window_unload");
   }
@@ -139,7 +135,7 @@ BrowserID.Modules.Dialog = (function() {
       var self=this,
           hash = win.location.hash;
 
-      setOrigin(origin_url);
+      user.setOrigin(origin_url);
 
 
       if (startExternalDependencies) {
diff --git a/resources/static/dialog/controllers/pick_email.js b/resources/static/dialog/controllers/pick_email.js
index 4382645c75ce2777cfb4008e5e50d40cb2e5bebf..95adea65bf1340c7e8888dd69387fa5077c9c468 100644
--- a/resources/static/dialog/controllers/pick_email.js
+++ b/resources/static/dialog/controllers/pick_email.js
@@ -83,6 +83,7 @@ BrowserID.Modules.PickEmail = (function() {
   var Module = bid.Modules.PageModule.extend({
     start: function(options) {
       var origin = user.getOrigin(),
+          originEmail = user.getOriginEmail(),
           self=this;
 
       options = options || {};
@@ -95,10 +96,17 @@ BrowserID.Modules.PickEmail = (function() {
 
       self.renderDialog("pick_email", {
         identities: identities,
-        siteemail: storage.site.get(origin, "email"),
+        siteemail: originEmail,
         privacy_url: options.privacyURL,
         tos_url: options.tosURL
       });
+
+      // If the user has been to this site before, they have already implicitly
+      // agreed to TOS/PP agreement.  Don't bug them a second time.
+      if (!originEmail && options.siteTOSPP) {
+        dialogHelpers.showRPTosPP.call(self);
+      }
+
       dom.getElements("body").css("opacity", "1");
       if (dom.getElements("#selectEmail input[type=radio]:visible").length === 0) {
         // If there is only one email address, the radio button is never shown,
diff --git a/resources/static/dialog/controllers/rp_info.js b/resources/static/dialog/controllers/rp_info.js
index 3bc9b20edd9efb34d9466a815024b6e09c0775e9..b6f6b55cdde732921d2965d7c7a59a92863e984d 100644
--- a/resources/static/dialog/controllers/rp_info.js
+++ b/resources/static/dialog/controllers/rp_info.js
@@ -7,7 +7,8 @@
 
 /**
  * Purpose:
- *  Display to the user RP related data such as hostname, name, and logo.
+ *  Display to the user RP related data such as hostname, sitename, logo,
+ *  TOS/PP, etc.
  */
 BrowserID.Modules.RPInfo = (function() {
   "use strict";
@@ -32,7 +33,9 @@ BrowserID.Modules.RPInfo = (function() {
       renderer.render("#rp_info", "rp_info", {
         hostname: options.hostname,
         siteName: options.siteName,
-        siteLogo: options.siteLogo
+        siteLogo: options.siteLogo,
+        privacyURL: options.privacyURL,
+        tosURL: options.tosURL
       });
 
       sc.start.call(this, options);
diff --git a/resources/static/dialog/controllers/verify_primary_user.js b/resources/static/dialog/controllers/verify_primary_user.js
index 9e38e6be13bfec2f9039451cb860310b7b03a2f3..e42deec4cdf8d0f7eec840ae4d4b02a301927964 100644
--- a/resources/static/dialog/controllers/verify_primary_user.js
+++ b/resources/static/dialog/controllers/verify_primary_user.js
@@ -12,7 +12,9 @@ BrowserID.Modules.VerifyPrimaryUser = (function() {
       add,
       email,
       auth_url,
+      dom = bid.DOM,
       helpers = bid.Helpers,
+      dialogHelpers = helpers.Dialog,
       complete = helpers.complete;
 
   function verify(callback) {
@@ -48,12 +50,15 @@ BrowserID.Modules.VerifyPrimaryUser = (function() {
       auth_url = data.auth_url;
 
       var templateData = helpers.extend({}, data, {
-        requiredEmail: data.requiredEmail || false,
-        privacy_url: data.privacyURL || null,
-        tos_url: data.tosURL || null
+        requiredEmail: data.requiredEmail || false
       });
       self.renderDialog("verify_primary_user", templateData);
 
+      if(data.siteTOSPP) {
+        dialogHelpers.showRPTosPP.call(self);
+      }
+      dom.show(".tospp");
+
       self.click("#cancel", cancel);
 
       sc.start.call(self, data);
diff --git a/resources/static/dialog/css/popup.css b/resources/static/dialog/css/popup.css
index 39d97a1f508042e5650c79ca03fa7d77b6f0dff5..5f5f7452ece5fe028c33edbc67e8ceffcd946f92 100644
--- a/resources/static/dialog/css/popup.css
+++ b/resources/static/dialog/css/popup.css
@@ -389,9 +389,19 @@ div#required_email {
   margin-top: 10px;
 }
 
+.submit > p + p:last-child {
+  margin-top: 15px;
+}
+
 .tospp {
-    color: #787878;
-    clear: right;
+  display: none;
+  font-size: 11px;
+  line-height: 1.2;
+}
+
+#rp_info .tospp {
+  margin: 10px auto;
+  max-width: 280px;
 }
 
 a.emphasize {
diff --git a/resources/static/dialog/resources/helpers.js b/resources/static/dialog/resources/helpers.js
index 64225604a1fd9b4ca32f7177702ade8afbfbae52..7419a230c47410f378c0ad5164eb877de956ebab 100644
--- a/resources/static/dialog/resources/helpers.js
+++ b/resources/static/dialog/resources/helpers.js
@@ -11,7 +11,8 @@
       complete = helpers.complete,
       user = bid.User,
       tooltip = bid.Tooltip,
-      errors = bid.Errors;
+      errors = bid.Errors,
+      dom = bid.DOM;
 
   function animateClose(callback) {
     var body = $("body"),
@@ -133,6 +134,10 @@
     }, self.getErrorDialog(errors.addEmail, callback));
   }
 
+  function showRPTosPP() {
+    dom.show(".rptospp");
+  }
+
   helpers.Dialog = helpers.Dialog || {};
 
   helpers.extend(helpers.Dialog, {
@@ -143,7 +148,8 @@
     addSecondaryEmail: addSecondaryEmail,
     resetPassword: resetPassword,
     cancelEvent: helpers.cancelEvent,
-    animateClose: animateClose
+    animateClose: animateClose,
+    showRPTosPP: showRPTosPP
   });
 
 }());
diff --git a/resources/static/dialog/resources/state.js b/resources/static/dialog/resources/state.js
index c56eee0ddf6d95326c190dde76913f89c403073d..ad6947ecf277955e8fce2dea852981e07ed0cfcd 100644
--- a/resources/static/dialog/resources/state.js
+++ b/resources/static/dialog/resources/state.js
@@ -42,8 +42,7 @@ BrowserID.State = (function() {
 
     handleState("start", function(msg, info) {
       self.hostname = info.hostname;
-      self.privacyURL = info.privacyURL;
-      self.tosURL = info.tosURL;
+      self.siteTOSPP = !!(info.privacyURL && info.tosURL);
       requiredEmail = info.requiredEmail;
 
       startAction(false, "doRPInfo", info);
@@ -77,8 +76,7 @@ BrowserID.State = (function() {
         self.email = requiredEmail;
         startAction("doAuthenticateWithRequiredEmail", {
           email: requiredEmail,
-          privacyURL: self.privacyURL,
-          tosURL: self.tosURL
+          siteTOSPP: self.siteTOSPP
         });
       }
       else if (authenticated) {
@@ -89,8 +87,8 @@ BrowserID.State = (function() {
     });
 
     handleState("authenticate", function(msg, info) {
-      info.privacyURL = self.privacyURL;
-      info.tosURL = self.tosURL;
+      info = info || {};
+      info.siteTOSPP = self.siteTOSPP;
       startAction("doAuthenticate", info);
     });
 
@@ -167,8 +165,7 @@ BrowserID.State = (function() {
         add: !!addPrimaryUser,
         email: email,
         requiredEmail: !!requiredEmail,
-        privacyURL: self.privacyURL,
-        tosURL: self.tosURL
+        siteTOSPP: self.siteTOSPP
       });
 
       if (primaryVerificationInfo) {
@@ -205,8 +202,7 @@ BrowserID.State = (function() {
     handleState("pick_email", function() {
       startAction("doPickEmail", {
         origin: self.hostname,
-        privacyURL: self.privacyURL,
-        tosURL: self.tosURL
+        siteTOSPP: self.siteTOSPP
       });
     });
 
@@ -245,8 +241,7 @@ BrowserID.State = (function() {
               startAction("doAuthenticateWithRequiredEmail", {
                 email: email,
                 secondary_auth: true,
-                privacyURL: self.privacyURL,
-                tosURL: self.tosURL
+                siteTOSPP: self.siteTOSPP
               });
             }
             else {
@@ -309,6 +304,9 @@ BrowserID.State = (function() {
       // finally reset, the password_reset message will be raised where we must
       // await email confirmation.
       self.resetPasswordEmail = info.email;
+      info = helpers.extend(info || {}, {
+        siteTOSPP: self.siteTOSPP
+      });
       startAction(false, "doForgotPassword", info);
     });
 
@@ -344,10 +342,28 @@ BrowserID.State = (function() {
       redirectToState("email_chosen", info);
     });
 
+    handleState("reset_password", function(msg, info) {
+      info = info || {};
+      // reset_password says the user has confirmed that they want to
+      // reset their password.  doResetPassword will attempt to invoke
+      // the create_user wsapi.  If the wsapi call is successful,
+      // the user will be shown the "go verify your account" message.
+
+      // We have to save the staged email address here for when the user
+      // verifies their account and user_confirmed is called.
+      self.stagedEmail = info.email;
+      startAction(false, "doResetPassword", info);
+    });
+
     handleState("add_email", function(msg, info) {
-      info = helpers.extend(info, {
-        privacyURL: self.privacyURL,
-        tosURL: self.tosURL
+      // add_email indicates the user wishes to add an email to the account,
+      // the add_email screen must be displayed.  After the user enters the
+      // email address they wish to add, add_email will trigger
+      // either 1) primary_user or 2) email_staged. #1 occurs if the email
+      // address is a primary address, #2 occurs if the address is a secondary
+      // and the verification email has been sent.
+      info = helpers.extend(info || {}, {
+        siteTOSPP: self.siteTOSPP
       });
 
       startAction("doAddEmail", info);
diff --git a/resources/static/dialog/views/add_email.ejs b/resources/static/dialog/views/add_email.ejs
index 5af78c55bba4147120393579d08484e2be5ebbb2..b20fda347cee3e89cf66f58e10fc3d0f77997f01 100644
--- a/resources/static/dialog/views/add_email.ejs
+++ b/resources/static/dialog/views/add_email.ejs
@@ -30,22 +30,8 @@
       </ul>
 
       <div class="submit cf">
-        <% if (privacy_url && tos_url) { %>
-          <p class="tospp">
-            <%= format(
-                  gettext('By clicking %s, you confirm that you accept this site\'s <a %s>Terms of Use</a> and <a %s>Privacy Policy</a>.'),
-                       [ gettext('add'),
-                         format(' href="%s" target="_new"', [tos_url]),
-                         format(' href="%s" target="_new"', [privacy_url])
-                       ]) %>
-          </p>
-          <p>
-        <% } %>
           <button id="addNewEmail"><%= gettext('add') %></button>
           <a href="#" id="cancel" class="action"><%= gettext('cancel') %></a>
-        <% if (privacy_url && tos_url) { %>
-          </p>
-        <% } %>
       </div>
 
   </div>
diff --git a/resources/static/dialog/views/authenticate.ejs b/resources/static/dialog/views/authenticate.ejs
index 06b6307b51c8d0aabd25ab4899c4eff2a7bedc40..57d0fad239416357fa29b1c28e9b9862eb835a88 100644
--- a/resources/static/dialog/views/authenticate.ejs
+++ b/resources/static/dialog/views/authenticate.ejs
@@ -58,16 +58,15 @@
           <button class="start addressInfo" tabindex="3"><%= gettext('next') %></button>
           <button class="returning" tabindex="3"><%= gettext('sign in') %></button>
         </p>
-        <% if (privacy_url && tos_url) { %>
-           <p class="tospp">
-            <%= format(
-                  gettext('By clicking %s, you confirm that you accept this site\'s <a %s>Terms of Use</a> and <a %s>Privacy Policy</a>.'),
-                       [ gettext('next'),
-                         format(' href="%s" target="_new"', [tos_url]),
-                         format(' href="%s" target="_new"', [privacy_url])
-                       ]) %>
+
+        <p class="tospp bidtospp">
+           <%= format(
+                gettext('By proceeding, you agree to %s\'s <a %s>Terms</a> and <a %s>Privacy Policy</a>.'),
+                     [ "Persona",
+                       ' href="https://browserid.org/tos" target="_new"',
+                       ' href="https://browserid.org/privacy" target="_new"',
+                     ]) %>
           </p>
-      <% } %>
 
       </div>
   </div>
diff --git a/resources/static/dialog/views/pick_email.ejs b/resources/static/dialog/views/pick_email.ejs
index c189f521055d156ee397366df6d6306a22645f98..059072425b93d6be854125b4290d444f26c019ad 100644
--- a/resources/static/dialog/views/pick_email.ejs
+++ b/resources/static/dialog/views/pick_email.ejs
@@ -23,18 +23,8 @@
 
 
       <div class="submit add cf">
-      <p class="cf">
-        <button id="signInButton"><%= gettext('sign in') %></button>
-      </p>
-      <% if (privacy_url && tos_url) { %>
-        <p class="tospp">
-          <%= format(
-            gettext('By clicking %s, you confirm that you accept this site\'s <a %s>Terms of Use</a> and <a %s>Privacy Policy</a>.'),
-                    [ gettext('sign in'),
-                      format(' href="%s" target="_new"', [tos_url]),
-                      format(' href="%s" target="_new"', [privacy_url])
-                    ]) %>
+        <p class="cf">
+          <button id="signInButton"><%= gettext('sign in') %></button>
         </p>
-      <% } %>
       </div>
   </div>
diff --git a/resources/static/dialog/views/required_email.ejs b/resources/static/dialog/views/required_email.ejs
index 04d38aaa22f6255ca65bddb66d87f70a0ef47e6b..ee613fa961903ce725a8ebce439c58fce3d8691b 100644
--- a/resources/static/dialog/views/required_email.ejs
+++ b/resources/static/dialog/views/required_email.ejs
@@ -50,17 +50,15 @@
       </ul>
 
       <div class="submit cf">
-        <% if (privacy_url && tos_url) { %>
-          <p class="tospp">
+          <p class="tospp bidtospp">
             <%= format(
-                  gettext('By clicking %s, you confirm that you accept this site\'s <a %s>Terms of Use</a> and <a %s>Privacy Policy</a>.'),
-                       [ gettext('sign in'),
-                         format(' href="%s" target="_new"', [tos_url]),
-                         format(' href="%s" target="_new"', [privacy_url])
+                  gettext('By proceeding, you agree to %s\'s <a %s>Terms</a> and <a %s>Privacy Policy</a>.'),
+                       [ "BrowserID",
+                         ' href="https://browserid.org/tos" target="_new"',
+                         ' href="https://browserid.org/privacy" target="_new"',
                        ]) %>
           </p>
           <p>
-        <% } %>
             <% if (signin) { %>
               <button id="sign_in" tabindex="3"><%= gettext("sign in") %></button>
             <% } else if (verify) { %>
@@ -70,8 +68,6 @@
             <% if (secondary_auth) { %>
               <a href="#" id="cancel" class="action" tabindex="4"><%= gettext("cancel") %></a>
             <% } %>
-        <% if (privacy_url && tos_url) { %>
           </p>
-        <% } %>
       </div>
   </div>
diff --git a/resources/static/dialog/views/rp_info.ejs b/resources/static/dialog/views/rp_info.ejs
index 5928a18d6c945d726598017558fbb69f1f4d16e1..84c22866b7a324ee43d1c8439dee85235d8a9829 100644
--- a/resources/static/dialog/views/rp_info.ejs
+++ b/resources/static/dialog/views/rp_info.ejs
@@ -19,3 +19,12 @@
   <% } %>
 <% } %>
 
+<% if(privacyURL && tosURL) { %>
+  <p class="rptospp tospp">
+    <%= format(gettext("By proceeding, you agree to %s\'s <a %s>Terms</a> and <a %s>Privacy Policy</a>."),
+    [ sitename,
+     ' href="' + tosURL + '" id="rp_tos" target="_blank"',
+     ' href="' + privacyURL + '" id="rp_pp" target="_blank"'
+     ]) %>
+   </p>
+<% } %>
diff --git a/resources/static/dialog/views/verify_primary_user.ejs b/resources/static/dialog/views/verify_primary_user.ejs
index fb80a0c654f2445a3eca6fa6322a70540a1e61da..d3860675929264cdccb53f538a05fb4d92009fb3 100644
--- a/resources/static/dialog/views/verify_primary_user.ejs
+++ b/resources/static/dialog/views/verify_primary_user.ejs
@@ -24,21 +24,17 @@
       </ul>
 
       <div class="submit cf">
-        <% if (privacy_url && tos_url) { %>
-          <p class="tospp">
-            <%= format(
-                  gettext('By clicking %s, you confirm that you accept this site\'s <a %s>Terms of Use</a> and <a %s>Privacy Policy</a>.'),
-                       [ gettext('verify'),
-                         format(' href="%s" target="_new"', [tos_url]),
-                         format(' href="%s" target="_new"', [privacy_url])
-                       ]) %>
+          <p class="tospp bidtospp">
+           <%= format(
+                gettext('By proceeding, you agree to %s\'s <a %s>Terms</a> and <a %s>Privacy Policy</a>.'),
+                     [ "BrowserID",
+                       ' href="https://browserid.org/tos" target="_new"',
+                       ' href="https://browserid.org/privacy" target="_new"',
+                     ]) %>
           </p>
           <p>
-        <% } %>
-          <button id="verifyWithPrimary"><%= gettext("verify") %></button>
-        <% if (privacy_url && tos_url) { %>
+            <button id="verifyWithPrimary"><%= gettext("verify") %></button>
           </p>
-        <% } %>
       </div>
   </div>
 
@@ -52,22 +48,18 @@
     </p>
 
     <div class="submit cf">
-        <% if (privacy_url && tos_url) { %>
-          <p class="tospp">
-            <%= format(
-                  gettext('By clicking %s, you confirm that you accept this site\'s <a %s>Terms of Use</a> and <a %s>Privacy Policy</a>.'),
-                       [ gettext('verify'),
-                         format(' href="%s" target="_new"', [tos_url]),
-                         format(' href="%s" target="_new"', [privacy_url])
-                       ]) %>
-          </p>
-          <p>
-        <% } %>
+        <p class="tospp bidtospp">
+         <%= format(
+              gettext('By proceeding, you agree to %s\'s <a %s>Terms</a> and <a %s>Privacy Policy</a>.'),
+                   [ "BrowserID",
+                     ' href="https://browserid.org/tos" target="_new"',
+                     ' href="https://browserid.org/privacy" target="_new"',
+                   ]) %>
+        </p>
+        <p>
           <button id="verifyWithPrimary"><%= gettext("verify") %></button>
           <a href="#" id="cancel" class="action"><%= gettext("cancel") %></a>
-        <% if (privacy_url && tos_url) { %>
-          </p>
-        <% } %>
+        </p>
     </div>
 
   </div>
diff --git a/resources/static/lib/dom-jquery.js b/resources/static/lib/dom-jquery.js
index 6438fec068304658384f58d1e86e2c0c1c309dcb..0faeb1ccc0db906754e3461716bbfd2b8c3bd1dc 100644
--- a/resources/static/lib/dom-jquery.js
+++ b/resources/static/lib/dom-jquery.js
@@ -313,7 +313,7 @@ BrowserID.DOM = ( function() {
         },
 
         /**
-         * Show an element/elements
+         * Show an element
          * @method show
          * @param {selector || element} elementToShow
          */
@@ -322,15 +322,13 @@ BrowserID.DOM = ( function() {
         },
 
         /**
-         * Hide an element/elements
+         * Hide an element
          * @method hide
          * @param {selector || element} elementToHide
          */
         hide: function( elementToHide ) {
           return jQuery( elementToHide ).hide();
         }
-
-
     };
 
     function isValBased( target ) {
diff --git a/resources/static/shared/modules/page_module.js b/resources/static/shared/modules/page_module.js
index 54b570841d4f0b3bb250039939ec26e0f173c1f2..f0e0f6854f3825e70434b36eba43014376262f51 100644
--- a/resources/static/shared/modules/page_module.js
+++ b/resources/static/shared/modules/page_module.js
@@ -129,6 +129,7 @@ BrowserID.Modules.PageModule = (function() {
       self.hideWait();
       self.hideError();
       self.hideDelay();
+      dom.hide(".tospp");
 
       screens.form.show(template, data);
       dom.focus("input:visible:not(:disabled):eq(0)");
diff --git a/resources/static/shared/user.js b/resources/static/shared/user.js
index ab493ae9f4870da8bc26472ff8a08f69b53b4095..d6c1ad1cb9f9a9f0a4cd3f6a0d255980fdccc7ef 100644
--- a/resources/static/shared/user.js
+++ b/resources/static/shared/user.js
@@ -264,6 +264,14 @@ BrowserID.User = (function() {
       return origin;
     },
 
+    setOriginEmail: function(email) {
+      storage.site.set(origin, "email", email);
+    },
+
+    getOriginEmail: function() {
+      return storage.site.get(origin, "email");
+    },
+
     /**
      * Get the hostname for the set origin
      * @method getHostname
diff --git a/resources/static/test/cases/controllers/actions.js b/resources/static/test/cases/controllers/actions.js
index 8d90d69f88dfd2bcd2b72865732ff267e1593e3a..27c54f781f818759fa4527d1c1c0910675b5bcee 100644
--- a/resources/static/test/cases/controllers/actions.js
+++ b/resources/static/test/cases/controllers/actions.js
@@ -88,7 +88,6 @@
     testActionStartsModule('doGenerateAssertion', { email: TEST_EMAIL }, "generate_assertion");
   });
 
-
   asyncTest("doStageUser with successful creation - trigger user_staged", function() {
     createController({
       ready: function() {
@@ -109,5 +108,21 @@
   asyncTest("doForgotPassword - call the set_password controller with reset_password true", function() {
     testActionStartsModule('doForgotPassword', { email: TEST_EMAIL }, "set_password");
   });
+
+  asyncTest("doRPInfo - start the rp_info service", function() {
+    createController({
+      ready: function() {
+        var error;
+        try {
+          controller.doRPInfo({ name: "browserid.org" });
+        } catch(e) {
+          error = e;
+        }
+
+        equal(error, "module not registered for rp_info", "correct service started");
+        start();
+      }
+    });
+  });
 }());
 
diff --git a/resources/static/test/cases/controllers/add_email.js b/resources/static/test/cases/controllers/add_email.js
index 6d635e82286fcb606da9e1fe8dd8c99307b40b9e..43f19e385b3091fcdd8411ee30f0c6891f38a123 100644
--- a/resources/static/test/cases/controllers/add_email.js
+++ b/resources/static/test/cases/controllers/add_email.js
@@ -41,16 +41,6 @@
     controller.start(options || {});
   }
 
-  test("privacyURL and tosURL specified - show TOS/PP", function() {
-    equal($(".tospp").length, 0, "tospp has not yet been added to the DOM");
-    createController({
-      privacyURL: "http://testuser.com/priv.html",
-      tosURL: "http://testuser.com/tos.html",
-    });
-
-    equal($(".tospp").length, 1, "tospp has been added to the DOM");
-  });
-
   test("addEmail with specified email address - fill in email", function() {
     createController({ email: "testuser@testuser.com" });
     ok($("#newEmail").val(), "testuser@testuser.com", "email prepopulated");
diff --git a/resources/static/test/cases/controllers/dialog.js b/resources/static/test/cases/controllers/dialog.js
index aedd54d97475b720ed0affd26f640161948dfd04..b1f6530bb4ec8c3a1f3e657d1155d812a5043aa9 100644
--- a/resources/static/test/cases/controllers/dialog.js
+++ b/resources/static/test/cases/controllers/dialog.js
@@ -152,6 +152,7 @@
         catch(e) {
           // do nothing, an exception will be thrown because no modules are
           // registered for the any services.
+          console.log(e);
         }
       }
     });
diff --git a/resources/static/test/cases/controllers/rp_info.js b/resources/static/test/cases/controllers/rp_info.js
index 0b89868ab973653fcec4d665f707b5f77b5580dc..6e2200b0928fcc01d3339cea3b33495ae4eb6ab6 100644
--- a/resources/static/test/cases/controllers/rp_info.js
+++ b/resources/static/test/cases/controllers/rp_info.js
@@ -13,8 +13,11 @@
       register = bid.TestHelpers.register,
       WindowMock = bid.Mocks.WindowMock,
       RP_HOSTNAME = "hostname.org",
-      RP_NAME = "RP Name",
-      RP_HTTPS_LOGO = "https://en.gravatar.com/userimage/6966791/c4feac761b8544cce13e0406f36230aa.jpg";
+      RP_NAME = "The Planet's Most Awesome Site",
+      RP_TOS_URL = "https://browserid.org/TOS.html",
+      RP_PP_URL = "https://browserid.org/priv.html",
+      RP_HTTPS_LOGO = "https://en.gravatar.com/userimage/6966791/c4feac761b8544cce13e0406f36230aa.jpg",
+      mediator = bid.Mediator;
 
   module("controllers/rp_info", {
     setup: testHelpers.setup,
@@ -84,5 +87,17 @@
     equal($("#rp_logo").attr("src"), RP_HTTPS_LOGO, "rp logo shown");
   });
 
+  test("privacyURL, tosURL, nextText specified - show TOS/PP info with nextText inserted", function() {
+    createController({
+      name: RP_NAME,
+      privacyURL: RP_PP_URL,
+      tosURL: RP_TOS_URL
+    });
+
+    equal($("#rp_name").text(), RP_NAME, "RP's name is set");
+    equal($("#rp_tos").attr("href"), RP_TOS_URL, "RP's TOS is set");
+    equal($("#rp_pp").attr("href"), RP_PP_URL, "RP's Privacy Policy is set");
+  });
+
 }());
 
diff --git a/resources/static/test/cases/controllers/verify_primary_user.js b/resources/static/test/cases/controllers/verify_primary_user.js
index 5203792b726a532a914f7ef376e269a4f1e86863..58573fa4a9a4c37c20d6a66c57eb8fdbfd6bda41 100644
--- a/resources/static/test/cases/controllers/verify_primary_user.js
+++ b/resources/static/test/cases/controllers/verify_primary_user.js
@@ -10,6 +10,7 @@
       controller,
       el,
       testHelpers = bid.TestHelpers,
+      testElementExists = testHelpers.testElementExists,
       WindowMock = bid.Mocks.WindowMock,
       win,
       mediator = bid.Mediator;
@@ -33,17 +34,17 @@
     }
   });
 
-  test("create with privacyURL and tosURL defined - show TOS/PP", function() {
+  test("create siteTOSPP set to true - show TOS/PP", function() {
     createController({
       window: win,
       add: false,
       email: "unregistered@testuser.com",
       auth_url: "http://testuser.com/sign_in",
-      privacyURL: "http://testuser.com/priv.html",
-      tosURL: "http://testuser.com/tos.html"
+      siteTOSPP: true
     });
 
-    equal($(".tospp").length, 1, "tospp has been added to the DOM");
+    // XXX There should be a generalized test for this.
+    testElementExists(".tospp", "tospp has been added to the DOM");
   });
 
   test("create with requiredEmail, privacyURL and tosURL defined - show TOS/PP", function() {
@@ -53,11 +54,10 @@
       requiredEmail: "unregistered@testuser.com",
       email: "unregistered@testuser.com",
       auth_url: "http://testuser.com/sign_in",
-      privacyURL: "http://testuser.com/priv.html",
-      tosURL: "http://testuser.com/tos.html"
+      siteTOSPP: true
     });
 
-    equal($(".tospp").length, 1, "tospp has been added to the DOM");
+    testElementExists(".tospp", "tospp has been added to the DOM");
   });
 
   asyncTest("submit with `add: false` option opens a new tab with CREATE_EMAIL URL", function() {
diff --git a/resources/static/test/cases/resources/state.js b/resources/static/test/cases/resources/state.js
index 1addb9623d02241590dc7906f8c0fdbf3a30f4be..1694a093c5ff7b50cb556a1f97bafe1d0915c1e4 100644
--- a/resources/static/test/cases/resources/state.js
+++ b/resources/static/test/cases/resources/state.js
@@ -34,6 +34,14 @@
     }
   }
 
+  function testActionStarted(actionName, requiredOptions) {
+    ok(actions.called[actionName], actionName + "called");
+    for(var key in requiredOptions) {
+      equal(actions.info[actionName][key], requiredOptions[key],
+          actionName + " called with " + key + "=" + requiredOptions[key]);
+    }
+  }
+
   function createMachine() {
     machine = bid.State.create();
     actions = new ActionsMock();
@@ -127,6 +135,17 @@
     equal(actions.info.doResetPassword.email, TEST_EMAIL, "correct email sent to doResetPassword");
   });
 
+  test("start - RPInfo always started", function() {
+    mediator.publish("start", {
+      tosURL: "https://browserid.org/TOS.html",
+      privacyURL: "https://browserid.org/priv.html"
+    });
+
+    ok(actions.info.doRPInfo.sitename, "doRPInfo called with sitename added and set");
+    ok(actions.info.doRPInfo.tosURL, "doRPInfo called with tosURL set");
+    ok(actions.info.doRPInfo.privacyURL, "doRPInfo called with privacyURL set");
+  });
+
   test("user_staged - call doConfirmUser", function() {
     mediator.publish("user_staged", { email: TEST_EMAIL });
 
@@ -250,13 +269,13 @@
     mediator.publish("authenticated", { email: TEST_EMAIL });
   });
 
-  test("forgot_password", function() {
+  test("forgot_password - call doForgotPassword with correct options", function() {
+    mediator.publish("start", { privacyURL: "priv.html", tosURL: "tos.html" });
     mediator.publish("forgot_password", {
       email: TEST_EMAIL,
       requiredEmail: true
     });
-    equal(actions.info.doForgotPassword.email, TEST_EMAIL, "correct email passed");
-    equal(actions.info.doForgotPassword.requiredEmail, true, "correct requiredEmail passed");
+    testActionStarted("doForgotPassword", { email: TEST_EMAIL, requiredEmail: true, siteTOSPP: true });
   });
 
   test("password_reset to user_confirmed - call doUserStaged then doEmailConfirmed", function() {
@@ -375,12 +394,11 @@
     ok(actions.called.doNotMe, "doNotMe has been called");
   });
 
-  test("authenticate", function() {
-    mediator.publish("authenticate", {
-      email: TEST_EMAIL
-    });
+  test("authenticate - call doAuthenticate with the correct options", function() {
+    mediator.publish("start", { privacyURL: "priv.html", tosURL: "tos.html" });
+    mediator.publish("authenticate", { email: TEST_EMAIL });
 
-    equal(actions.info.doAuthenticate.email, TEST_EMAIL, "authenticate with testuser@testuser.com");
+    testActionStarted("doAuthenticate", { email: TEST_EMAIL, siteTOSPP: true });
   });
 
   test("start with no special parameters - go straight to checking auth", function() {
@@ -406,16 +424,23 @@
   });
 
 
+  test("add_email - call doAddEmail with correct options", function() {
+    mediator.publish("start", { privacyURL: "priv.html", tosURL: "tos.html" });
+    mediator.publish("add_email");
+    testActionStarted("doAddEmail", { siteTOSPP: true });
+  });
+
   asyncTest("email_chosen with secondary email, user must authenticate - call doAuthenticateWithRequiredEmail", function() {
     var email = TEST_EMAIL;
     storage.addEmail(email, { type: "secondary" });
 
     xhr.setContextInfo("auth_level", "assertion");
 
+    mediator.publish("start", { privacyURL: "priv.html", tosURL: "tos.html" });
     mediator.publish("email_chosen", {
       email: email,
       complete: function() {
-        equal(actions.called.doAuthenticateWithRequiredEmail, true, "doAuthenticateWithRequiredEmail called");
+        testActionStarted("doAuthenticateWithRequiredEmail", { siteTOSPP: true });
         start();
       }
     });
@@ -472,8 +497,7 @@
 
     equal(actions.called.doPickEmail, true, "doPickEmail callled");
     equal(actions.info.doPickEmail.origin, "http://example.com", "hostname preserved");
-    equal(actions.info.doPickEmail.privacyURL, "http://example.com/priv.html", "privacyURL preserved");
-    equal(actions.info.doPickEmail.tosURL, "http://example.com/tos.html", "tosURL preserved");
+    equal(actions.info.doPickEmail.siteTOSPP, true, "siteTOSPP preserved");
   });
 
   test("add_email - call doAddEmail", function() {
diff --git a/resources/static/test/cases/shared/user.js b/resources/static/test/cases/shared/user.js
index a252cd357f1f73bc34d6c3bfed4755514813f2db..723ed803f6f74149fe7a116266fb44f6c616898d 100644
--- a/resources/static/test/cases/shared/user.js
+++ b/resources/static/test/cases/shared/user.js
@@ -91,6 +91,22 @@ var jwcrypto = require("./lib/jwcrypto");
     equal(lib.getReturnTo(), returnTo, "get/setReturnTo work as expected");
   });
 
+  test("setOriginEmail/getOriginEmail", function() {
+    storage.addEmail("testuser@testuser.com", { type: "primary" });
+    storage.addEmail("testuser2@testuser.com", { type: "primary" });
+
+    lib.setOrigin("http://testdomain.org");
+
+    lib.setOriginEmail("testuser@testuser.com");
+    equal(lib.getOriginEmail(), "testuser@testuser.com", "correct email");
+
+    lib.setOrigin("http://othertestdomain.org");
+    lib.setOriginEmail("testuser2@testuser.com");
+
+    lib.setOrigin("http://testdomain.org");
+    equal(lib.getOriginEmail(), "testuser@testuser.com", "correct email");
+  });
+
   test("getStoredEmailKeypairs without key - return all identities", function() {
     var identities = lib.getStoredEmailKeypairs();
     equal("object", typeof identities, "object returned");
diff --git a/resources/static/test/testHelpers/helpers.js b/resources/static/test/testHelpers/helpers.js
index 0a7130ef5fc565d31ee50761f104cad7d28043d2..8b65177da7e36526e587f7e738ca3efa25ed7634 100644
--- a/resources/static/test/testHelpers/helpers.js
+++ b/resources/static/test/testHelpers/helpers.js
@@ -220,17 +220,25 @@ BrowserID.TestHelpers = (function() {
       }
     },
 
-    testHasClass: function(selector, className, msg) {
-      ok($(selector).hasClass(className),
-          selector + " has className " + className + " - " + msg);
-    },
-
     testUndefined: function(toTest, msg) {
       equal(typeof toTest, "undefined", msg || "object is undefined");
     },
 
     testNotUndefined: function(toTest, msg) {
       notEqual(typeof toTest, "undefined", msg || "object is defined");
+    },
+
+    testHasClass: function(selector, className, msg) {
+      ok($(selector).hasClass(className),
+          msg || (selector + " has className " + className));
+    },
+
+    testElementDoesNotExist: function(selector, msg) {
+      equal($(selector).length, 0, msg || ("element '" + selector + "' does not exist"));
+    },
+
+    testElementExists: function(selector, msg) {
+      ok($(selector).length, msg || ("element '" + selector + "' exists"));
     }
 
   };