diff --git a/morph/grid.config.json b/morph/grid.config.json
index c6ee26422d3af52d7618ffc84add6fc825e3f4d4..db199357552ccd27b4a83f3cda8383163020806c 100644
--- a/morph/grid.config.json
+++ b/morph/grid.config.json
@@ -3,4 +3,9 @@
 , "stripeSecretKeyPath": "../../PrivateStorageSecrets/stripe.secret"
 , "issuerDomain": "payments.privatestorage.io"
 , "letsEncryptAdminEmail": "jean-paul@privatestorage.io"
+, "allowedChargeOrigins": [
+    "http://localhost:5000"
+  , "https://privatestorage-staging.com"
+  , "https://www.privatestorage-staging.com"
+  ]
 }
diff --git a/morph/issuer.nix b/morph/issuer.nix
index fe448699c7ad87a74a63e823f428d9d46462f3de..a37bba5c26cf698cae78b647bd36d5be1c3d4fe8 100644
--- a/morph/issuer.nix
+++ b/morph/issuer.nix
@@ -3,6 +3,7 @@
 , stripeSecretKeyPath
 , issuerDomain
 , letsEncryptAdminEmail
+, allowedChargeOrigins
 , stateVersion
 , ...
 }: {
@@ -32,6 +33,7 @@
     databasePath = "/var/db/vouchers.sqlite3";
     inherit letsEncryptAdminEmail;
     domain = issuerDomain;
+    inherit allowedChargeOrigins;
   };
 
   system.stateVersion = stateVersion;
diff --git a/morph/testing-grid.config.json b/morph/testing-grid.config.json
index 46cf4ff25c5eb0c6dffdba01f774c7862e300aa3..16d9380282ddfb1c1a2e0e7184cb9ec1af82bb7b 100644
--- a/morph/testing-grid.config.json
+++ b/morph/testing-grid.config.json
@@ -3,4 +3,8 @@
 , "stripeSecretKeyPath": "../../PrivateStorageSecrets/stripe.secret"
 , "issuerDomain": "payments.privatestorage-staging.com"
 , "letsEncryptAdminEmail": "jean-paul@privatestorage.io"
+, "allowedChargeOrigins": [
+    "https://privatestorage.io"
+  , "https://www.privatestorage.io"
+  ]
 }
diff --git a/nixos/modules/issuer.nix b/nixos/modules/issuer.nix
index dbe751320e45fea3af885638ef438d9f6bf05dad..fdf63d644e61549c8d5791b6584cd3ac32aa6687 100644
--- a/nixos/modules/issuer.nix
+++ b/nixos/modules/issuer.nix
@@ -78,6 +78,14 @@ in {
         for the service's TLS certificate.
       '';
     };
+    services.private-storage-issuer.allowedChargeOrigins = lib.mkOption {
+      type = lib.types.listOf lib.types.str;
+      description = ''
+        The CORS "Origin" values which are allowed to submit charges to the
+        payment server.  Note this is not currently enforced by the
+        PaymentServer.  It just controls the CORS headers served.
+      '';
+    };
   };
 
   config =
@@ -131,9 +139,14 @@ in {
             else
               # Only for automated testing.
               "--http-port 80";
-          stripeArgs = "--stripe-key ${builtins.readFile cfg.stripeSecretKeyPath}";
+
+          prefixOption = s: "--allow-origin=" + s;
+          originStrings = map prefixOption cfg.allowedChargeOrigins;
+          originArgs = builtins.concatStringsSep " " originStrings;
+
+          stripeArgs = "--stripe-key-path ${cfg.stripeSecretKeyPath}";
         in
-          "${cfg.package}/bin/PaymentServer-exe ${issuerArgs} ${databaseArgs} ${httpsArgs} ${stripeArgs}";
+          "${cfg.package}/bin/PaymentServer-exe ${originArgs} ${issuerArgs} ${databaseArgs} ${httpsArgs} ${stripeArgs}";
     };
 
     # Certificate renewal.  We must declare that we *require* it in our