Question about accountId

For global end user accounts (doesn’t include Service Desk users), the following definitely holds:
Atlassian user accounts are global, and their immutable identifiers are unique in the global domain of account IDs. Those identifiers will be reported consistently by all systems backed by Atlassian account (which includes Cloud instances of Jira, Confluence and Stride).

For app accounts:
I believe that the same applies, but I cannot personally assert it. Apologies!

3 Likes

@jack re: your question about accountId on production instances vs. developer instances — yes, also the same. Two things here… first, a development instance is no different than a live customer prod instance. They’re just on a different license/subscription. Second, the accountId is tied to the account login. So, if you’re signing in with the same email address across two cloud instances, the accountId will be the same.

2 Likes

@nmansilla and what about add-on users? Will they have the same accountId across all instances?

@david2 @jack @danielwester
The accountId of the user created for an app will be the same across all instances. There is a single account made per app key, not per-installation. I will confirm if apps installed using different mechanisms (marketplace, and via url in dev-mode) get different users, but I suspect that isn’t the case.

@danielwester you mentioned ‘It’s already impossible to discern regular users from add-on users from the “shape” of the accountId’. AccountId’s are meant to be opaque identifiers, and their format can change, so we would not advise on using the shape of the id to extract any information. The only guarantee that we can provide is that it will be 1-128 alphanumeric containers, with maybe a few “:”'s in it.

1 Like

Awesome! Thank you! Now can I that if this changes can i go the normal deprecation routes for app developers (ie. announcement with some period of heads up)?

The reason I’m asking for that is that I’ve seen the response of “it wasn’t an api so it the api deprecations didn’t apply” and since this isn’t really an api but a behavior/output of a system which the apps are a downstream consumer of it, the might not be alerted to it until after it changes (and a change with anything user identifications could cause all kinds of “fun”).

/Daniel

@shraj thanks for the reply.
Actually, I was the one asking about how to identify add-on users, and the question still stands. It is essential that we are able to identify that an accountId represents an add-on user, because Connect will not let an app impersonate an add-on user, and will instead return all sorts of errors (depending on the REST API endpoint) when such an attempt is made.
Let me explain when that might happen: when a post-function implemented by an app is triggered, the qpp receives a /trigger http call with the accountId of the “current user” (i.e. the user who triggered the transition on which the post-function is defined) in the JWT token. The post-function will in turn call Jira back (through the REST API) to make changes: set a field value, transition issues, add comments, etc. It will generally make these changes “on behalf of” the current user, using impersonation, so that the appropriate user shows in the issue history. However, if the original transition was triggered by another app (e.g. the Salesforce connector), the “current user” will be… an add-on user!
When that is the case, all REST calls back into Jira done with impersonation will fail - and the error message generally won’t even be explicit as to why the call failed.
That’s why we need to be able to know ahead of time that the “current user” is an add-on user, in which case we don’t attempt impersonation. This was easy with userKeys, since every add-on user’s userKey started with “addon_”. this is not the case with accountIds.

1 Like

@danielwester:
As far as I know, we don’t really anticipate this behaviour changing for now, and will likely provide a heads up if that were to change.

We try and adhere to a 6 month deprecation where possible, and our “it wasn’t an API so api deprecations didn’t apply” is usually for undocumented API’s / behaviours that we’re changing.

@david2 That’s definitely an interesting case! I don’t think we currently have a way of differentiating the two, but will have a chat with the rest of the team to see what the options are.

1 Like

@shraj thanks!
Of course, one easy solution would be to re-allow impersonating addon users like it was with JWT impersonation (“sub” claims).

@david2, let me take my chance at answering your question. With the user keys gone, the app will only receive the account ID in the webhook. Now, I think at least one more API call needs to be made to figure out what kind of user it is. Here is the Jira API that returns details of a user, given the account ID: https://developer.atlassian.com/cloud/jira/platform/rest/v2/#api-api-2-user-get

With me so far? Now that we agreed (?) on making one extra call to fetch the details of the user, this is what we need to do: Make the API return whether the user is an app user, or a regular user. The underlying Atlassian Accounts API already provides this information in a field called account_type. Jira and Confluence should relay that information back to the client. It is also worth pointing out that there are other ‘app’ users in the system, besides the ones created for Connect apps. This solution will work for all other cases where the acting user is not a real person.

About enabling impersonation for app users, the reason for disabling that was an app could impersonate other app users, which was a security concern. We could perhaps look into allowing an app to impersonate its own user, but it wouldn’t solve for all the cases.

Hi @natashbar,
first of all, I don’t think that having to make an extra call to the Jira REST API is a good thing - Atlassian is trying to reduce the number of calls apps have to make to function (c.f. the GraphQL initiative), and now you’re saying we should increase it…
Then, I tried to call the (Jira) /rest/api/2/user endpoint for our addon user, and the response did not include an account_type field:

{
  "self": "https://innovalog.atlassian.net/rest/api/2/user?accountId=557058:472c64c9-2567-4213-839b-86bf21558300",
  "key": "addon_com.innovalog.jmwe.jira-misc-workflow-extensions",
  "accountId": "557058:472c64c9-2567-4213-839b-86bf21558300",
  "name": "addon_com.innovalog.jmwe.jira-misc-workflow-extensions",
  "emailAddress": "com.innovalog.jmwe.jira-misc-workflow-extensions@connect.atlassian.com",
  "avatarUrls": {
    "16x16": "https://avatar-cdn.atlassian.com/7dc7b05da33fdf03bcef359457ceb3f0?s=16&d=https%3A%2F%2Fsecure.gravatar.com%2Favatar%2F7dc7b05da33fdf03bcef359457ceb3f0%3Fd%3Dmm%26s%3D16%26noRedirect%3Dtrue",
    "24x24": "https://avatar-cdn.atlassian.com/7dc7b05da33fdf03bcef359457ceb3f0?s=24&d=https%3A%2F%2Fsecure.gravatar.com%2Favatar%2F7dc7b05da33fdf03bcef359457ceb3f0%3Fd%3Dmm%26s%3D24%26noRedirect%3Dtrue",
    "32x32": "https://avatar-cdn.atlassian.com/7dc7b05da33fdf03bcef359457ceb3f0?s=32&d=https%3A%2F%2Fsecure.gravatar.com%2Favatar%2F7dc7b05da33fdf03bcef359457ceb3f0%3Fd%3Dmm%26s%3D32%26noRedirect%3Dtrue",
    "48x48": "https://avatar-cdn.atlassian.com/7dc7b05da33fdf03bcef359457ceb3f0?s=48&d=https%3A%2F%2Fsecure.gravatar.com%2Favatar%2F7dc7b05da33fdf03bcef359457ceb3f0%3Fd%3Dmm%26s%3D48%26noRedirect%3Dtrue"
  },
  "displayName": "Jira Misc Workflow Extensions",
  "active": true,
  "timeZone": "Europe/Berlin",
  "locale": "en_US",
  "groups": {
    "size": 3,
    "items": [
      
    ]
  },
  "applicationRoles": {
    "size": 2,
    "items": [
      
    ]
  },
  "expand": "groups,applicationRoles"
}

I still believe this information should be passed to apps without requiring an extra call.

Finally, we use Atlassian Connect Express, and it could also handle whatever is required to identify add-on users when calling the “asUserByAccountId()” method - for example as part of the impersonation token acquisition. Basically, if the impersonated user is unacceptable (because it’s an add-on user), it should revert to no impersonation.

Am I missing anything?

Hi @david2 @natashbar

I’m on the JIRA GDPR team and I’ve added a ticket to my teams backlog to see if we can add this information to the jira rest api (no commitment that we can at this stage though). It sounds like something we’d want to do, but doing so would probably be a while away as it requires some dependencies to be complete that aren’t there yet.

@david2 if you want to use GDPR mode in the meantime a workaround is to use the email address as this shouldn’t be hidden for app users.

1 Like

@hday I think from an efficiency usage perspective it would be best if you could include in the webhook payload (or http headers) - don’t make us have have more latency than necessary (and add an extra hit to your services).

2 Likes

@hday thanks for the workaround. Is it safe to assume that any email address @connect.atlassian.com will be an add-on (app) user?

@david2 yes, it should be safe to assume that. I don’t believe anyone else would be able to make an account with that email domain, and all Connect apps have that email domain.

1 Like

We are currently making this assumption internally in jira. Can’t guarantee that that won’t change in the future, but it seems unlikely to.

1 Like

@hday And by the way, why doesn’t the authorization server (auth.atlassian.io) simply reject requests to create an access token for an add-on user other than the current app’s add-on user? This way, we would have a clear and consistent error beforehand, which could be handled directly in Atlassian Connect Express (in internal/oauth2.js).

Please note that the structure of the email address ...@connect.atlassian.com is an undocumented feature and is subject to change without any notice.
Please also note that, there are other types of system/app users (that are not related to Connect users), for which this trick won’t work. For example if a 3LO app does things via an API call, the corresponding user won’t have an email address to check against.
Therefore, providing extra information about the “type” of the user (by Jira and Confluence) is probably the most reliable way to address this situation, in the webhook payload and/or in the user fetch API. This information is available in the underlying Identity API, but unfortunately it is not passed on to the apps by Jira/Confluence. Even if it is only provided in the fetch API, you can cache this information for a fairly long time since the type of user is not likely to change at all.

Hi @natashbar,
Are you saying we should not heed to the advice the other Atlassians gave here? But then, what should we do? Can you commit to providing a solution like the one you described in time for us to implement the GDPR migration in due time? We are already completely in the dark as far as configuration migration is concerned (migrating post-function configurations in workflows), and the clock is ticking…

1 Like

Hi David,
What I am saying is that, heed that advice by all means but be aware of those caveats. I could see us providing a more reliable solution, but we (different teams in Atlassian) haven’t yet agreed on the solution yet since this topic was brought up only recently. I will be following that up with Jira and Confluence teams and get back to you. I shared some information about the internal state of things (so you are not kept in the dark), which could have caused confusion at the same time. The good thing is we have a work-around, chances are we can get a proper solution out in time.
Regards,
Norman