diff --git a/example/primary/provision.html b/example/primary/provision.html
index c8b7cd583c4c38008d9df3181fa2ee3539bbce92..01394cb48057b0a3ac2cdb3863b538686876e991 100644
--- a/example/primary/provision.html
+++ b/example/primary/provision.html
@@ -9,9 +9,6 @@
 <script type="text/javascript" src="/jquery.js"></script>
 <script type="text/javascript">
 
-  // an alias
-  var fail = navigator.id.raiseProvisioningFailure;
-
   // begin provisioning!  This both gives us indicated to browserid that we're
   // a well formed provisioning page and gives us the parameters of the provisioning
   navigator.id.beginProvisioning(function(email, cert_duration) {
@@ -22,7 +19,7 @@
     $.get('/api/whoami')
       .success(function(who) {
         if (user != who) {
-          return fail('user is not authenticated as target user');
+          return navigator.id.raiseProvisioningFailure('user is not authenticated as target user');
         }
 
         // Awesome!  The user is authenticated as who we want to provision.  let's
@@ -44,13 +41,13 @@
               navigator.id.registerCertificate(r.cert);
             },
             error: function(r) {
-              fail("couldn't certify key");
+              navigator.id.raiseProvisioningFailure("couldn't certify key");
             }
           });
         });
       })
       .error(function() {
-        fail('user is not authenticated');
+        navigator.id.raiseProvisioningFailure('user is not authenticated');
       });
   });
 </script>
diff --git a/example/primary/sign_in.html b/example/primary/sign_in.html
index 51a0eaccae58c47b4ffa31f88220cb0a9b2aec60..838080d2fb96fb83dfe87695538437e7269e1d4d 100644
--- a/example/primary/sign_in.html
+++ b/example/primary/sign_in.html
@@ -33,37 +33,30 @@ button { line-height: 20px; }
 </div>
 
 <script type="text/javascript" src="jquery.js"></script>
+<script type="text/javascript" src="https://login.persona.org/authentication_api.js"></script>
 <script type="text/javascript">
 
-function getParameterByName(name)
-{
-  name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
-  var regexS = "[\\?&]" + name + "=([^&#]*)";
-  var regex = new RegExp(regexS);
-  var results = regex.exec(window.location.href);
-  if(results == null)
-    return "";
-  else
-    return decodeURIComponent(results[1].replace(/\+/g, " "));
-}
+var who = null;
 
 $(document).ready(function() {
   try {
-    var who = getParameterByName("email").replace(/@.*$/, "");
-    $('#who').text(who);
+    navigator.id.beginAuthentication(function(email) {
+      who = /^([^@]+)@/.exec(email)[1];
+      $('#who').text(who);
+    });
   } catch(e) {
     alert("uh oh: " + e);
   }
   $("button").click(function(e) {
     $.get('/api/login', { user: who })
       .success(function(r) {
-        window.location = getParameterByName('return_to');
+        navigator.id.completeAuthentication();
       });
   });
 
   $("#cancel").click(function(e) {
     e.preventDefault();
-    window.location = getParameterByName('return_to');
+    navigator.id.raiseAuthenticationFailure('cancel');
   });
 });
 </script>
diff --git a/resources/static/authentication_api.js b/resources/static/authentication_api.js
index 5bc44cd704cabf66c811e6933da34cc720c4bc3a..ca9b16c49990977dac2d828dacfdf2a9ea669571 100644
--- a/resources/static/authentication_api.js
+++ b/resources/static/authentication_api.js
@@ -23,7 +23,6 @@
       return decodeURIComponent(results[1].replace(/\+/g, " "));
   }
 
-
   if (!navigator.id.beginAuthentication || navigator.id._primaryAPIIsShimmed) {
     navigator.id.beginAuthentication = function(cb) {
       if (typeof cb !== 'function') {
@@ -34,11 +33,11 @@
     };
 
     navigator.id.completeAuthentication = function(cb) {
-      window.location = getParameterByName('return_to');
+      window.location = 'https://login.persona.org/sign_in#AUTH_RETURN';
     };
 
     navigator.id.raiseAuthenticationFailure = function(reason) {
-      window.location = getParameterByName('return_to');
+      window.location = 'https://login.persona.org/sign_in#AUTH_RETURN_CANCEL';
     };
 
     navigator.id._primaryAPIIsShimmed = true;
diff --git a/resources/static/dialog/js/modules/dialog.js b/resources/static/dialog/js/modules/dialog.js
index 1e14ca80d2f1354555169b977c9986431cbbe8a8..1a426a580653df1bfa93e288c8e0b8fa6306ad3f 100644
--- a/resources/static/dialog/js/modules/dialog.js
+++ b/resources/static/dialog/js/modules/dialog.js
@@ -195,24 +195,19 @@ BrowserID.Modules.Dialog = (function() {
           user.setReturnTo(returnTo);
         }
 
-
-        if (hash.indexOf("#CREATE_EMAIL=") === 0) {
-          var email = hash.replace(/#CREATE_EMAIL=/, "");
-          if (!bid.verifyEmail(email))
-            throw "invalid #CREATE_EMAIL= (" + email + ")";
-          params.type = "primary";
-          params.email = email;
-          params.add = false;
-        }
-        else if (hash.indexOf("#ADD_EMAIL=") === 0) {
-          var email = hash.replace(/#ADD_EMAIL=/, "");
-          if (!bid.verifyEmail(email))
-            throw "invalid #ADD_EMAIL= (" + email + ")";
+        if (hash.indexOf("#AUTH_RETURN") === 0) {
+          var primaryParams = JSON.parse(win.sessionStorage.primaryVerificationFlow);
+          params.email = primaryParams.email;
+          params.add = primaryParams.add;
           params.type = "primary";
-          params.email = email;
-          params.add = true;
+
+          // FIXME: if it's AUTH_RETURN_CANCEL, we should short-circuit
+          // the attempt at provisioning. For now, we let provisioning
+          // be tried and fail.
         }
 
+        // no matter what, we clear the primary flow state for this window
+        win.sessionStorage.primaryVerificationFlow = undefined;
       } catch(e) {
         // note: renderError accepts HTML and cheerfully injects it into a
         // frame with a powerful origin. So convert 'e' first.
diff --git a/resources/static/dialog/js/modules/verify_primary_user.js b/resources/static/dialog/js/modules/verify_primary_user.js
index 9e38e6be13bfec2f9039451cb860310b7b03a2f3..b12827f7c6a99f4290df6f81a3483c5c26594371 100644
--- a/resources/static/dialog/js/modules/verify_primary_user.js
+++ b/resources/static/dialog/js/modules/verify_primary_user.js
@@ -18,15 +18,14 @@ BrowserID.Modules.VerifyPrimaryUser = (function() {
   function verify(callback) {
     this.publish("primary_user_authenticating");
 
-    // replace any hashes that may be there already.
-    var returnTo = win.document.location.href.replace(/#.*$/, "");
-
-    var type = add ? "ADD_EMAIL" : "CREATE_EMAIL";
-    var url = helpers.toURL(auth_url, {
-      email: email,
-      return_to: returnTo + "#" + type + "=" +email
+    // set up some information about what we're doing
+    win.sessionStorage.primaryVerificationFlow = JSON.stringify({
+      add: add,
+      email: email
     });
 
+    var url = helpers.toURL(auth_url, {email: email});
+    
     win.document.location = url;
 
     complete(callback);
diff --git a/resources/static/dialog/js/start.js b/resources/static/dialog/js/start.js
index 70c574bad3f2e645532c48aee54fdec314b886fc..3536e1f25e1b9f346debb65f5ecc0966f04d0d21 100644
--- a/resources/static/dialog/js/start.js
+++ b/resources/static/dialog/js/start.js
@@ -15,7 +15,7 @@
   network.init();
 
   var hash = window.location.hash || "",
-      continuation = hash.indexOf("#CREATE_EMAIL") > -1 || hash.indexOf("#ADD_EMAIL") > -1;
+      continuation = hash.indexOf("#AUTH_RETURN") > -1;
 
   moduleManager.register("interaction_data", modules.InteractionData);
   moduleManager.start("interaction_data", { continuation: continuation });
diff --git a/resources/static/test/cases/dialog/js/modules/dialog.js b/resources/static/test/cases/dialog/js/modules/dialog.js
index 1f0f7ffd1ac497d3a62b4922394a24d062f20e94..0a6c14d5f3ba78f1e537426c2ede9608fd1ece13 100644
--- a/resources/static/test/cases/dialog/js/modules/dialog.js
+++ b/resources/static/test/cases/dialog/js/modules/dialog.js
@@ -50,6 +50,8 @@
     },
 
     navigator: {},
+
+    sessionStorage: {}
   };
 
   function createController(config) {
@@ -134,8 +136,12 @@
     });
   });
 
-  asyncTest("initialization with #CREATE_EMAIL=testuser@testuser.com - trigger start with correct params", function() {
-    winMock.location.hash = "#CREATE_EMAIL=testuser@testuser.com";
+  asyncTest("initialization with #AUTH_RETURN and add=false - trigger start with correct params", function() {
+    winMock.location.hash = "#AUTH_RETURN";
+    winMock.sessionStorage.primaryVerificationFlow = JSON.stringify({
+      add: false,
+      email: TESTEMAIL
+    });
 
     createController({
       ready: function() {
@@ -157,8 +163,12 @@
     });
   });
 
-  asyncTest("initialization with #ADD_EMAIL=testuser@testuser.com - trigger start with correct params", function() {
-    winMock.location.hash = "#ADD_EMAIL=testuser@testuser.com";
+  asyncTest("initialization with #AUTH_RETURN and add=true - trigger start with correct params", function() {
+    winMock.location.hash = "#AUTH_RETURN";
+    winMock.sessionStorage.primaryVerificationFlow = JSON.stringify({
+      add: true,
+      email: TESTEMAIL
+    });
 
     createController({
       ready: function() {
diff --git a/resources/static/test/cases/dialog/js/modules/verify_primary_user.js b/resources/static/test/cases/dialog/js/modules/verify_primary_user.js
index 5203792b726a532a914f7ef376e269a4f1e86863..0bd75f72e9456e2fc72097969fc46d4a2b7766a4 100644
--- a/resources/static/test/cases/dialog/js/modules/verify_primary_user.js
+++ b/resources/static/test/cases/dialog/js/modules/verify_primary_user.js
@@ -60,7 +60,7 @@
     equal($(".tospp").length, 1, "tospp has been added to the DOM");
   });
 
-  asyncTest("submit with `add: false` option opens a new tab with CREATE_EMAIL URL", function() {
+  asyncTest("submit with `add: false` option opens a new tab with proper URL (updated for sessionStorage)", function() {
     var messageTriggered = false;
     createController({
       window: win,
@@ -77,13 +77,13 @@
     win.document.location.hash = "#NATIVE";
 
     controller.submit(function() {
-      equal(win.document.location, "http://testuser.com/sign_in?email=unregistered%40testuser.com&return_to=sign_in%23CREATE_EMAIL%3Dunregistered%40testuser.com");
+      equal(win.document.location, "http://testuser.com/sign_in?email=unregistered%40testuser.com");
       equal(messageTriggered, true, "primary_user_authenticating triggered");
       start();
     });
   });
 
-  asyncTest("submit with `add: true` option opens a new tab with ADD_EMAIL URL", function() {
+  asyncTest("submit with `add: true` option opens a new tab with proper URL (updated for sessionStorage)", function() {
     createController({
       window: win,
       add: true,
@@ -96,7 +96,7 @@
     win.document.location.hash = "#NATIVE";
 
     controller.submit(function() {
-      equal(win.document.location, "http://testuser.com/sign_in?email=unregistered%40testuser.com&return_to=sign_in%23ADD_EMAIL%3Dunregistered%40testuser.com");
+      equal(win.document.location, "http://testuser.com/sign_in?email=unregistered%40testuser.com");
       start();
     });
   });
diff --git a/resources/static/test/mocks/window.js b/resources/static/test/mocks/window.js
index 510514288a7897747ba90d6c00b38be5641a0ba4..a633ba0d20180139f7bcca5d6230f0d30379c1aa 100644
--- a/resources/static/test/mocks/window.js
+++ b/resources/static/test/mocks/window.js
@@ -15,6 +15,7 @@ BrowserID.Mocks.WindowMock = (function() {
 
   function WindowMock() {
     this.document = new DocumentMock();
+    this.sessionStorage = {};
   }
   WindowMock.prototype = {
     open: function(url, name, options) {