Action Required - Atlassian Connect installation lifecycle security improvements

@HanjooSong Is my understanding correct: Versions of ACE after 7.1.5 modify the atlassian-connect.json that is served from our app. ACE adds automatically

apiMigrations: {
  "signed-install": true

I was surprised by this, as it seems not documented. We have atlassian-connect.json in source control to know what the capabilities of our app were at which point in time. I’d argue that changing atlassian-connect.json is a major new thing in ACE. This change also automatically released a new version of our app on marketplace, which also was a surprise, as we did not change atlassian-connect.json.

Are there any other changes done to atlassian-connect.json when serving through ACE?


For apps that have authentication none in the descriptor - do they need to do anything?

  "authentication": {
    "type": "none"

Or is this a case of where we should just add the signed-install thing just in case?

1 Like

You do not need to do anything for authentication type none as we will ignore them when we collect reports before the enforcement date.
FYI, new version of ACE framework will automatically add "signed-install":true to the descriptor but will have no effect.

Hi @marc ,
We updated ACE to add signed install support and it was set to automatically opt-in apps to this new feature. We realise now this was not the correct approach and a subsequent ACE update removes this opt-in. Our apologies if you app unexpectedly registered a new version due to this change.

Hi @scottohara
Apologies for the confusion with ACE and its default opt-in feature.
We agree that modifying app descriptor from the framework was not a good idea, and have removed the default opt-in with a recent release.
The settings from config.json will still work as before with the new v7.4.0, it is recommend to edit the app descriptor file directly and add "signed-install":true under apiMigrations to opt-in.
Please ask any questions if you have.

1 Like

Hi @ErkkiLepre , We have added support for multiple baseUrl for verifying the audience claims with the recent v7.4.0 release. You can define list of allowed app base urls in you config.json as below.

  "production": {
    "allowedBaseUrls" : [
1 Like

Hi @HanjooSong

I recently upgraded my ACE version 7.3.0 and added "signed-install": "enable" to my config.js.

Not long after I noticed that webhooks started to become “patchy”.

Sometimes POST request would be sent when an issue was updated in Jira, sometimes it wouldn’t be. There would be stretches where no event would be emitted at all. Sometimes the event would be emitted a few minutes later with a retry header, sometimes not. But the original POST to my API was never sent.

Likewise, sometimes app installation worked, other times it returned a 503 error.

But when I go to my app logs, the /installed endpoint is never called.

  1. Could these issues be related to ACE v7.3.0?

  2. Is there any chance you could check if this new version alters webhook behaviour? I’m not sure if the issue is related to the ACE version but It’s the only change I’ve made to my app recently and am trying to narrow it down.

  3. Would you suggest updating immediately to v7.4.0 and adding "signed-install": true to my descriptor as a potential fix?

Thanks in advance.


Hi @RhysDiab ,

  1. Could these issues be related to ACE v7.3.0 ?
    There hasn’t been any changes related to the webhook in ACE, also 503 status code is not what ACE returns explicitly from the framework as far as I know. I believe it may not be related to the upgrade.
  1. Is there any chance you could check if this new version alters webhook behaviour?
    We did not notice any issues around webhook with recent ACE versions, but I will keep on investigating around this area and keep you posted.
  1. Would you suggest updating immediately to v7.4.0 and adding "signed-install": true to my descriptor as a potential fix?
    The minor patch from v7.3.0 to v7.4.0 only changes the default opt-in behaviour. Patching your app will not mitigate the issue with the webhook if ACE did introduce the bug.

Additionally, if this issue keeps blocking you from releasing your app, creating DEVHELP ticket with more detail around your app and test instance will help with the investigation.
Thank you.

1 Like

Thanks @HanjooSong

My app is already in production.

Can you post a link to the DEVHELP portal?

I can’t find it anywhere in the UI.

UPDATE: found the support portal here



1 Like

Hi @HanjooSong ,

When we add addon.authenticateInstall() to our uninstall route, the uninstall authentication fails for installations that were done before the change. What’s the best way to identify the new asymetrically signed requests? Or is there another way to work around this?

And another question: for non-customised apps, what’s the best way to confirm, that the installed / uninstalled routes are being authenticated properly?

Hi @ErkkiLepre
For non-customised apps, the framework will fallback to use old method of authentication if the JWT header alg is not RS256. Basically the force flag is introduced to disable this fallback and fully gain the security benefit.
But I understand the problem that you are having with custom uninstalls, and I think it should be something addon.authenticateInstall() should support out of the box, just as the default framework behaviour. Thanks again for reporting this issue, I will have this bug sorted as soon as possible.

Hi @ErkkiLepre please find latest ACE (v7.4.1) for the addon.authenticateInstall() middleware patch.


Thanks for the prompt response, but unfortunately the new version doesn’t seem to help.

To reiterate, the scenario is, that the customer has installed the app using an older version of the app. We update to ACE 7.4.1 and add addon.authenticateInstall() to the /uninstalled route. The the uninstallation fails with the error 'Authentication verification error (401): Invalid JWT: Algorithm from the header "HS256" does not match'

Hi @ErkkiLepre , sorry to hear that the patch did not work as expected. I am assuming it could be the “force” behaviour in your config.json file.
Can you try with removing that setting if it is there, and have “singed-install” configuration only from the descriptor files?

  "baseUrl": "{{localBaseUrl}}",
  "apiMigrations": {
    "gdpr": true,
    "signed-install": true
1 Like

Hi @HanjooSong ,

As a matter of fact, we have two apps - one that serves both Jira and Confluence, and one traditional one that serves only Confluence, and I was experimenting with the latter one yesterday. Nonetheless, moving the configuration from config.json to the descriptor solved the issue. Thanks.

One more question. authenticateInstall overwrites req.context (originally set in request.js in ACE). What is the purpose of this change? We rely on req.context in our installation flow, and this causes changes for us. We can work around this, no problems there. Just trying to understand the purpose of this change and whether we should rely on req.context to begin with.

How do we validate enabled and disabled events? Will a JWT be included for those as well?

Hi @rohan this change applies to install and uninstall lifecycle only.
enabled and disabled lifecycle will remain unchanged, which includes the symmetric JWT
that needs to be verified using a sharedSecret.


Hi @ErkkiLepre , Thank you for your patience with reciprocating issues you are finding. request.context is restored for authenticateInstall middleware in v7.4.3.
For your information, hostBaseUrl in request.context comes from the request body if it is a very first installation for a host, and from the db storage for subsequent install callbacks(upgrades). Which is expected to be eventually consistent as hostBaseUrl should be stored in database during postInstallation step.

Updated: wrong version was mentioned, corrected it to v7.4.3


Hi @HanjooSong, isn’t the setting atlassian.connect.allow-symmetric-auth-install-callback now?

When I set it to false, I get an error

java.lang.ClassNotFoundException: org.springframework.boot.web.error.ErrorAttributeOptions
at ~[na:1.8.0_292]
at java.lang.ClassLoader.loadClass( ~[na:1.8.0_292]
at sun.misc.Launcher$AppClassLoader.loadClass( ~[na:1.8.0_292]
at java.lang.ClassLoader.loadClass( ~[na:1.8.0_292]
at com.atlassian.connect.spring.internal.AtlassianConnectErrorController.error( ~[atlassian-connect-spring-boot-core-2.2.2.jar:na]

it it ok?

Hi @palbecki , I will have a look at the error you’ve reported. In the mean time it is not required to set atlassian.connect.allow-symmetric-auth-install-callback to false.