diff --git a/resources/static/dialog/controllers/dialog.js b/resources/static/dialog/controllers/dialog.js
index 8f670b8b238bc3d0fa85a1cb0d3f6ad3d3691ef6..ec3a1d365735b200f93d315c0d916df4ed936f18 100644
--- a/resources/static/dialog/controllers/dialog.js
+++ b/resources/static/dialog/controllers/dialog.js
@@ -184,16 +184,19 @@ BrowserID.Modules.Dialog = (function() {
           params.siteName = _.escape(paramsFromRP.siteName);
         }
 
-        var originHREF = paramsFromRP.originHREF;
-
-        // Native implementations will be behind on the originHREF feature.  Until
-        // they are ready, set the originHREF to be the origin_url;
-        if (!originHREF) originHREF = origin_url;
-
-        if(originHREF.indexOf(origin_url) !== 0) {
-          throw "originHREF/origin mismatch";
+        // returnTo is used for post verification redirection.  Redirect back
+        // to the path specified by the RP.
+        var returnTo;
+        if (paramsFromRP.returnTo) {
+          returnTo = fixupAbsolutePath(origin_url, paramsFromRP.returnTo);
         }
-        user.setOriginHREF(fixupURL(origin_url, originHREF));
+        else {
+          // Native implementations will be behind on the returnTo feature.  Until
+          // they are ready, set the returnTo to be the origin_url;
+          returnTo = origin_url;
+        }
+
+        user.setReturnTo(returnTo);
 
         if (hash.indexOf("#CREATE_EMAIL=") === 0) {
           var email = hash.replace(/#CREATE_EMAIL=/, "");
diff --git a/resources/static/include_js/include.js b/resources/static/include_js/include.js
index 053b1b58fcad9bffcb9cab7ca7a2eac3c386027b..b4da74e0cd095e51a08e0c5831b9c88d40d07e3f 100644
--- a/resources/static/include_js/include.js
+++ b/resources/static/include_js/include.js
@@ -1069,8 +1069,8 @@
       // don't do duplicative work
       if (commChan) commChan.notify({ method: 'dialog_running' });
 
-      // originHREF is used for post-email-verification redirect
-      options.originHREF = document.location.href;
+      // returnTo is used for post-email-verification redirect
+      if (!options.returnTo) options.returnTo = document.location.href;
 
       w = WinChan.open({
         url: ipServer + '/sign_in',
diff --git a/resources/static/shared/storage.js b/resources/static/shared/storage.js
index 53ff05adc9496b39cec096984e72897a96492924..7f055c069e5df2c03c27361ad853604ba82b5db0 100644
--- a/resources/static/shared/storage.js
+++ b/resources/static/shared/storage.js
@@ -146,18 +146,18 @@ BrowserID.Storage = (function() {
     }
   }
 
-  function setStagedOnBehalfOf(origin) {
-    storage.stagedOnBehalfOf = JSON.stringify({
+  function setReturnTo(origin) {
+    storage.returnTo = JSON.stringify({
       at: new Date().toString(),
       origin: origin
     });
   }
 
-  function getStagedOnBehalfOf() {
+  function getReturnTo() {
     var origin;
 
     try {
-      var staged = JSON.parse(storage.stagedOnBehalfOf);
+      var staged = JSON.parse(storage.returnTo || storage.stagedOnBehalfOf);
 
       if (staged) {
         if ((new Date() - new Date(staged.at)) > (5 * 60 * 1000)) throw "stale";
@@ -165,6 +165,7 @@ BrowserID.Storage = (function() {
         origin = staged.origin;
       }
     } catch (x) {
+      storage.removeItem("returnTo");
       storage.removeItem("stagedOnBehalfOf");
     }
 
@@ -569,7 +570,7 @@ BrowserID.Storage = (function() {
     clear: clear,
     storeTemporaryKeypair: storeTemporaryKeypair,
     retrieveTemporaryKeypair: retrieveTemporaryKeypair,
-    setStagedOnBehalfOf: setStagedOnBehalfOf,
-    getStagedOnBehalfOf: getStagedOnBehalfOf
+    setReturnTo: setReturnTo,
+    getReturnTo: getReturnTo
   };
 }());
diff --git a/resources/static/shared/user.js b/resources/static/shared/user.js
index b0445716346abe5a2deba5f80930dac55e42272e..2d293c7e0d80790903ad6d6b1778a5e17e31706e 100644
--- a/resources/static/shared/user.js
+++ b/resources/static/shared/user.js
@@ -113,7 +113,7 @@ BrowserID.User = (function() {
           // As soon as the registration comes back as complete, we should
           // ensure that the stagedOnBehalfOf is cleared so there is no stale
           // data.
-          storage.setStagedOnBehalfOf("");
+          storage.setReturnTo("");
 
           // To avoid too many address_info requests, returns from each
           // address_info request are cached.  If the user is doing
@@ -273,12 +273,12 @@ BrowserID.User = (function() {
       return origin.replace(/^.*:\/\//, "").replace(/:\d*$/, "");
     },
 
-    setOriginHREF: function(originHREF) {
-      this.originHREF = originHREF;
+    setReturnTo: function(returnTo) {
+      this.returnTo = returnTo;
     },
 
-    getOriginHREF: function() {
-      return this.originHREF;
+    getReturnTo: function() {
+      return this.returnTo;
     },
 
     /**
@@ -292,8 +292,8 @@ BrowserID.User = (function() {
       network.createUser(email, password, origin, function(created) {
         // Used on the main site when the user verifies - once verification
         // is complete, the user is redirected back to the RP and logged in.
-        var site = User.getOriginHREF();
-        if (created && site) storage.setStagedOnBehalfOf(site);
+        var site = User.getReturnTo();
+        if (created && site) storage.setReturnTo(site);
         complete(onComplete, created);
       }, onFailure);
     },
@@ -486,7 +486,7 @@ BrowserID.User = (function() {
     tokenInfo: function(token, onComplete, onFailure) {
       network.emailForVerificationToken(token, function (info) {
         if(info) {
-          info = _.extend(info, { origin: storage.getStagedOnBehalfOf() });
+          info = _.extend(info, { origin: storage.getReturnTo() });
         }
 
         onComplete && onComplete(info);
@@ -512,8 +512,8 @@ BrowserID.User = (function() {
             var result = invalidInfo;
 
             if(valid) {
-              result = _.extend({ valid: valid, origin: storage.getStagedOnBehalfOf() }, info);
-              storage.setStagedOnBehalfOf("");
+              result = _.extend({ valid: valid, origin: storage.getReturnTo() }, info);
+              storage.setReturnTo("");
             }
 
             complete(onComplete, result);
@@ -582,8 +582,8 @@ BrowserID.User = (function() {
             // Used on the main site when the user verifies - once
             // verification is complete, the user is redirected back to the
             // RP and logged in.
-            var site = User.getOriginHREF();
-            if (reset && site) storage.setStagedOnBehalfOf(site);
+            var site = User.getReturnTo();
+            if (reset && site) storage.setReturnTo(site);
 
             complete(onComplete, status);
           }, onFailure);
@@ -816,8 +816,8 @@ BrowserID.User = (function() {
       network.addSecondaryEmail(email, password, origin, function(added) {
         // Used on the main site when the user verifies - once verification
         // is complete, the user is redirected back to the RP and logged in.
-        var originHREF = User.getOriginHREF();
-        if (added && originHREF) storage.setStagedOnBehalfOf(originHREF);
+        var returnTo = User.getReturnTo();
+        if (added && returnTo) storage.setReturnTo(returnTo);
 
         // we no longer send the keypair, since we will certify it later.
         complete(onComplete, added);
@@ -882,8 +882,8 @@ BrowserID.User = (function() {
             var result = invalidInfo;
 
             if(valid) {
-              result = _.extend({ valid: valid, origin: storage.getStagedOnBehalfOf() }, info);
-              storage.setStagedOnBehalfOf("");
+              result = _.extend({ valid: valid, origin: storage.getReturnTo() }, info);
+              storage.setReturnTo("");
             }
 
             complete(onComplete, result);
diff --git a/resources/static/test/cases/controllers/dialog.js b/resources/static/test/cases/controllers/dialog.js
index ebd95b2b12932d258356ab4c34afdab514a4b8c5..aedd54d97475b720ed0affd26f640161948dfd04 100644
--- a/resources/static/test/cases/controllers/dialog.js
+++ b/resources/static/test/cases/controllers/dialog.js
@@ -18,7 +18,6 @@
       user = bid.User,
       HTTP_TEST_DOMAIN = "http://testdomain.org",
       HTTPS_TEST_DOMAIN = "https://testdomain.org",
-      HTTPS_TEST_URL = "https://testdomain.org/some/page",
       TESTEMAIL = "testuser@testuser.com",
       controller,
       el,
@@ -585,33 +584,36 @@
   });
 
 
-  asyncTest("originHREF specified, different domain as origin - error thrown", function() {
+  asyncTest("get with returnTo with https - not allowed", function() {
     createController({
       ready: function() {
+        var URL = HTTP_TEST_DOMAIN + "/path";
+
         mediator.subscribe("start", function(msg, info) {
           ok(false, "unexpected start");
         });
 
         var retval = controller.get(HTTP_TEST_DOMAIN, {
-          originHREF: "http://different.domain"
+          returnTo: URL
         });
-        equal(retval, "originHREF/origin mismatch", "expected error");
+
+        equal(retval, "must be an absolute path: (" + URL + ")", "expected error");
         testErrorVisible();
         start();
       }
     });
   });
 
-  asyncTest("originHREF specified, same domain as origin - originHREF correctly set", function() {
+  asyncTest("get with absolute path returnTo - allowed", function() {
     createController({
       ready: function() {
         mediator.subscribe("start", function(msg, info) {
-          equal(user.getOriginHREF(), HTTPS_TEST_URL, "Origin HREF correctly set");
+          equal(user.getReturnTo(), HTTPS_TEST_DOMAIN + "/path", "returnTo correctly set");
           start();
         });
 
         var retval = controller.get(HTTPS_TEST_DOMAIN, {
-          originHREF: HTTPS_TEST_URL
+          returnTo: "/path"
         });
       }
     });
diff --git a/resources/static/test/cases/pages/verify_secondary_address.js b/resources/static/test/cases/pages/verify_secondary_address.js
index 79bfcd6ab6ce324199b0c453365859d1c86c0ac0..99d2917af1a4c93aa1429069c449ae532f30d055 100644
--- a/resources/static/test/cases/pages/verify_secondary_address.js
+++ b/resources/static/test/cases/pages/verify_secondary_address.js
@@ -71,7 +71,7 @@
   });
 
   asyncTest("no password: start with good token and site", function() {
-    storage.setStagedOnBehalfOf("browserid.org");
+    storage.setReturnTo("browserid.org");
 
     createController(config, function() {
       testEmail();
diff --git a/resources/static/test/cases/shared/storage.js b/resources/static/test/cases/shared/storage.js
index c9406c84a21ef077b4a150f956a3666a0eccc505..5a7048c00799dfa54ebd351407cf45199264aec9 100644
--- a/resources/static/test/cases/shared/storage.js
+++ b/resources/static/test/cases/shared/storage.js
@@ -164,12 +164,9 @@
     // XXX needs a test
   });
 
-  test("setStagedOnBehalfOf", function() {
-    // XXX needs a test
-  });
-
-  test("getStagedOnBehalfOf", function() {
-    // XXX needs a test
+  test("setReturnTo", function() {
+    storage.setReturnTo("http://some.domain/path");
+    equal(storage.getReturnTo(), "http://some.domain/path", "setReturnTo/getReturnTo working as expected");
   });
 
   test("signInEmail.set/.get/.remove - set, get, and remove the signInEmail", function() {
diff --git a/resources/static/test/cases/shared/user.js b/resources/static/test/cases/shared/user.js
index 0a3a8cdb2e08197d120d48a16211c71ee2deab2d..9da4f8474665ec7be3f35a6e1e5f8e7be80c5dbd 100644
--- a/resources/static/test/cases/shared/user.js
+++ b/resources/static/test/cases/shared/user.js
@@ -85,10 +85,10 @@ var jwcrypto = require("./lib/jwcrypto");
     equal(hostname, "browserid.org", "getHostname returns only the hostname");
   });
 
-  test("setOriginHREF, getOriginHREF", function() {
-    var originHREF = "http://samplerp.org";
-    lib.setOriginHREF(originHREF);
-    equal(lib.getOriginHREF(), originHREF, "get/setOriginHREF work as expected");
+  test("setReturnTo, getReturnTo", function() {
+    var returnTo = "http://samplerp.org";
+    lib.setReturnTo(returnTo);
+    equal(lib.getReturnTo(), returnTo, "get/setReturnTo work as expected");
   });
 
   test("getStoredEmailKeypairs without key - return all identities", function() {
@@ -298,27 +298,27 @@ var jwcrypto = require("./lib/jwcrypto");
   });
 
   asyncTest("waitForUserValidation with `complete` response", function() {
-    storage.setStagedOnBehalfOf(testOrigin);
+    storage.setReturnTo(testOrigin);
 
     xhr.useResult("complete");
 
     lib.waitForUserValidation("registered@testuser.com", function(status) {
       equal(status, "complete", "complete response expected");
 
-      ok(!storage.getStagedOnBehalfOf(), "staged on behalf of is cleared when validation completes");
+      ok(!storage.getReturnTo(), "staged on behalf of is cleared when validation completes");
       start();
     }, testHelpers.unexpectedXHRFailure);
   });
 
   asyncTest("waitForUserValidation with `mustAuth` response", function() {
-    storage.setStagedOnBehalfOf(testOrigin);
+    storage.setReturnTo(testOrigin);
 
     xhr.useResult("mustAuth");
 
     lib.waitForUserValidation("registered@testuser.com", function(status) {
       equal(status, "mustAuth", "mustAuth response expected");
 
-      ok(!storage.getStagedOnBehalfOf(), "staged on behalf of is cleared when validation completes");
+      ok(!storage.getReturnTo(), "staged on behalf of is cleared when validation completes");
       start();
     }, testHelpers.unexpectedXHRFailure);
   });
@@ -326,12 +326,12 @@ var jwcrypto = require("./lib/jwcrypto");
   asyncTest("waitForUserValidation with `noRegistration` response", function() {
     xhr.useResult("noRegistration");
 
-    storage.setStagedOnBehalfOf(testOrigin);
+    storage.setReturnTo(testOrigin);
     lib.waitForUserValidation(
       "registered@testuser.com",
       testHelpers.unexpectedSuccess,
       function(status) {
-        ok(storage.getStagedOnBehalfOf(), "staged on behalf of is not cleared for noRegistration response");
+        ok(storage.getReturnTo(), "staged on behalf of is not cleared for noRegistration response");
         ok(status, "noRegistration", "noRegistration response causes failure");
         start();
       }
@@ -340,12 +340,12 @@ var jwcrypto = require("./lib/jwcrypto");
 
 
   asyncTest("waitForUserValidation with XHR failure", function() {
-    storage.setStagedOnBehalfOf(testOrigin);
+    storage.setReturnTo(testOrigin);
     lib.waitForUserValidation(
       "registered@testuser.com",
       testHelpers.unexpectedSuccess,
       function() {
-        ok(storage.getStagedOnBehalfOf(), "staged on behalf of is not cleared on XHR failure");
+        ok(storage.getReturnTo(), "staged on behalf of is not cleared on XHR failure");
         ok(true, "xhr failure should always be a failure");
         start();
       }
@@ -355,7 +355,7 @@ var jwcrypto = require("./lib/jwcrypto");
   asyncTest("cancelUserValidation: ~1 second", function() {
     xhr.useResult("pending");
 
-    storage.setStagedOnBehalfOf(testOrigin);
+    storage.setReturnTo(testOrigin);
     // yes, we are neither expected succes nor failure because we are
     // cancelling the wait.
     lib.waitForUserValidation(
@@ -366,13 +366,13 @@ var jwcrypto = require("./lib/jwcrypto");
 
     setTimeout(function() {
       lib.cancelUserValidation();
-      ok(storage.getStagedOnBehalfOf(), "staged on behalf of is not cleared when validation cancelled");
+      ok(storage.getReturnTo(), "staged on behalf of is not cleared when validation cancelled");
       start();
     }, 500);
   });
 
   asyncTest("tokenInfo with a good token and origin info, expect origin in results", function() {
-    storage.setStagedOnBehalfOf(testOrigin);
+    storage.setReturnTo(testOrigin);
 
     lib.tokenInfo("token", function(info) {
       equal(info.email, TEST_EMAIL, "correct email");
@@ -394,14 +394,14 @@ var jwcrypto = require("./lib/jwcrypto");
   });
 
   asyncTest("verifyUser with a good token", function() {
-    storage.setStagedOnBehalfOf(testOrigin);
+    storage.setReturnTo(testOrigin);
 
     lib.verifyUser("token", "password", function onSuccess(info) {
 
       ok(info.valid, "token was valid");
       equal(info.email, TEST_EMAIL, "email part of info");
       equal(info.origin, testOrigin, "origin in info");
-      equal(storage.getStagedOnBehalfOf(), "", "initiating origin was removed");
+      equal(storage.getReturnTo(), "", "initiating origin was removed");
 
       start();
     }, testHelpers.unexpectedXHRFailure);
@@ -467,12 +467,12 @@ var jwcrypto = require("./lib/jwcrypto");
   });
 
   asyncTest("requestPasswordReset with known email - true status", function() {
-    var originHREF = "http://samplerp.org";
-    lib.setOriginHREF(originHREF);
+    var returnTo = "http://samplerp.org";
+    lib.setReturnTo(returnTo);
 
     lib.requestPasswordReset("registered@testuser.com", "password", function(status) {
       equal(status.success, true, "password reset for known user");
-      equal(storage.getStagedOnBehalfOf(), originHREF, "RP URL is stored for verification");
+      equal(storage.getReturnTo(), returnTo, "RP URL is stored for verification");
 
       start();
     }, testHelpers.unexpectedXHRFailure);
@@ -653,8 +653,8 @@ var jwcrypto = require("./lib/jwcrypto");
   });
 
   asyncTest("addEmail", function() {
-    var originHREF = "http://samplerp.org";
-    lib.setOriginHREF(originHREF);
+    var returnTo = "http://samplerp.org";
+    lib.setReturnTo(returnTo);
 
     lib.addEmail("testemail@testemail.com", "password", function(added) {
       ok(added, "user was added");
@@ -662,7 +662,7 @@ var jwcrypto = require("./lib/jwcrypto");
       var identities = lib.getStoredEmailKeypairs();
       equal("testemail@testemail.com" in identities, false, "new email is not added until confirmation.");
 
-      equal(storage.getStagedOnBehalfOf(), originHREF, "RP URL is stored for verification");
+      equal(storage.getReturnTo(), returnTo, "RP URL is stored for verification");
 
       start();
     }, testHelpers.unexpectedXHRFailure);
@@ -677,7 +677,7 @@ var jwcrypto = require("./lib/jwcrypto");
       var identities = lib.getStoredEmailKeypairs();
       equal(false, "testemail@testemail.com" in identities, "Our new email is not added until confirmation.");
 
-      equal(typeof storage.getStagedOnBehalfOf(), "undefined", "initiatingOrigin is not stored");
+      equal(typeof storage.getReturnTo(), "undefined", "initiatingOrigin is not stored");
 
       start();
     }, testHelpers.unexpectedXHRFailure);
@@ -689,36 +689,36 @@ var jwcrypto = require("./lib/jwcrypto");
 
 
  asyncTest("waitForEmailValidation `complete` response", function() {
-    storage.setStagedOnBehalfOf(testOrigin);
+    storage.setReturnTo(testOrigin);
 
     xhr.useResult("complete");
     lib.waitForEmailValidation("registered@testuser.com", function(status) {
-      ok(!storage.getStagedOnBehalfOf(), "staged on behalf of is cleared when validation completes");
+      ok(!storage.getReturnTo(), "staged on behalf of is cleared when validation completes");
       equal(status, "complete", "complete response expected");
       start();
     }, testHelpers.unexpectedXHRFailure);
   });
 
   asyncTest("waitForEmailValidation `mustAuth` response", function() {
-    storage.setStagedOnBehalfOf(testOrigin);
+    storage.setReturnTo(testOrigin);
     xhr.useResult("mustAuth");
 
     lib.waitForEmailValidation("registered@testuser.com", function(status) {
-      ok(!storage.getStagedOnBehalfOf(), "staged on behalf of is cleared when validation completes");
+      ok(!storage.getReturnTo(), "staged on behalf of is cleared when validation completes");
       equal(status, "mustAuth", "mustAuth response expected");
       start();
     }, testHelpers.unexpectedXHRFailure);
   });
 
   asyncTest("waitForEmailValidation with `noRegistration` response", function() {
-    storage.setStagedOnBehalfOf(testOrigin);
+    storage.setReturnTo(testOrigin);
     xhr.useResult("noRegistration");
 
     lib.waitForEmailValidation(
       "registered@testuser.com",
       testHelpers.unexpectedSuccess,
       function(status) {
-        ok(storage.getStagedOnBehalfOf(), "staged on behalf of is cleared when validation completes");
+        ok(storage.getReturnTo(), "staged on behalf of is cleared when validation completes");
         ok(status, "noRegistration", "noRegistration response causes failure");
         start();
       });
@@ -726,7 +726,7 @@ var jwcrypto = require("./lib/jwcrypto");
 
 
  asyncTest("waitForEmailValidation XHR failure", function() {
-    storage.setStagedOnBehalfOf(testOrigin);
+    storage.setReturnTo(testOrigin);
     xhr.useResult("ajaxError");
 
     lib.waitForEmailValidation(
@@ -740,7 +740,7 @@ var jwcrypto = require("./lib/jwcrypto");
   asyncTest("cancelEmailValidation: ~1 second", function() {
     xhr.useResult("pending");
 
-    storage.setStagedOnBehalfOf(testOrigin);
+    storage.setReturnTo(testOrigin);
     lib.waitForEmailValidation(
       "registered@testuser.com",
       testHelpers.unexpectedSuccess,
@@ -749,19 +749,19 @@ var jwcrypto = require("./lib/jwcrypto");
 
     setTimeout(function() {
       lib.cancelUserValidation();
-      ok(storage.getStagedOnBehalfOf(), "staged on behalf of is not cleared when validation cancelled");
+      ok(storage.getReturnTo(), "staged on behalf of is not cleared when validation cancelled");
       start();
     }, 500);
   });
 
   asyncTest("verifyEmail with a good token - callback with email, origin, valid", function() {
-    storage.setStagedOnBehalfOf(testOrigin);
+    storage.setReturnTo(testOrigin);
     lib.verifyEmail("token", "password", function onSuccess(info) {
 
       ok(info.valid, "token was valid");
       equal(info.email, TEST_EMAIL, "email part of info");
       equal(info.origin, testOrigin, "origin in info");
-      equal(storage.getStagedOnBehalfOf(), "", "initiating origin was removed");
+      equal(storage.getReturnTo(), "", "initiating origin was removed");
 
       start();
     }, testHelpers.unexpectedXHRFailure);
@@ -1213,7 +1213,7 @@ var jwcrypto = require("./lib/jwcrypto");
 
   asyncTest("shouldAskIfUsersComputer with user who has not been asked and has verified email in this dialog session - call onSuccess with false", function() {
     lib.authenticate(TEST_EMAIL, "password", function() {
-      storage.setStagedOnBehalfOf(testOrigin);
+      storage.setReturnTo(testOrigin);
       xhr.useResult("complete");
 
       lib.waitForEmailValidation(TEST_EMAIL, function() {