diff --git a/resources/static/dialog/js/modules/dialog.js b/resources/static/dialog/js/modules/dialog.js
index f7102480aafea9ca45b1b0e29d02473f262bc870..e59ee32575e1e23bc8a83cee4ba82e6fd6a4250e 100644
--- a/resources/static/dialog/js/modules/dialog.js
+++ b/resources/static/dialog/js/modules/dialog.js
@@ -109,6 +109,16 @@ BrowserID.Modules.Dialog = (function() {
     throw "must be an absolute path: (" + path + ")";
   }
 
+  function fixupReturnTo(origin_url, path) {
+    // "/" is a valid returnTo, but it is not a valid path for any other
+    // parameter. If the path is "/", allow it, otherwise pass the path down
+    // the normal checks.
+    var returnTo = path === "/" ?
+      origin_url + path :
+      fixupAbsolutePath(origin_url, path);
+    return returnTo;
+  }
+
   function validateRPAPI(rpAPI) {
     var VALID_RP_API_VALUES = [
       "watch_without_onready",
@@ -225,7 +235,7 @@ BrowserID.Modules.Dialog = (function() {
         // returnTo is used for post verification redirection.  Redirect back
         // to the path specified by the RP.
         if (paramsFromRP.returnTo) {
-          var returnTo = fixupAbsolutePath(origin_url, paramsFromRP.returnTo);
+          var returnTo = fixupReturnTo(origin_url, paramsFromRP.returnTo);
           user.setReturnTo(returnTo);
         }
 
diff --git a/resources/static/test/cases/dialog/js/modules/dialog.js b/resources/static/test/cases/dialog/js/modules/dialog.js
index 207d9cca50b0bba930b60a1c8f23d524f45b9717..ca94b81280c47f952de90526f0e19c9710a62fea 100644
--- a/resources/static/test/cases/dialog/js/modules/dialog.js
+++ b/resources/static/test/cases/dialog/js/modules/dialog.js
@@ -59,7 +59,7 @@
     // dialog as an individual unit.
     var options = $.extend({
       window: winMock,
-      startExternalDependencies: false,
+      startExternalDependencies: false
     }, config);
 
     controller = BrowserID.Modules.Dialog.create();
@@ -72,13 +72,13 @@
     });
   }
 
-  function testExpectGetFailure(options, expectedErrorMessage) {
+  function testExpectGetFailure(options, expectedErrorMessage, domain) {
     _.extend(options, {
       ready: function() {
         testMessageNotExpected("kpi_data");
         testMessageNotExpected("start");
 
-        var retval = controller.get(HTTPS_TEST_DOMAIN, options);
+        var retval = controller.get(domain || HTTPS_TEST_DOMAIN, options);
 
         if (expectedErrorMessage) {
           equal(retval, expectedErrorMessage, "expected error: " + expectedErrorMessage);
@@ -87,6 +87,9 @@
           ok(retval, "error message returned");
         }
 
+        // If a parameter is not properly escaped, scriptRun will be true.
+        equal(typeof window.scriptRun, "undefined", "script was not run");
+
         testErrorVisible();
         start();
       }
@@ -94,6 +97,35 @@
     createController(options);
   }
 
+  function testRelativeURLNotAllowed(options, path) {
+    testExpectGetFailure(options, "relative urls not allowed: (" + path + ")");
+  }
+
+  function testMustBeAbsolutePath(options, path) {
+    testExpectGetFailure(options, "must be an absolute path: (" + path + ")");
+  }
+
+  function testExpectGetSuccess(options, expected, domain, done) {
+    createController({
+      ready: function() {
+        var startInfo;
+        mediator.subscribe("start", function(msg, info) {
+          startInfo = info;
+        });
+
+        var retval = controller.get(domain || HTTPS_TEST_DOMAIN, options);
+        testHelpers.testObjectValuesEqual(startInfo, expected);
+
+        equal(typeof retval, "undefined", "no error expected");
+        testErrorNotVisible();
+
+        done && done();
+
+        start();
+      }
+    });
+  }
+
 
   module("dialog/js/modules/dialog", {
     setup: function() {
@@ -237,174 +269,82 @@
 
 
   asyncTest("get with relative termsOfService & valid privacyPolicy - print error screen", function() {
-    createController({
-      ready: function() {
-        mediator.subscribe("start", function(msg, info) {
-          ok(false, "start should not have been called");
-        });
-
-        var retval = controller.get(HTTP_TEST_DOMAIN, {
-          termsOfService: "relative.html",
-          privacyPolicy: "/privacy.html"
-        });
-        equal(retval, "relative urls not allowed: (relative.html)", "expected error");
-        testErrorVisible();
-        start();
-      }
-    });
+    testRelativeURLNotAllowed({
+      termsOfService: "relative.html",
+      privacyPolicy: "/privacy.html"
+    }, "relative.html");
   });
 
   asyncTest("get with script containing termsOfService - print error screen", function() {
-    createController({
-      ready: function() {
-        mediator.subscribe("start", function(msg, info) {
-          ok(false, "start should not have been called");
-        });
-
-        var retval = controller.get(HTTP_TEST_DOMAIN, {
-          termsOfService: "relative.html<script>window.scriptRun=true;</script>",
-          privacyPolicy: "/privacy.html"
-        });
-
-        // If termsOfService is not properly escaped, scriptRun will be true.
-        equal(typeof window.scriptRun, "undefined", "script was not run");
-        equal(retval, "relative urls not allowed: (relative.html<script>window.scriptRun=true;</script>)", "expected error");
-        testErrorVisible();
-        start();
-      }
-    });
+    var URL = "relative.html<script>window.scriptRun=true;</script>";
+    testRelativeURLNotAllowed({
+      termsOfService: URL,
+      privacyPolicy: "/privacy.html"
+    }, URL);
   });
 
   asyncTest("get with valid termsOfService & relative privacyPolicy - print error screen", function() {
-    createController({
-      ready: function() {
-        mediator.subscribe("start", function(msg, info) {
-          ok(false, "start should not have been called");
-        });
-
-        var retval = controller.get(HTTP_TEST_DOMAIN, {
-          termsOfService: "/tos.html",
-          privacyPolicy: "relative.html"
-        });
-        equal(retval, "relative urls not allowed: (relative.html)", "expected error");
-        testErrorVisible();
-        start();
-      }
-    });
+    var URL = "relative.html";
+    testRelativeURLNotAllowed({
+      termsOfService: "/tos.html",
+      privacyPolicy: URL
+    }, URL);
   });
 
-  asyncTest("get with script containing privacyPolicy - print error screen", function() {
-    createController({
-      ready: function() {
-        mediator.subscribe("start", function(msg, info) {
-          ok(false, "start should not have been called");
-        });
-
-        var retval = controller.get(HTTP_TEST_DOMAIN, {
-          termsOfService: "/tos.html",
-          privacyPolicy: "relative.html<script>window.scriptRun=true;</script>"
-        });
-
-        // If privacyPolicy is not properly escaped, scriptRun will be true.
-        equal(typeof window.scriptRun, "undefined", "script was not run");
-        equal(retval, "relative urls not allowed: (relative.html<script>window.scriptRun=true;</script>)", "expected error");
-        testErrorVisible();
-        start();
-      }
-    });
+  asyncTest("get with valid termsOfService & privacyPolicy='/' - print error screen", function() {
+    var URL = "/";
+    testRelativeURLNotAllowed({
+      termsOfService: "/tos.html",
+      privacyPolicy: URL
+    }, URL);
   });
 
-  asyncTest("get with privacyPolicy - print error screen", function() {
-    createController({
-      ready: function() {
-        mediator.subscribe("start", function(msg, info) {
-          ok(false, "start should not have been called");
-        });
-
-        var retval = controller.get(HTTP_TEST_DOMAIN, {
-          termsOfService: "/tos.html",
-          privacyPolicy: "relative.html<script>window.scriptRun=true;</script>"
-        });
+  asyncTest("get with valid termsOfService='/' and valid privacyPolicy - print error screen", function() {
+    var URL = "/"
+    testRelativeURLNotAllowed({
+      termsOfService: URL,
+      privacyPolicy: "/privacy.html"
+    }, URL);
+  });
 
-        // If privacyPolicy is not properly escaped, scriptRun will be true.
-        equal(typeof window.scriptRun, "undefined", "script was not run");
-        equal(retval, "relative urls not allowed: (relative.html<script>window.scriptRun=true;</script>)", "expected error");
-        testErrorVisible();
-        start();
-      }
-    });
+  asyncTest("get with script containing privacyPolicy - print error screen", function() {
+    var URL = "relative.html<script>window.scriptRun=true;</script>";
+    testRelativeURLNotAllowed({
+      termsOfService: "/tos.html",
+      privacyPolicy: URL
+    }, URL);
   });
 
   asyncTest("get with javascript protocol for privacyPolicy - print error screen", function() {
-    createController({
-      ready: function() {
-        mediator.subscribe("start", function(msg, info) {
-          ok(false, "start should not have been called");
-        });
-
-        var retval = controller.get(HTTP_TEST_DOMAIN, {
-          termsOfService: "/tos.html",
-          privacyPolicy: "javascript:alert(1)"
-        });
-
-        equal(retval, "relative urls not allowed: (javascript:alert(1))", "expected error");
-        testErrorVisible();
-        start();
-      }
-    });
+    var URL = "javascript:alert(1)";
+    testRelativeURLNotAllowed({
+      termsOfService: "/tos.html",
+      privacyPolicy: URL
+    }, URL);
   });
 
   asyncTest("get with invalid httpg protocol for privacyPolicy - print error screen", function() {
-    createController({
-      ready: function() {
-        mediator.subscribe("start", function(msg, info) {
-          ok(false, "start should not have been called");
-        });
-
-        var retval = controller.get(HTTP_TEST_DOMAIN, {
-          termsOfService: "/tos.html",
-          privacyPolicy: "httpg://testdomain.com/privacy.html"
-        });
-
-        equal(retval, "relative urls not allowed: (httpg://testdomain.com/privacy.html)", "expected error");
-        testErrorVisible();
-        start();
-      }
-    });
+    var URL = "httpg://testdomain.com/privacy.html";
+    testRelativeURLNotAllowed({
+      termsOfService: "/tos.html",
+      privacyPolicy: URL
+    }, URL);
   });
 
 
-  function testValidTermsOfServicePrivacyPolicy(options, expected) {
-    createController({
-      ready: function() {
-        var startInfo;
-        mediator.subscribe("start", function(msg, info) {
-          startInfo = info;
-        });
-
-        var retval = controller.get(HTTP_TEST_DOMAIN, options);
-        testHelpers.testObjectValuesEqual(startInfo, expected);
-
-        equal(typeof retval, "undefined", "no error expected");
-        testErrorNotVisible();
-        start();
-      }
-    });
-  }
-
   asyncTest("get with valid absolute termsOfService & privacyPolicy - go to start", function() {
-    testValidTermsOfServicePrivacyPolicy({
+    testExpectGetSuccess({
       termsOfService: "/tos.html",
       privacyPolicy: "/privacy.html"
     },
     {
-      termsOfService: HTTP_TEST_DOMAIN + "/tos.html",
-      privacyPolicy: HTTP_TEST_DOMAIN + "/privacy.html"
+      termsOfService: HTTPS_TEST_DOMAIN + "/tos.html",
+      privacyPolicy: HTTPS_TEST_DOMAIN + "/privacy.html"
     });
   });
 
   asyncTest("get with valid fully qualified http termsOfService & privacyPolicy - go to start", function() {
-    testValidTermsOfServicePrivacyPolicy({
+    testExpectGetSuccess({
       termsOfService: HTTP_TEST_DOMAIN + "/tos.html",
       privacyPolicy: HTTP_TEST_DOMAIN + "/privacy.html"
     },
@@ -416,7 +356,7 @@
 
 
   asyncTest("get with valid fully qualified https termsOfService & privacyPolicy - go to start", function() {
-    testValidTermsOfServicePrivacyPolicy({
+    testExpectGetSuccess({
       termsOfService: HTTPS_TEST_DOMAIN + "/tos.html",
       privacyPolicy: HTTPS_TEST_DOMAIN + "/privacy.html"
     },
@@ -427,166 +367,58 @@
   });
 
   asyncTest("get with valid termsOfService, tosURL & privacyPolicy, privacyURL - use termsOfService and privacyPolicy", function() {
-    testValidTermsOfServicePrivacyPolicy({
+    testExpectGetSuccess({
       termsOfService: "/tos.html",
       tosURL: "/tos_deprecated.html",
       privacyPolicy: "/privacy.html",
       privacyURL: "/privacy_deprecated.html"
     },
     {
-      termsOfService: HTTP_TEST_DOMAIN + "/tos.html",
-      privacyPolicy: HTTP_TEST_DOMAIN + "/privacy.html"
+      termsOfService: HTTPS_TEST_DOMAIN + "/tos.html",
+      privacyPolicy: HTTPS_TEST_DOMAIN + "/privacy.html"
     });
   });
 
   asyncTest("get with relative siteLogo - not allowed", function() {
-    createController({
-      ready: function() {
-        mediator.subscribe("start", function(msg, info) {
-          ok(false, "start should not have been called");
-        });
-
-        var retval = controller.get(HTTP_TEST_DOMAIN, {
-          siteLogo: "logo.png",
-        });
-
-        equal(retval, "must be an absolute path: (logo.png)", "expected error");
-        testErrorVisible();
-        start();
-      }
-    });
+    var URL = "logo.png";
+    testMustBeAbsolutePath({ siteLogo: URL }, URL);
   });
 
   asyncTest("get with javascript: siteLogo - not allowed", function() {
-    createController({
-      ready: function() {
-        mediator.subscribe("start", function(msg, info) {
-          ok(false, "start should not have been called");
-        });
-
-        var retval = controller.get(HTTP_TEST_DOMAIN, {
-          siteLogo: "javascript:alert('xss')",
-        });
-
-        equal(retval, "must be an absolute path: (javascript:alert('xss'))", "expected error");
-        testErrorVisible();
-        start();
-      }
-    });
+    var URL = "javascript:alert('xss')";
+    testMustBeAbsolutePath({ siteLogo: URL }, URL);
   });
 
   asyncTest("get with data-uri: siteLogo - not allowed", function() {
-    createController({
-      ready: function() {
-        mediator.subscribe("start", function(msg, info) {
-          ok(false, "start should not have been called");
-        });
-
-        var retval = controller.get(HTTP_TEST_DOMAIN, {
-          siteLogo: "data:image/png,FAKEDATA",
-        });
-
-        equal(retval, "must be an absolute path: (data:image/png,FAKEDATA)", "expected error");
-        testErrorVisible();
-        start();
-      }
-    });
+    var URL = "data:image/png,FAKEDATA";
+    testMustBeAbsolutePath({ siteLogo: URL }, URL);
   });
 
   asyncTest("get with http: siteLogo - not allowed", function() {
-    createController({
-      ready: function() {
-        mediator.subscribe("start", function(msg, info) {
-          ok(false, "start should not have been called");
-        });
-
-        var retval = controller.get(HTTP_TEST_DOMAIN, {
-          siteLogo: HTTP_TEST_DOMAIN + "://logo.png",
-        });
-
-        equal(retval, "must be an absolute path: (" + HTTP_TEST_DOMAIN + "://logo.png)", "expected error");
-        testErrorVisible();
-        start();
-      }
-    });
+    var URL = HTTP_TEST_DOMAIN + "://logo.png";
+    testMustBeAbsolutePath({ siteLogo: URL }, URL);
   });
 
   asyncTest("get with https: siteLogo - not allowed", function() {
-    createController({
-      ready: function() {
-        mediator.subscribe("start", function(msg, info) {
-          ok(false, "start should not have been called");
-        });
-
-        var retval = controller.get(HTTP_TEST_DOMAIN, {
-          siteLogo: HTTPS_TEST_DOMAIN + "://logo.png",
-        });
-
-        equal(retval, "must be an absolute path: (" + HTTPS_TEST_DOMAIN + "://logo.png)", "expected error");
-        testErrorVisible();
-        start();
-      }
-    });
+    var URL = HTTPS_TEST_DOMAIN + "://logo.png";
+    testMustBeAbsolutePath({ siteLogo: URL }, URL);
   });
 
   asyncTest("get with absolute path and http RP - not allowed", function() {
-    createController({
-      ready: function() {
-        mediator.subscribe("start", function(msg, info) {
-          ok(false, "start should not have been called");
-        });
-
-        var siteLogo = '/i/card.png';
-        var retval = controller.get(HTTP_TEST_DOMAIN, {
-          siteLogo: siteLogo
-        });
-
-        equal(retval, "only https sites can specify a siteLogo", "expected error");
-        testErrorVisible();
-        start();
-      }
-    });
+    var siteLogo = '/i/card.png';
+    testExpectGetFailure({ siteLogo: siteLogo }, "only https sites can specify a siteLogo", HTTP_TEST_DOMAIN);
   });
 
   asyncTest("get with absolute path that is too long - not allowed", function() {
-    createController({
-      ready: function() {
-        mediator.subscribe("start", function(msg, info) {
-          ok(false, "start should not have been called");
-        });
-
-        // create a logo path that is one character too long
-        var siteLogo = '/' + testHelpers.generateString(bid.PATH_MAX_LENGTH);
-        var retval = controller.get(HTTPS_TEST_DOMAIN, {
-          siteLogo: siteLogo
-        });
-
-        equal(retval, "path portion of a url must be < " + bid.PATH_MAX_LENGTH + " characters");
-        testErrorVisible();
-        start();
-      }
-    });
+    var siteLogo = '/' + testHelpers.generateString(bid.PATH_MAX_LENGTH);
+    testExpectGetFailure({ siteLogo: siteLogo }, "path portion of a url must be < " + bid.PATH_MAX_LENGTH + " characters");
   });
 
   asyncTest("get with absolute path causing too long of a URL - not allowed", function() {
-    createController({
-      ready: function() {
-        mediator.subscribe("start", function(msg, info) {
-          ok(false, "start should not have been called");
-        });
-
-        var shortHTTPSDomain = "https://test.com";
-        // create a URL that is one character too long
-        var siteLogo = '/' + testHelpers.generateString(bid.URL_MAX_LENGTH - shortHTTPSDomain.length);
-        var retval = controller.get(shortHTTPSDomain, {
-          siteLogo: siteLogo
-        });
-
-        equal(retval, "urls must be < " + bid.URL_MAX_LENGTH + " characters");
-        testErrorVisible();
-        start();
-      }
-    });
+    var shortHTTPSDomain = "https://test.com";
+    // create a URL that is one character too long
+    var siteLogo = '/' + testHelpers.generateString(bid.URL_MAX_LENGTH - shortHTTPSDomain.length);
+    testExpectGetFailure({ siteLogo: siteLogo }, "urls must be < " + bid.URL_MAX_LENGTH + " characters");
   });
 
   asyncTest("get with absolute path and https RP - allowed URL but is properly escaped", function() {
@@ -613,73 +445,35 @@
   });
 
   asyncTest("get with a scheme-relative siteLogo URL - not allowed", function() {
-    createController({
-      ready: function() {
-        mediator.subscribe("start", function(msg, info) {
-          ok(false, "start should not have been called");
-        });
-
-        var retval = controller.get(HTTPS_TEST_DOMAIN, {
-          siteLogo: "//example.com/image.png"
-        });
-
-        equal(retval, "must be an absolute path: (//example.com/image.png)", "expected error");
-        testErrorVisible();
-        start();
-      }
-    });
+    var URL = "//example.com/image.png";
+    testMustBeAbsolutePath({ siteLogo: URL }, URL);
   });
 
-  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, {
-          returnTo: URL
-        });
+  asyncTest("get with siteLogo='/' URL - not allowed", function() {
+    testMustBeAbsolutePath({ siteLogo: "/" }, "/");
+  });
 
-        equal(retval, "must be an absolute path: (" + URL + ")", "expected error");
-        testErrorVisible();
-        start();
-      }
-    });
+  asyncTest("get with fully qualified returnTo - not allowed", function() {
+    var URL = HTTPS_TEST_DOMAIN + "/path";
+    testMustBeAbsolutePath({ returnTo: URL }, URL);
   });
 
   asyncTest("get with a scheme-relative returnTo URL - not allowed", function() {
-    createController({
-      ready: function() {
-        mediator.subscribe("start", function(msg, info) {
-          ok(false, "unexpected start");
-        });
-
-        var retval = controller.get(HTTP_TEST_DOMAIN, {
-          returnTo: '//example.com/return'
-        });
-
-        equal(retval, "must be an absolute path: (//example.com/return)", "expected error");
-        testErrorVisible();
-        start();
-      }
-    });
+    var URL = '//example.com/return';
+    testMustBeAbsolutePath({ returnTo: URL }, URL);
   });
 
   asyncTest("get with absolute path returnTo - allowed", function() {
-    createController({
-      ready: function() {
-        mediator.subscribe("start", function(msg, info) {
-          equal(user.getReturnTo(), HTTPS_TEST_DOMAIN + "/path", "returnTo correctly set");
-          start();
-        });
+    testExpectGetSuccess({ returnTo: "/path"}, {}, undefined, function() {
+      equal(user.getReturnTo(),
+        HTTPS_TEST_DOMAIN + "/path", "returnTo correctly set");
+    });
+  });
 
-        var retval = controller.get(HTTPS_TEST_DOMAIN, {
-          returnTo: "/path"
-        });
-      }
+  asyncTest("get with returnTo='/' - allowed", function() {
+    testExpectGetSuccess({ returnTo: "/"}, {}, undefined, function() {
+      equal(user.getReturnTo(),
+        HTTPS_TEST_DOMAIN + "/", "returnTo correctly set");
     });
   });