Customer-managed egress and remotes are currently available through Forge's Early Access Program (EAP). EAP capabilities are experimental, unsupported, and subject to change without notice, and are not recommended for production use.
For more details, see Forge EAP, Preview, and GA.
Customer-managed egress and remotes are a way of defining egress in your app. They let customers and admins control which external services your app can talk to, and when those connections are enabled.
In other implementations, Forge apps must declare all possible egress destinations up front, which limits customer choice and can introduce unnecessary security risks.
Customer-managed egress enables apps to declare and manage their egress and remotes per installation, instead of listing every destination in the manifest. This approach improves trust for customers by giving them more visibility and control over data flows, and provides more flexible integration options.
Consider using customer‑managed egress and remotes when:
Customer‑managed egress and remotes must not be used to request pre‑defined, required egress.
If your app always needs to talk to specific external domains that are fixed or pre‑set, you must declare those via static external permissions and remotes, rather than prompting admins to approve them immediately via customer‑managed egress.
If your app always talks to the same fixed set of external destinations, you can keep using static external permissions and remotes.
Instead of declaring every external destination up front in manifest.yml, your app can:
Forge apps that use customer‑managed egress or customer‑managed remotes are not eligible for Runs on Atlassian. For more information, see Limitations and compatibility.
permissions.external.* model.In practice, you will usually:
The customer-managed egress data model is based on the idea of an egress group. A group may have one or more egress entries defined. Grouping makes it easier for an admin to understand what a particular egress is related to.
An example egress group looks like:
1 2{ "key": "egress-group", "description": "Access to example.com", "configured": [ { "domain": "https://api.example.com", "type": ["FETCH_BACKEND_SIDE", "FETCH_CLIENT_SIDE"] }, { "domain": "https://media.example.com", "type": ["IMAGES", "MEDIA"] }, { "domain": "https://cdn.example.com", "type": ["FONTS", "SCRIPTS", "STYLES"] } ] }
Field details
| Field | Type | Description |
|---|---|---|
key | string | A key for the egress group that is defined by the Forge app. |
description | string | A user‑facing description for this egress group. |
configured[].domain | string | A URL or wildcard that will be used to fetch resources from. |
configured[].type | EgressType[] |
The type(s) of allowed egress. These map to the existing manifest egress types documented in Add content security and egress controls. There is an enum
|
The data model for a customer-managed remote looks like:
1 2{ "key": "external-api", "configured": { "endpoint": "https://api.external.com" } }
Field details
| Field | Type | Description |
|---|---|---|
key | string | Must correlate to a remote key defined in the manifest. |
endpoint | string (URL) | The absolute URL for the remote as defined by the admin of your app (inside configured). |
Updating the manifest is not part of EAP scope but will be released as part of Preview. When using this feature in EAP, skip this section and focus on interacting with the Forge Bridge APIs.
To use customer‑managed egress or remotes, enable the feature in your app manifest:
1 2permissions: external: configurable: enabled: true
If this property is not set to true, any calls to the customer-managed egress and remotes APIs will fail.
This property is required for egress and remotes, but a customer-managed remote requires one additional
property to be set.
Customer-managed remotes are defined in the manifest similarly to existing remotes, but add a configurable object describing how admins can configure the endpoint URL.
Basic example:
1 2remotes: - key: my-site-1 configurable: name: "My site" description: "This will be used to make connections to My Site" supportedPatterns: - "*.example.com"
Key points:
key is still required; remotes are always keyed values.baseUrl becomes optional when configurable is defined. If you omit baseUrl, the remote is purely customer‑configured.configurable object provides:
name: Used in the Atlassian Administration Connected Apps UI and in in‑app modals to explain what the remote is used for.description: Additional context about what the remote is used for.supportedPatterns: An array of patterns used to validate admin‑provided URLs. This accepts any string values, including a single * wildcard character. Validation for these will be performed in Admin Hub, but not in a Forge app. Validating this is the responsibility of the app.For example, to provide a default baseUrl while still allowing customers to override it:
1 2remotes: - key: my-site-1 baseUrl: "https://default.example.com" configurable: name: "My site" description: "This will be used to make connections to My Site" supportedPatterns: - "*.example.com"
Customer-managed remotes and data residency follow the same rules as other remotes. You can combine customer-managed remotes with region‑specific baseUrl values:
1 2remotes: - key: my-site-1 baseUrl: default: "https://example.com" US: "https://us.example.com" EU: "https://eu.example.com" configurable: name: "My site" description: "This will be used to make connections to My Site" supportedPatterns: - "*.example.com"
In Atlassian Administration, if an admin resets a remote to its default value:
baseUrl is set in the manifest, the remote becomes unset (endpoint becomes null).baseUrl is set in the manifest, the remote reverts to the manifest baseUrl (or the region‑specific baseUrl if applicable).See Data residency and Remotes manifest reference for full details.
Once the manifest is configured, your app can interact with customer‑managed egress and remotes at runtime using the Forge bridge.
All customer-managed egress and remotes APIs:
permissions module in @forge/bridge.permissions.external.configurable.enabled: true in the manifest.There are six async Forge bridge functions available in @forge/bridge:
permissions.egress.getpermissions.egress.setpermissions.egress.deleteDomainpermissions.egress.deleteGrouppermissions.remote.setpermissions.remote.getFor detailed arguments and TypeScript types, see Forge bridge APIs.
The following shows how you might call permissions.egress.set from a Custom UI component:
1 2import { permissions } from "@forge/bridge"; async function configureEgress() { await permissions.egress.set({ groups: [ { key: "example-egress", description: "Access to example.com", configured: [ { domain: "https://api.example.com", type: ["FETCH_BACKEND_SIDE"], }, ], }, ], }); }
When this is called by an admin, they will see a confirmation modal describing the egress that will be added. If they approve, the group is saved and the Promise resolves. If they reject, the Promise rejects.
Once the manifest of an app has been configured correctly, the app can interact with customer‑managed egress and remotes using six async Forge functions in the permissions module in @forge/bridge. All of these calls will fail if permissions.external.configurable.enabled is not set to true. These APIs are part of the Early Access Program and are not recommended for production use.
permissions.egress.getUse this to get previously configured egress for an installation. You can fetch specific groups or all groups.
Arguments
keys (optional): Array of group keys to fetch. If undefined, all configured egress groups are returned.pageSize (optional): Number of egress groups to return in a single page.nextPageToken (optional): Token to fetch the next page of values when using pagination.Type
1 2type EgressGetPayload = { keys?: string[]; pageSize?: number; nextPageToken?: string; };
permissions.egress.setUse this to set customer-managed egress for an installation. You can set one or multiple egress groups (up to the maximum allowed).
Arguments
groups: Array of egress groups to set. Each group has:
key: Key for this egress group. Must be unique for this installation.description: Human‑readable description shown to admins.configured: Array of entries, each containing:
domain: URL or wildcard for the egress destination.type: One or more egress types (see EgressType).Type
1 2export type EgressSetPayload = { groups: { key: string; description: string; configured: { domain: string; type: EgressType; }[]; }[]; };
permissions.egress.deleteDomainUse this to delete a single domain from a previously defined egress group. This is useful when you want to keep the group but remove one domain/type entry.
Arguments
key: Key of the egress group to delete a domain from.domain: Domain to be deleted from the group.type: Egress type to be deleted for that domain.Type
1 2export type EgressDeleteDomainPayload = { key: string; domain: string; type: EgressType; };
permissions.egress.deleteGroupUse this to delete an entire egress group and all of its defined domains.
Arguments
key: Key of the egress group to be deleted.Type
1 2export type EgressDeleteGroupPayload = { key: string; };
permissions.remote.setUse this to set or update the endpoint of a customer-managed remote.
Arguments
key: Key of the remote to update. Must match a key defined in the app manifest.configured:
endpoint: Absolute URL for the remote, or null to reset it:
baseUrl is defined in the manifest, resetting to null will restore the manifest value.baseUrl is defined, resetting to null will unset the endpoint.Type
1 2export type Remote = { key: string; configured: { endpoint: string | null; }; };
permissions.remote.getUse this to get previously configured remotes for an installation. You can fetch specific remotes or all remotes.
Arguments
keys (optional): Array of remote keys to fetch. If undefined, all configured remotes are returned.pageSize (optional): Number of remotes to return in a single page. If this is not specified, all configured remotes will be returned.nextPageToken (optional): Token to fetch the next page of values when using pagination.Type
1 2type RemoteGetPayload = { keys?: string[]; pageSize?: number; nextPageToken?: string; };
The underlying TypeScript definitions for these functions are published as part of the Forge SDK (see @forge/bridge/out/permissions/types.d.ts and @forge/egress for EgressType).
Customer‑managed egress and remotes are designed to be understandable and controllable for admins. An admin’s primary experience is usually within the context of your app, but some functionality is also available in Connected Apps in Atlassian Administration.
When a Forge app invokes the set operations for egress or remotes, an admin will see a modal asking them to confirm the addition or change. If the permissions.external.configurable.enabled is not true, this will be rejected.
If egress has already been configured for a particular domain and that domain is reused for a different type, the modal is not shown again for the same domain.
When viewing a specific app after navigating to Connected Apps in Atlassian Administration, and selecting an app, the Data management tab provides:
This gives admins a centralized place to review data flows across multiple apps in their organization.
The customer-managed egress and remotes APIs are designed so that admins must be in control of any changes:
For detailed API behaviour and type definitions, see the Forge bridge permissions reference.
configurable field to a Connect remote will be rejected.Rate this page: