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.
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.
{
"permissions": {
"network": {
"whitelist": {
"required": ["https://api.example.com"]
}
}
}
}
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.
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
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-Methodsfor the methods you support - Return
Access-Control-Allow-Headersfor headers such asContent-TypeandAuthorization - Return a successful status for
OPTIONSwithout running the application handler
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.
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.
