Hi everyone,
Project Summary
Publish: 19 June 2026
Discuss: 17 July 2026
Resolve: 30 July 2026
We’re proposing a reduction of the fields included in the signed invocation context sent to Forge Remotes and Forge Containers. This is to address the issue where large context causes requests to fail before reaching the remote or container.
Problem
Today, when a Forge frontend calls invokeRemote or requestRemote, Forge sends a Forge Invocation Token (FIT) to the remote backend in the Authorization header, which includes a signed context claim. For some modules, this context can become large enough to exceed individual or combined header limit sizes in common infrastructure, causing requests to fail before they reach the app’s remote backend.
Forge Containers use the same underlying invocation model, therefore a large header carrying the context will stop requests reaching the container. A Forge frontend calls a containerised service with invokeService and the context is exposed through the /invocation/context Containers API.
Proposed Solution
To address this, we’re proposing an opt-in manifest setting (context: trusted-only) that limits the fields in the signed invocation context sent to remotes and containers. Existing apps would not change by default.
When enabled, Forge Remote and Forge Containers would receive only trusted context in the signed invocation context.
Additional context would remain available to the app frontend through existing APIs, such as view.getContext() in Custom UI and useProductContext() in UI Kit. If your remote backend or container service needs any of that additional context, your frontend can send it explicitly in the request body.
Trusted and untrusted context
This proposal introduces a clearer distinction between two kinds of context:
-
Trusted context: product-specific context that Atlassian has permission-checked and signed into the invocation context.
-
Untrusted frontend context: additional context available to the app frontend, which can be sent to a remote backend or container service if needed, but must be treated as app-provided input and not relied on for security or authorisation decisions.
To clarify, only trusted context will now be available in the FIT context claim for Forge Remotes and through the /invocation/context API for Forge Containers. All remaining app context will be available in the frontend context.
What changes for app developers?
If your app does not opt in, there is no behaviour change.
If your app opts in with:
app:
id: ari:cloud:ecosystem::app/example-app-id
endpoint:
context: trusted-only // new opt-in property
some fields that were previously available in the context may no longer be present, but they will be available on the frontend context.
If your remote backend or container service needs those fields, your frontend should:
-
Read the required values from frontend context.
-
Send these values in the request body of the
invokeRemote,requestRemote, orinvokeServicecall. -
Treat them as untrusted on the backend.
-
Validate them before use.
Example: sending frontent context
import { invokeRemote, view } from '@forge/bridge';
// import { invokeService, view } from '@forge/bridge';
export async function callRemote() {
const context = await view.getContext();
// same approach for invokeService()
return await invokeRemote({
path: '/my-remote-endpoint',
method: 'POST',
body: {
frontendContext: {
localId: context.localId,
extension: {
// Include only the fields your remote actually needs.
macroParameters: context.extension?.macroParameters,
gadgetConfiguration: context.extension?.gadgetConfiguration,
},
},
}
});
}
Example: reading trusted and untrusted context in a Forge Remote
app.post('/my-remote-endpoint', async (req, res) => {
const fitPayload = await verifyForgeInvocationToken(
req.header('authorization')
);
// Trusted: signed by Atlassian in the FIT.
const trustedContext = fitPayload.context;
// Untrusted: supplied by the app frontend.
const frontendContext = req.body.frontendContext as {
localId?: string;
extension?: Record<string, unknown>;
};
if (
frontendContext.localId !== undefined &&
typeof frontendContext.localId !== 'string'
) {
return res.status(400).json({ error: 'Invalid localId' });
}
// Do not use frontendContext as proof of authorization.
// Validate or independently verify frontend-provided values before use.
res.json({
ok: true,
cloudId: trustedContext?.cloudId,
localId: frontendContext.localId,
});
});
Example: reading trusted and untrusted context in a Forge Container
async function getInvocationContext() {
// Use the local Containers runtime API base URL documented for your container environment.
const response = await fetch(
`${CONTAINERS_RUNTIME_API_BASE_URL}/invocation/context`
);
if (!response.ok) {
throw new Error('Failed to read Forge Containers invocation context');
}
return response.json();
}
app.post('/my-container-endpoint', async (req, res) => {
const invocationContext = await getInvocationContext();
// Trusted: exposed by the Forge Containers runtime API after platform validation.
const trustedContext = invocationContext.context;
// Untrusted: supplied by the app frontend.
const frontendContext = req.body.frontendContext as {
localId?: string;
extension?: Record<string, unknown>;
};
if (
frontendContext.localId !== undefined &&
typeof frontendContext.localId !== 'string'
) {
return res.status(400).json({ error: 'Invalid localId' });
}
// Do not use frontendContext as proof of authorization.
// Validate or independently verify frontend-provided values before use.
res.json({
ok: true,
cloudId: trustedContext?.cloudId,
localId: frontendContext.localId,
});
});
Proposed rollout
| Date | Milestone |
|---|---|
| 19 June 2026 | Publish this RFC for community feedback. |
| 17 July 2026 | Close RFC feedback period. |
| 31 July 2026 | Resolve RFC with a final decision. |
| 1 October 2026 | Publish developer documentation about the opt-in process and which module fields will be included in the trusted context vs untrusted frontend context. |
| 1 April 2027 | Deprecate the original context payload. |
Note that there are currently no plans to remove the original context payload but the expectation is that new apps should use the new, reduced, trusted context.
What we’d like feedback on
We’d especially like feedback from developers using Forge Remote or Forge Containers.
-
Does the proposed opt-in manifest property work for your app?
-
Which fields do your remote endpoints currently read from the FIT
contextclaim, or your container services read from the Containers/invocation/contextAPI and to whichmodulesdo they relate? -
Would sending non-sensitive frontend context explicitly in the request body of
invokeRemote,requestRemote, orinvokeServicecalls work for your app? -
Are the proposed rollout dates workable?
To reiterate, this proposal is intended to reduce failed remote and container invocations caused by oversized headers while making the trust boundary around invocation context clearer.
Please share feedback by 17 July 2026.