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!
Summary of Project
Forge remote is a set capabilities that make it easier to securely integrate remote back ends with your Forge apps. So far, we’ve made it possible to call Atlassian APIs from your remote server when:
- a user interacts with the UI of your Forge app, or
- a product or lifecycle event you’ve subscribed to is triggered, or
- a scheduled trigger is invoked
This RFC goes into detail on Milestone 3 from RFC-8 and proposes a new mechanism for calling Atlassian APIs from remote back ends without any invocation coming from Forge.
- Publish: 5 Feb 2024
- Discuss: 23 Feb 2024
- Resolve: 1 Mar 2024
Problem
There are various use cases that require communication with Atlassian APIs from a remote back end without relying on a user interaction, product event or schedule. For example, you might need to trigger actions based on webhooks from other systems or utilise your own external UI.
Typically this might be solved for by providing long lived credentials that could be used to generate access tokens as needed (client_secret
, refresh_token
etc) or something like a per-installation shared secret like we have in Connect.
The downside of long lived credentials is the risk that comes with managing them (retrieving them, storing them, rotating them etc). These credentials are extremely sensitive and require robust security controls to manage and protect them.
Proposed Solution
With Forge, our goal is to abstract away as much security risk as possible. We want to take care of that as part of the platform.
Our proposal is to introduce a new module called authTrigger
that operates in a similar way to a web trigger. This module will offer a URL that can be invoked from your remote server, with the sole purpose of triggering the generation and delivery of a new Atlassian API token back to your remote server.
An example manifest would look like this:
modules:
authtrigger:
- key: auth-trigger
endpoint: auth-trigger-endpoint
endpoint:
- key: auth-trigger-endpoint
remote: my-remote-server
route:
path: /auth
auth:
appSystemToken:
enabled: true
Each installation would have a unique auth trigger URL, which you can retrieve via GraphQL similarly to how getURL works for web triggers today. This request would be authenticated with a short-lived access token that you will receive through one of the existing Forge remote flows (e.g. an Install/Upgrade lifecycle event).
So the installation of an app might go something like:
- Customer installs your app
- The
avi:forge:installed:app
lifecycle event is delivered to your remote server with anappSystemToken
. - You use the
appSystemToken
to call the auth trigger getURL GraphQL mutation and retrieve the auth trigger URL. - You persist the installationId and authTriggerURL in your remote data store to use when you need it.
Then later, when you need to make an offline API request
- Make a request to the authTriggerURL for that installation (no auth required). A successful request will return a 200 response code and an empty response body.
- A new
appSystemToken
is delivered to the remoteendpoint
defined in your manifest
Success! You now have the appSystemToken
which you can use as the bearer token to make API requests for the next 55 minutes.
If things go out of sync
In cases where installations go out of sync (despite our retry logic for events etc.) your app will be able to recover automatically. The next time it receives a short lived access token for that installation (e.g. the next time as user interacts with the app or a product event you’ve subscribed to is triggered) you will be able to make a getURL() request to recover the auth trigger URL and restore the offline access.
You will also be able add an additional layer of redundancy with remote support for scheduled triggers. Potentially you could set up a schedule to ensure all your installations are synced daily.
This is an important improvement over Connect where it can be difficult to recover if the shared secret for an installation is lost because you need to wait for a new install or upgrade event.
What about asUser() tokens?
Forge doesn’t currently support asUser access for back-end processes and that will also be the case for the initial release of this functionality. It is something we’ll be exploring soon for Forge across the board, but we’ll save that for a future RFC .
Remember, you can make asUser() requests with the short lived tokens available when the user is invoking your UI modules.
Our thinking behind this design
We recognize that this differs from standard OAuth and is a trade-off against one of our other goals, which is to adhere to standards as much as possible. However, we believe that this strikes the best balance between security and ease of adoption.
We considered options such as providing a client_id
and client_secret
in the developer console, or including refresh_tokens
with installation events. However, these options don’t meet our goals around trust and would also require some level of customization to work in the Forge/Atlassian context anyway.
While this proposal may require more effort to implement initially, it will ultimately reduce ongoing security risks for both you and our shared customers.
Action
We are still early in the design/proof-of-concept phase and keen for your feedback.
We’re seeking input on:
- Whether this would work for your use case.
- Whether you see any major flaws in the proposal.
- Any specific implementation details you might like to see included in the final design.
- Any major difficulties you might see if you’re migrating from Connect and shared secrets.
- What you’d like to see from a developer tooling perspective.