diff --git a/server/service_test.go b/server/service_test.go
index c7471f2bf83fea27907685a5a656e90b53b93970..6829ff49f249bc0f9d115214cda40660ceafedec 100644
--- a/server/service_test.go
+++ b/server/service_test.go
@@ -38,6 +38,10 @@ public_key_file: %s
 domain: example.com
 allowed_services:
   - "^service\\.example\\.com/$"
+  - "^service2\\.example\\.com/$"
+allowed_exchanges:
+  - src_regexp: "^service\\.example\\.com/$"
+    dst_regexp: "\\.example\\.com/.*$"
 allowed_cors_origins:
   - "https://origin.example.com"
 service_ttls:
@@ -120,3 +124,36 @@ func TestLoginService_SanityChecks(t *testing.T) {
 		}
 	}
 }
+
+func TestLoginService_Exchange(t *testing.T) {
+	tmpdir, _ := ioutil.TempDir("", "")
+	defer os.RemoveAll(tmpdir)
+
+	config := testConfig(t, tmpdir, "")
+	svc, err := NewLoginService(config)
+	if err != nil {
+		t.Fatal("NewLoginService():", err)
+	}
+
+	var testdata = []struct {
+		service, destination string
+		ok                   bool
+	}{
+		{"service.example.com/", "service2.example.com/", true},
+		{"service.example.com/", "bad-service.another.com/", false},
+		{"service.example.com/", "service.example.com/", true}, // self-exchange??
+	}
+
+	for _, td := range testdata {
+		tkt, err := svc.Authorize("user", td.service, "https://"+td.service, "nonce", nil)
+		if err != nil {
+			t.Errorf("%s: Authorize() error", td.service)
+			continue
+		}
+
+		_, err = svc.Exchange(tkt, td.service, "nonce", td.destination, "nonce")
+		if (err == nil) != td.ok {
+			t.Errorf("Exchange error: s=%s d=%s expected=%v got=%v", td.service, td.destination, td.ok, err)
+		}
+	}
+}