Suppose two customers use your reporting app. Both have a report numbered 42. The database keeps their records separate, but the remote backend caches a generated report under the key report:42.
The database design is fine. The cache has lost the customer boundary.
This is the sort of detail worth looking for when a Forge app starts using a remote backend. Reviewing only the incoming HTTP handler leaves a lot of the data path unchecked.
Begin at the incoming request
The backend needs to establish that a request came from Forge and is intended for your app. Atlassian requires verification of the Forge Invocation Token (FIT), including its signature and expected audience, using the appropriate signing keys. The expected app ID must come from trusted configuration. Forge Remote essentials describes that contract.
Decoding a JWT only makes its claims readable. It doesn’t verify them. Don’t use an unverified claim or a tenantId field in the request body to decide which customer’s records to open.
Use a maintained verification library and check the current guidance for the environment you’re deploying into. Keep access tokens out of logs, including error logs. A debugging statement that prints an entire request can undo otherwise careful credential handling.
Follow the customer identifier into storage
Once the request has been verified, follow the trusted installation context through every place data is stored or retrieved. For the report example, review the database lookup, cache key, export filename, download permission, and background job payload.
A useful review exercise is to put the two customer requests side by side. At each step, identify what prevents customer A’s request from selecting customer B’s report. If the answer depends on a convention that isn’t enforced in code, investigate it.
Atlassian recommends associating remotely stored data with installationId. Its documentation also explains that this identifier changes on reinstallation. Decide how your service handles that transition. An assertion from a newly installed client should not be enough to reconnect old customer data.
Include the paths people forget to draw
Architecture diagrams often show the normal request and response, then stop. Add the other paths before the review:
- A queued export that runs after the user has left the page.
- A retry after the backend timed out.
- A support tool used to inspect a failed job.
- A cached download that remains available after permissions change.
These are not necessarily vulnerabilities. They are places where the identity, timing, or permission decision may differ from the interactive request. Make that difference explicit.
Check the payload as well as the destination
The Forge permissions manifest declares scopes and access to external resources. Keep those declarations narrow and consistent with the application’s needs.
Then inspect what the app actually sends. A service that summarises one selected paragraph may not need the entire issue history. Check ordinary requests, retries, and failure logs; the latter two can contain more data than the successful path.
Agree where that data is retained and how it is deleted. This is easier to answer while designing the integration than after several services have each kept their own copy.
A small release check
In an authorised test environment, use synthetic records for two installations. Try a missing token, an invalid token, an unexpected app identity, and a request for the other installation’s report. Confirm that the request is rejected before data is returned or changed.
Repeat a completed export request and inspect the result. Depending on the workflow, it may return an existing export or create another one; either way, the behaviour should be deliberate and remain within the correct customer boundary.
Keep these checks alongside the functional integration tests. A successful report download proves the feature works. These cases establish who can obtain it.
References
Reviewed 10 November 2026. The reporting service is a worked example.
Have a question about your application?
Talk to Actiotech →