A backend request from an installed Sage app passes through two independent gates. Sage’s network policy decides whether the frontend may connect, then your backend’s CORS policy decides whether the browser may expose the response. Configure and test both before adding wallet features.

01

Allow the backend in the manifest

Add every remote origin the installed frontend needs to permissions.network.whitelist. Use required when the app cannot work without that service. Use optional only when the app has a useful fallback if the user declines it.

Sage accepts https and wss origins. Declare the origin only—scheme, host, and optional port—with no path. You do not need a bridge capability just to call your own backend.

Add to sage-manifest.jsonjson
{
  "permissions": {
    "network": {
      "whitelist": {
        "required": ["https://api.example.com"]
      }
    }
  }
}
02

Calculate the installed app origin

Sage normalizes the installation URL by removing its query and fragment and ensuring the path ends with /. It calculates the SHA-256 hash of that complete normalized URL, takes the first 16 hexadecimal characters, and combines them with a slug of the hostname to produce an identity such as url-xch-place-4c641f547d3d7923.

Each installation adds a UUID to that stable identity. The app runs as sage-app://{uuid}.{identity} on macOS and Linux, and as https://sage-app.{uuid}.{identity} on Windows. Use the calculator below to generate one CORS regex that recognizes both forms for your app URL.

Use this regex in your backend’s CORS origin matcher. It does not belong in the Sage manifest—the manifest’s network whitelist contains the backend origin the frontend calls.

App identity calculatorOpen this page in a browser to use it
03

Choose the right CORS policy

The installed app does not run at your public website’s origin, so allowing only that website will not cover Sage. Match the generated cross-platform pattern alongside the ordinary production and development origins your backend already trusts.

For an API that does not use browser cookies or other credentialed requests, Access-Control-Allow-Origin: * is the simplest compatible response. It is not authentication: continue to protect private operations with tokens or signatures. If the API uses browser credentials, validate the incoming origin, echo only an allowed value, return Access-Control-Allow-Credentials: true, and add Vary: Origin.

  • Keep existing production and local-development web origins working
  • Treat CORS as a browser boundary, not authorization
  • Apply the same policy to success and error responses
04

Answer preflight before authentication

Requests with JSON, authorization headers, or non-simple methods usually trigger an OPTIONS preflight. Handle it before authentication middleware rejects the request. Return the allowed origin, methods, and every request header the frontend actually sends.

A successful preflight normally has no response body. Cache it only for a duration that lets you change the policy safely.

  • Return Access-Control-Allow-Methods for the methods you support
  • Return Access-Control-Allow-Headers for headers such as Content-Type and Authorization
  • Return a successful status for OPTIONS without running the application handler
05

Test both gates

Rebuild and update the Sage app after changing its manifest, then test the real installed app against the deployed backend. A connect-src console error points to the Sage network permission. A CORS or preflight error means the request reached the browser’s CORS boundary and the backend response needs attention.

Verify a normal response, an authenticated response, a backend error, and a preflight. Then repeat the ordinary web version to make sure Sage compatibility did not break existing users.

Builder's note

Bridge APIs and client behavior can evolve. Verify implementation details against the Sage version you support, then test in both Sage and a normal browser.