RFC-28: Custom Domains Support For Jira

Summary of Project:

Custom Domains support is coming to the Jira product family. This means that customers will be able to choose domains for their Jira products instead of using default atlassian.net domain. While no API changes are planned, it is important for Ecosystem apps to properly use the existing siteUrl (Forge apps) and baseUrl, displayUrl fields (Connect apps) as their values will be distinct when custom domains are enabled. We would like to invite you to validate these changes in testing instances to assess any impact on your apps. Your collaboration and feedback are essential to us as we work together to deliver a seamless experience to our mutual customers.

  • Publish : 13 Oct 2023
  • Discuss : ~31 Oct 2023
  • Resolve : ~10 Nov 2023

Problem / Opportunity

Cloud customers have long wanted to access their Atlassian products using their own domain names, e.g. use ***.acme.com, instead of the *.atlassian.net domain they use today. We are excited to announce that with our next Custom Domains milestone, customers can enjoy the flexibility of customizing their domain names for Jira family products to promote their own brands with simple setup steps.

Org admins have a one-click toggle to activate or deactivate their custom domains. Please refer to Add a custom domain documentation on how to do this. When activated, there is a possibility that your apps may fail to load if you don’t use API properly. See Proposed Solution Section for more details.

Proposed Solution

In this post, we will provide important details about this upcoming change and what you need to know as an ecosystem developer.

What is changing in upcoming release?

API URL For Custom Domains

There will be no change for REST API URL when Custom Domains is configured. More specifically, all browser requests should be using custom domain URL, and all API requests will continue to be made via the default *.atlassian.net URL.

Such decision is made to address security concerns. As a rule of thumb, tokens with global scope cannot be used on Custom Domains to limit any impact in case of a security incident.

API Token & OAuth Apps

Considering the rule of thumb above, URL for UI and API used by API Token & OAuth apps will no longer be the same. You may find your app needs to perform extra work to handle conversion between custom domain URL and the default *.atlassian.net URL.

If you encounter difficulties handling URL conversions, please reach out with your use case.

Forge apps

Site domains are mostly abstracted away in Forge so we don’t expect Custom Domains to have an impact on Forge apps. That said, we still encourage you to test your apps in a site with Custom Domains enabled and confirm expected functionality.

The siteURL property on the Custom UI Bridge will automatically return the custom domain URL for sites that have the Custom Domains feature enabled. So if your app uses this property for display or navigation it should continue to work seamlessly.

Connect Apps

For Connect apps we expect that most apps will function correctly without any changes. If your app is displaying URLs to the user, be sure to review your usage of the baseUrl, displayUrl, and displayUrlServicedeskHelpCenter returned as part of the lifecycle events sent to connect apps.

If a tenant does not have a custom domain, all of these values will be equal to each other. However, if a tenant does have a custom domain, the displayUrl and displayUrlServicedeskHelpCenter fields will contain the custom domains that should be used when displaying a URL to the user (examples see below).

No Custom Domain
{
  'baseUrl': "url.atlassian.net",
  'displayUrl: "url.atlassian.net",
  'displayUrlServicedeskHelpCenter': "url.atlassian.net"
}
With A Custom Domain
{
  'baseUrl': "url.atlassian.net",
  'displayUrl: "url.custom-domain.com",
  'displayUrlServicedeskHelpCenter': "url.custom-helpDesk.com"
}

If, as a developer, you are currently using the baseUrl for displaying URLs to the user, these should be replaced with either displayUrl or displayUrlServicedeskHelpCenter so that the relevant custom domains are always displayed when present for a particular tenant.

Additionally, If you have enabled Content Security Policy for you apps, or declared an X-Frame-Header limiting to app to render in an *.atlassian.net domain, your apps will not render in any tenant that has a custom domain. This should be amended for your apps to be able to function properly across all tenants.

Asks

As we prepare to go live to support Custom Domains for Jira customers, we seek your collaboration in validating and mitigating any potential impact that these changes may have on your apps. We plan to apply a 3 month deprecation notice period and fully support Custom Domains afterwards.

More specifically, we seek your help in following aspects:

  • Be aware of the upcoming changes and plan to adopt Custom Domains information for your app experience
  • Thoroughly test your apps and report back any impact or issues that you may encounter. To facilitate this process, we will provide means to set up Custom Domains. Please register for the testing with your tenant details here Jira Service Management.

We will enable Custom Domains feature in your tenant within 48 business hours after you register.

If your apps is impacted by the changes, we are looking forward to working together with you to resolve any issues before releasing Custom Domains to general public. Please reach out to us if you encounter any issues through this link - Jira Service Management

2 Likes

Hi @Ningqi,

for Connect, it will be a requirement for us to make baseUrl, displayUrl, and displayUrlServicedeskHelpCenter available via the Connect Javascript API, e.g. using a method similar to window.AP.getLocation. I’d expect a method like window.AP.getUrls(). (Edit: I’d also be happy for it to be added to AP.context.getContext() as suggested by @remie.)

Background: If we only get the URLs from the lifecycle events, a Connect app’s frontend will have to do a call to the vendor’s own backend to retrieve the URLs. For apps that, so far, relied exclusively on Jira’s REST APIs, this will now create the need for their own backend, with all the engineering and operational overhead that comes with this. This would be entirely unnecessary, as the URLs are obviously already available to Jira and would simply need to be exposed via the Javascript API.

6 Likes

Would it also be an option to just add it to AP.context.getContext()?

7 Likes

Sounds like a great implementation, and congrats for reaching this outcome on this project.

  • We used to assume that the Jira and Confluence sites would both be under the same atlassian.net subdomain. Can we still assume that, and/or can we have an API to tell us which Confluence(s) are linked to which Jira instances?
  • Will cross-app authentication keep working? Currently, accountIds from Confluence work in Jira. Will it remain the same? (See screenshot below: When we receive a request to view info in our Confluence app, on which we have to add info from Jira, we take the accountId from the JWT token, then create a Jira user with it, add the clientKey of our app in the Jira instance we want to reach to, and it’s a valid authentication).
  • The new CSP means we’ll have to replace the CSP img-src with * Isn’t that worrying?

Both img-src and frame-ancesstors will become *, and I’m worried for img-src (It’s required to display ADF):

3 Likes

@Ningqi,

In the Jira Platform REST API, a client can get Jira instance info using GET /rest/api/3/serverInfo. Can you confirm the baseUrl valued returned by this endpoint would continue to be the base URL for the API? Is there any other way for API-only clients (ie API tokens or OAuth 2.0) to know the base URL of the UI (ie the custom domain)?

3 Likes

Thanks for the request @hannes-finesoftware! We have started exploration on how feasible it is to include such change in the upcoming release. Will address this in the RFC resolution. Cheers!

2 Likes

Thanks for your comments @aragot. To try and address your questions:

  • While that assumption will no longer hold, and products may be under different domains for the same customer, The use of the custom domains are solely for display purposes and any API communication between products should use the baseUrl which is not changing

  • Similar to the above points, all of this cross-product communication should still happen using the baseUrl for the tenant, this behaviour will continue to work as expected

  • Yes, the recommendation is to change the CSP to ‘*’. At the moment this is a required change for apps with a CSP to function correctly on tenants with a custom domain

Thanks again for your comment and hopefully this helps.

4 Likes

@Ningqi, @nsher, I think the CSP (Content Security Policy) topic needs more detailed information: According to MDN’s page on CDN there are multiple fetch directives, with differing semantics. @aragot asked about directives img-src and frame-ancestors and that adding * is probably needed (Atlassian confirmed this)
But what about the other directives, mainly script-src? That is what we are settings to specific domains in order to comply with Atlassian’s security requirements. Do we need to set this to * also? I suspect that specifically for our app we do not need to do that, because we do not include 3rd-party JS scripts in our HTML documents. Infact, only from these 2 domains are scripts included:

  • *.azurewebsites.net: our own scripts from our own hosting
  • connect-cdn.atl-paas.net: for Atlassian Connect’s all.js

We don’t include other scripts. We don’t make it possible for users to include other scripts. → We should be fine without * for script-src, right?

3 Likes

Hi @Ningqi ,
so we just activated a custom domain for our site, and my (naive) expectation would have been that our app should receive an Connect lifecycle hook with the updated display* values. This did not happen. Does that mean we’ll only receive the updated values after we update our app the next time, during the “normal” app update flow? That seems not so great, as we only release about once a week, while having “bad” data in our DB in the meantime? I’m asking this, because we have an external integration, where users would enter their Jira URL to connect. If they enter their display URL we cannot do the lookup correctly if we have stale data. It’s not the biggest dealbreaker, but it would’ve been great to send a Connect hook with updated display* properties once the custom domain is activated.

3 Likes

Hi @tobias.viehweger if you could open a support ticket via Jira Service Management or update existing one with more details (for example, for which domain you are experiencing this issue), we will investigate into this further.

In one of our apps we display a link to a specific endpoint the Jira REST API to an admin, so he can perform the GET call directly from his browser. Should we use the custom domain or base URL for this?

Also, are the displayUrl, and displayUrlServicedeskHelpCenter fields coming to atlassian-connect-spring-boot, specifically the AtlassianHost class/table?

1 Like

Do displayURl and displayUrlServicedeskHelpCenter will be available to fetch by REST API some way? When customer will change domain after installation of app then we will need to get somehow that information

2 Likes

Hello @Ningqi,

We haven’t been able to try this out with our app as our domains does not get set up and we’re currently awaiting assistance from Atlassian on our bug report. Will it be possible to provide feedback later than today?

In the meanwhile I’m wondering what lifecycle event we can expect when a domain is changed?

@Ningqi, @nsher, it’s been a while. Do you have any feedback here? Would be much appreciated. Thanks.

Hello @ibuchanan @FilipBaszak, thank you for your comments regarding the custom domains information in the Server Info API. We’ll soon be adding displayUrl & displayUrlServicedeskHelpCenter to that API. Watch out the for change log in this month.

4 Likes

@tobias.viehweger & @Ningqi,

did you have some outcome of your investigation? I’d also expect that as soon as I activate a custom domain for my site, all apps would get a lifecycle webhook. Is this not the case?
So, when would apps get a lifecycle webhook with the display urls?

1 Like

@Ningqi,
can you clarify your intended plan when this feature should go live? You’ve stated a 3 month deprecation notice period but not exactly when this period will start.
I’d like to have our app prepared in time.

PS: Is there a specific reason why this feature has a 3 month deprecation notice instead of the usual 6 months?

1 Like

hi @AndreasEbert,

Apologies for the delay in responding to your questions about CSPs and custom domains. We have been clarifying our recommendations based on these comments.

Our original recommendation came from our observations that when a custom domain is activated for a tenant, directives like frame-ancestor that allowed traffic from the tenant’s domain broke, and do need adjustment.

While you can still remedy this by adding ‘*’ to these directives, the better recommendation is to create a dynamic CSP to account for custom domain activation.

When a custom domain is activated for any given tenant, an installation lifecycle event will be sent with the relevant custom domain fields, which can be added to a dynamic CSP

As for other directives such as your script-src example, you are correct that this does not need to be changed, as this does not allow requests from any domain that would change as a result of custom domain activation.

Also to address the questions around the lifecycle events that should be firing on the activation of a custom domain. We did find that this was not working as intended, and should now be fixed. Events will fire any time that a custom domain is activated or deactivated, and will appear the same as other installation/update lifecycle events.

Sorry again for the delay getting to these questions, and hope that they helped.

3 Likes

Thanks for the detailed answer.
One question to:

What exactly do you mean with “dynamic CSP”? That the domains are included in the CSP directive dynamically? Or that a “nonce” is used, as this article explains? Just so we’re on the same page :slight_smile:

1 Like

Yeah, for sure, In this case, we are not talking about a “nonce”, but rather talking about a ‘dynamic CSP’ from the idea that each time a new custom domain is received through lifecycle events, it’s added to the CSP directive.