RFCs are a way for Atlassian to share what we’re working on with our valued developer community.
It’s a document for building shared understanding of a topic. It expresses a technical solution, but can also communicate how it should be built or even document standards. The most important aspect of an RFC is that a written specification facilitates feedback and drives consensus. It is not a tool for approving or committing to ideas, but more so a collaborative practice to shape an idea and to find serious flaws early.
Please respect our community guidelines: keep it welcoming and safe by commenting on the idea not the people (especially the author); keep it tidy by keeping on topic; empower the community by keeping comments constructive. Thanks!
Project Summary
Forge currently supports the ability to define egress and remotes for loading data/resources or interacting with remote services, however utilisation requires pre-declaration within the Forge manifest (or generic wildcarded access), or prior knowledge of the location of the remote service. This project seeks to explore alternatives which enable apps to define egress and remotes through admin configuration, improving customer trust and flexibility when utilising Forge apps.
- Publish: May 27, 2025
- Discuss: Jun 10, 2025
- Resolve: Jun 24, 2025
Problem
Forge Egress
When interacting with or loading remote services from Forge, apps must proactively declare egress permissions (fetch, fonts, styles, scripts, images, etc.) within their Forge manifest. Where these are of a fixed type of domain, apps can declare more refined egress permissions (i.e. *.domain.com). Where apps provide broader flexibility for customers (i.e. an app which can load images from any location), an app must declare a more generic wildcard (*).
As these are pre-registered, customers do not have any control over which locations an app could subsequent interact with. As a result of this, they must make a decision to trust apps with generic wildcards during the installation process, rather than being able to manage app permissions throughout the app lifecycle.
Forge Remotes
Unlike egress, remotes do not support wildcarding. A known fixed URL must be known to communicate with and proactively declared within the Forge manifest.
Where an app may seek to build an integration into a remote customer service which has variable domains (for example, a customer hosting Splunk in a self-hosted configuration), they are unable to integrate directly as the FQDN is not known and wildcards are not supported.
Proposed Solution
Apps will be able to dynamically declare and manage their egress and remotes post-installation. This would enable:
- Apps which have a subset of features which require a remote/egress to gate this functionality, turning it on if/when a customer enables the required remotes.
- Apps which do not know where a customer may need to load data from can provide an experience in which customers declare a permitted list of domains.
- Apps which interact with external services which can be hosted on variable URLs can securely provide remote integrations.
Forge Egress
Configurable egress enables apps to add, remove and retrieve a list of urls which are applied to all external property types (frames, images, scripts, fonts, fetch, etc.)
To enable the ability to declare and interact with configurable egress, an app must for declare its support for this within its Forge manifest via a permissions.external.configurable
property.
permissions:
scopes:
- read:project:jira
- read:jira-work
- read:jira-user
- manage:jira-configuration
- write:jira-work
external:
configurable: true
frames:
- 'assets.mysite.com'
scripts:
- 'cdn.mysite.com'
fetch:
backend:
- '*.mysite.com'
client:
- '*.mysite.com'
Apps can attach or remove egress domains via UI functions when an admin is present. The app would have access to retrieve set domains when any user is present. When egress is added, the administrator will be prompted to confirm the request (see Customer Experience below).
import { permissions } from '@forge/bridge';
const domains = ['*.atlassian.com', '*.jira.com'];
function setPermittedImages (domains) {
const configurableEgressDomainResult = await permissions.egress.requestDomains(domains);
if (configurableEgressDomainResult) {
//customer confirmed egress addition
} else {
//customer declined egress addition
}
}
function DynamicDomainsDisplay() {
const domains = permissions.egress.domainsDomains();
return domains.map(domain => { ... });
}
Forge Remotes
Configurable remotes enable apps to pre-declare and dynamically register new remotes as required, providing context to support user declaration of where that remote should communicate. An optional domainPattern
could also be declared to limit declarations to specific domain or url shapes where required.
remotes:
- key: github1
userConfiguration:
name: 'Github'
description: 'Enter your Github site to link to Jira'
default: api.github.com
supportedPatterns:
- *.github.com
Apps will be able to set or update remotes via UI functions when an admin is present. The app would have access to retrieve set remotes when any user is present. When a remote is set or changes, the administrator will be prompted to confirm the request (see Customer Experience below).
import { permissions } from '@forge/bridge';
const setRemote = async () => {
const status = await permissions.remote.setRemote('github1', 'https://mysite.github.com');
if (status) {
//customer confirmed remote
} else {
//customer declined remote
}
}
//Retrieve Remote
const remoteDomain = await permissions.remote.getRemote('github1');
console.log(remoteDomain)
Where an app may interact with multiple remote services, where they are unaware of how many the customer needs to configure, the can dynamically register a configurable remote.
mutation RegisterDynamicModule($input: RegisterModuleInput!) {
registerModule(input: $input) {
success
errors {
message
code
}
}
}
{
"input": {
"key": "github2",
"type": "remote",
"userDefined": {
"name": "Second Github",
"description": "Another one",
"domainPatterns": "*.github.com"
}
}
}
Customer Experience
When an app requests either dynamicRemotes().setRemote()
or dynamicEgress().addDomain
(or similar), an Atlassian-owned modal would be displayed to the present administrator to approve egress to the domain/s. If an admin is not present, then the modal would not be displayed and the request would fail.
Depending upon the context in which the update has occurred, the app may need to invoke router.reload()
to reload the page with new CSPs. We will leave this behaviour up to the discretion of the app.
Beyond the app-defined experiences, administrators will also be able to view and manage defined configurable egress and remotes within Connected Apps.
Marketplace signals and program eligibility
Configurable egress / remotes enable partners to deliver more flexible apps which increase customer trust by enabling them to better understand and control how their data is managed. With that said, the ability to share data remotely would preclude these apps from being eligible for Runs on Atlassian in the program’s current definition and state.
This RFC will not explore the impacts of the utilisation of this capability on RoA or other marketplace signals at this time.
Asks
While we would appreciate any reactions you have to this RFC (even if it’s simply giving it a supportive “Agree, no serious flaws”), we’re especially interested in learning more about:
- Whether this unlocks new use cases for you on Forge which were previously inaccessible?
- Does this implementation make sense for your app/s?
- The implementation proposed to configurable egress applies to all egress types. Is this acceptable, or would you prefer a more granular approach?
- Can you foresee any significant constraints of this implementation? Are there things which you would not be able to achieve which should be unlocked through this?
- Is there anything you believe we are missing, or which should be reconsidered in the above proposal?