Developer
News and Updates
Get Support
Sign in
Get Support
Sign in
DOCUMENTATION
Cloud
Data Center
Resources
Sign in
Sign in
DOCUMENTATION
Cloud
Data Center
Resources
Sign in
Last updated Jun 19, 2026

Calling Atlassian app APIs from a remote

Once your remote backend has received a request from Forge, you can call Atlassian app APIs.

Prerequisites

When setting up your app to:

  • Call a remote from a Custom UI or UI Kit frontend
  • Call a remote from a Forge function backend
  • Send Atlassian app and lifecycle events to a remote
  • Configure scheduled triggers to invoke a remote backend

You'll need one of the following auth properties set to true in your manifest.yml:

  • appSystemToken — to access Atlassian app APIs as the app's generic bot user
  • appUserToken — to access Atlassian app APIs with the current user's permissions

Where you configure auth depends on where your remote is invoked from:

When your remote is called, the authentication token for calling Atlassian app and Forge storage APIs is sent in either the x-forge-oauth-system HTTP header (for appSystemToken) or the x-forge-oauth-user HTTP header (for appUserToken).

Token Expiry

Tokens sent in either the x-forge-oauth-system header or the x-forge-oauth-user header are encoded in JWT. The exp claim in their payload represents the expiration time.

Getting started

Each request from Forge to your remote includes two values you'll need to call Atlassian app APIs:

  • The auth token, in either the x-forge-oauth-system or x-forge-oauth-user HTTP header
  • The API base URL, embedded in the FIT token (in the Authorization header) under the app.apiBaseUrl claim

Extracting the values you need

To extract both values from an incoming request:

  1. Read the auth token from the x-forge-oauth-system or x-forge-oauth-user header
  2. Parse the FIT token from the Authorization header
  3. Extract app.apiBaseUrl from the FIT token's claims — use this as the base URL for all Atlassian app API requests

Example FIT token claim:

1
2
{
  "app": {
    "apiBaseUrl": "https://api.atlassian.com/ex/confluence/4c822e2f-510f-48b9-b8d0-8419d0932949",
    "installationId": "ari:cloud:ecosystem::installation/...",
    "id": "ari:cloud:ecosystem::app/..."
  }
}

Important: The apiBaseUrl is NOT the same as your site URL (e.g., yoursite.atlassian.net). Always use the apiBaseUrl from the FIT token.

For details on the FIT token structure and validation, see Forge Invocation Token (FIT).

Node.js example

This example uses the fetch function from the node-fetch module to request data from the Confluence API (here, token is the value you received in the x-forge-oauth-system or x-forge-oauth-user header):

1
2
'use strict'
import fetch from 'node-fetch';

export async function fetchFromConfluence(token, apiBaseUrl) {
  const headers = {
    Accept: 'application/json',
    Authorization: `Bearer ${token}`
  }
  return await fetch(`${apiBaseUrl}/wiki/rest/api/content`, { headers });
}

For more detail, see the Confluence node client in Bitbucket.

For Connect apps that have adopted Forge, the Atlassian Connect Express framework provides a method getForgeAppToken to retrieve an app token stored in a request from the Forge platform.

Java example

This example uses a GET request to call the Confluence Content API (here token is the value you received in the x-forge-oauth-system or x-forge-oauth-user header):

1
2
public ResponseEntity<String> getContent(final String token, String apiBaseUrl) {

    final HttpHeaders headers = new HttpHeaders();
    headers.setBearerAuth(token);

    final HttpEntity<String> entity = new HttpEntity<>(null, headers);

    final ResponseEntity<String> response =
            restTemplate.exchange(apiBaseUrl + "/wiki/rest/api/content",
                    HttpMethod.GET, entity, String.class);

    logger.info("Response statusCode={}", response.getStatusCode());

    return response;
}

For more detail, see the Confluence java client in Bitbucket.

For Connect apps that have adopted Forge, the Atlassian Connect Spring Boot framework provides a method asApp(String installationId) to send a request using a stored app access token. An example is available at Forge Remote Sample.

Offline user impersonation

Apps have the ability to impersonate any user in their installation context, subject to a number of conditions. For more information, see:

On a Forge remote, impersonating a user that's not in session requires exchanging the app system token for an authorisation token for another user. This can be done by calling a special mutation on Atlassian's GraphQL Gateway. This mutation is configured to allow being called from a Forge remote using a Forge app system token.

1
2
mutation forge_remote_offlineUserAuthToken($input: OfflineUserAuthTokenInput!) {
  offlineUserAuthToken(input: $input) {
    success
    errors {
      message
    }
    authToken {
      token
      ttl
    }
  }
}

Where input contains:

1
2
{
  contextIds: ["<context ARI of the installation>"],
  userId: "<account ID being impersonated>"
}

This can be called by calling the GraphQL gateway at https://api.atlassian.com/graphql and setting the Authorization header to Bearer ${appSystemToken}. If success is set to true in the response, the corresponding token in authToken can be used in the same way as the app system token or app user token in the examples above. This will make API calls authenticated as the given account ID, subject to the constraints of offline user impersonation.

The ttl is the token lifetime in seconds. This can be used to cache a particular user token for a given installation and user ID, we recommend doing this if your app will make multiple impersonation calls for the same user.

The rate limit for requesting user impersonation tokens using this mutation is 10,000 requests per minute, per app.

Node.js example

1
2
const query = "<as above>";

async getTokenForUser(systemToken, contextAri, userAccountId) {
  const response = await fetch("https://api.atlassian.com/graphql", {
    method: "POST",
    headers: {
      accept: "application/json",
      "content-type": "application/json",
      authorization: `Bearer ${systemToken}`,
    },
    body: JSON.stringify({
      query,
      variables: {
        input: {
          contextIds: [contextAri],
          userId: userAccountId,
        },
      },
    }),
  });

  if (!response.ok) {
    throw new Error(`HTTP error: ${response.status}`);
  }

  const json = await response.json();

  if (!json.data.offlineUserAuthToken.success) {
    throw new Error(`GraphQL error: ${json.data.offlineUserAuthToken.errors}`);
  }

  // returns { token: "<token>", ttl: <token TTL> }
  return json.data.offlineUserAuthToken.authToken;
}

Atlassian app APIs

For a complete list of Atlassian app APIs that you can call from your remote, see :

Next steps

For further help, see how you can:

Rate this page: