Once your remote backend has received a request from Forge, you can call product APIs.
When setting up your app to:
You’ll need one of the following in your manifest.yml:
endpoint.auth.appSystemToken
set to true
endpoint.auth.appUserToken
set to true
Which one you need depends on whether you want to access product APIs as a generic bot user (appSystemToken
) or the current user’s permission (appUserToken
).
This ensures requests to your remote contain an x-forge-oauth-system
or x-forge-oauth-user
header, containing a token you can use to call product and Forge storage APIs.
Both of these tokens are encoded in JWT. The exp
claim in their payload represents the expiration time.
Once you’ve got your token, you can use it in backend requests to Product APIs.
This example uses the fetch
function from the node-fetch
module to request data from the Confluence API:
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.
This example uses a GET request to call from a Confluence Content API:
1 2public ResponseEntity<String> getContent(final String token, String baseUrl) { final HttpHeaders headers = new HttpHeaders(); headers.setBearerAuth(token); final HttpEntity<String> entity = new HttpEntity<>(null, headers); final ResponseEntity<String> response = restTemplate.exchange(baseUrl + "/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.
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 2mutation 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.
1 2const 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; }
For a complete list of each of the product APIs that you can call from your remote:
For further help, see how you can:
Rate this page: