Atlassian products: multi-connector setup
This page is not about a single connector — it's about running one or
more Atlassian connectors (today: identos.jira-user; on the
roadmap: Confluence, Bitbucket, OpsGenie) off a single Atlassian IdP.
It mirrors the Google Workspace setup page — same pattern, different vendor, a few Atlassian-specific quirks.
One IdP, many connectors
identity_provider
└── atlassian (registered once, OAuth client_id/client_secret from
developer.atlassian.com)
managed_resource
├── jira-user → identos.jira-user + idp_passthrough + atlassian IdP
├── confluence-user → identos.confluence-user + idp_passthrough + atlassian IdP (future)
├── bitbucket-user → identos.bitbucket-user + idp_passthrough + atlassian IdP (future)
└── opsgenie-user → identos.opsgenie-user + idp_passthrough + atlassian IdP (future)
A single Atlassian login grants access to every product whose connector is provisioned against that IdP. The user consents once, on the Atlassian consent screen, for the union of scopes every connector declares.
How scope growth works
Each connector declares upstream_scopes on its idp_passthrough auth
option — the actual Atlassian OAuth scopes its users need. Jira wants
read:jira-user + read:jira-work + write:jira-work + read:me +
offline_access.
When you provision a managed resource in idp_passthrough mode, the
gateway automatically merges that connector's upstream_scopes
into the target IdP's scopes list (IdpScopeMerger). Subsequent user
logins at /authorize pass the union of all those scopes to Atlassian.
before jira-user provision: idp.scopes = [openid, email, profile]
after jira-user provision: idp.scopes = [openid, email, profile,
read:me, read:jira-user,
read:jira-work,
write:jira-work,
offline_access]
after confluence-user provision: idp.scopes = [... + read:confluence-user,
read:confluence-content.all,
write:confluence-content]
The merge is additive and idempotent — uninstalling a connector does not remove scopes (another managed resource may still need them, and we can't safely attribute scopes to a single installer).
The audience=api.atlassian.com quirk
Atlassian 3LO's /authorize endpoint requires an
audience=api.atlassian.com query parameter. Without it, Atlassian
returns a generic "There seems to be an issue with your identity
provider" / server_error on id.atlassian.com.
The Atlassian IdP preset bundled with PBAC now auto-populates this via
authorize_params when you pick Atlassian from the preset tile in
Add identity provider. You can verify / override it in the IdP's
Advanced → Extra authorize params textarea. Every Atlassian 3LO
integration needs it — there is no supported setup without.
Classic vs granular scopes
Atlassian has two scope styles for Cloud APIs:
- Classic:
read:jira-work,write:jira-work,read:me,read:confluence-content.all, etc. Single scope covers many API endpoints. - Granular:
read:issue:jira,read:project:jira,read:comment:jira, etc. Scope per resource × action.
PBAC connectors ship with classic scopes because the mapping from
connector route → required scope is 1:1 and the consent screen stays
short. Don't mix the two — Atlassian treats them as separate grant
sets, and requesting both can cause the consent screen to loop or
deny. If a granular-scope migration becomes necessary, update the
connector manifest's upstream_scopes and re-provision; the merger
will rewrite the IdP row on next install.
Pre-configuring the Atlassian 3LO app
On the Atlassian side, at https://developer.atlassian.com/console/myapps/:
- Create app → OAuth 2.0 (3LO). Name it something recognisable
(
PolicyArc gateway — prod). - Authorization tab → set Callback URL to the AS callback:
(or your real AS issuer +
http://localhost:8080/oauth2/callback/oauth2/callback). - Permissions tab → Add API for each Atlassian product you plan to connect. For Jira Cloud, add the Jira API; then click Configure on that row and grant every scope from the table below that matches a connector you'll provision.
- Settings tab → copy the Client ID and Secret into the PBAC admin UI (Add identity provider → Atlassian tile → paste into Step 3).
PBAC auto-merges scopes into its IdP row; it cannot teach
Atlassian about scopes your app hasn't been granted. If the app's
Permissions tab doesn't list write:jira-work, no amount of PBAC
configuration will fix the consent-screen reject.
Per-product scope reference
| Product | Classic OAuth scopes to grant | Shipped as a connector? |
|---|---|---|
| Jira Cloud | read:me, read:jira-user, read:jira-work, write:jira-work, offline_access | identos.jira-user |
| Jira Service Management | above + read:servicedesk-request, write:servicedesk-request, manage:servicedesk-customer | not yet |
| Confluence Cloud | read:me, read:confluence-user, read:confluence-space.summary, read:confluence-content.all, write:confluence-content, offline_access | not yet |
| Bitbucket Cloud | account, repository, repository:write, pullrequest, pullrequest:write, issue, offline_access | not yet |
| OpsGenie | read:opsgenie, write:opsgenie, offline_access | not yet |
Always cross-check against Atlassian's current scope documentation — Atlassian occasionally renames or adds scopes.
Bitbucket Cloud uses a different scope vocabulary from the rest of
Atlassian; its scopes are verbs (repository, pullrequest:write,
issue) rather than the verb:resource-product form. Don't mix
Bitbucket's scope style with Jira/Confluence scopes in the same
connector — they're granted separately on the Atlassian app, and the
consent screen will surface them as distinct API blocks.
When a user sees "stored IdP token missing required scopes"
If you install / provision an Atlassian connector after users have already logged in through PBAC, their stored IdP tokens do not carry the newly-added scopes. The first gateway call that needs those scopes fails with a 502:
Stored IdP token missing required scopes:
[write:jira-work]. User must re-authenticate with step-up.
Two paths out:
- Recommended: have the user sign out and back in. On the next
/authorizepass, PBAC requests the expanded scope list and the user re-consents on Atlassian's screen. No operator action needed. - Batch: clear
upstream_identity_tokenfor the affected users via the admin API; their next interaction will bounce through Atlassian for consent.
Going forward, the rule is: install and provision Atlassian connectors before inviting users to the gateway, and users never see this error.
Two managed resources, one connector
Atlassian connectors today ship only in idp_passthrough mode — every
call acts as the signed-in user, with that user's Atlassian
permissions. There's no "service account" equivalent like Google's
domain-wide-delegation because Atlassian Cloud doesn't expose one at
the OAuth layer.
If a future use case needs a non-user identity (e.g. webhook ingest, batch reporting), expect a separate connector that uses Atlassian Connect or an API token with Basic auth rather than 3LO. This page doesn't cover those modes.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
id.atlassian.com/error?error=server_error on first redirect | IdP row missing audience=api.atlassian.com | Edit the IdP, paste audience=api.atlassian.com into Extra authorize params. The Atlassian preset should auto-fill this — if not, your IdP row predates the preset change |
| "There seems to be an issue with your identity provider" after entering credentials | Scope list on the request includes a scope the app doesn't have on its Permissions tab | Add the missing scope on the Atlassian console → Permissions tab, or remove it from the connector manifest's upstream_scopes |
| Consent screen shows, user approves, then lands on AS with generic 400 | redirect_uri mismatch | The Authorization tab → Callback URL on Atlassian must match the AS's /oauth2/callback byte-for-byte, including scheme, port, and path |
Refresh-token requests fail with invalid_grant after ~90 days | Atlassian rotates refresh tokens on every use; stored token is stale | Force re-login (clear upstream_identity_token). Also ensure offline_access is in both the app's Permissions tab AND the connector's upstream_scopes |
| User logs in with Google, Jira tool says "no session", redirects back to Google | resource_type_to_idp mapping missing — Atlassian resource falls back to default_idp | Add resource_type_to_idp["urn:connector:identos:jira-user"] = "atlassian" to data.oauth_config.user.idp_selection. (A general connector-install-time wiring of this mapping is on the roadmap; until then, set manually.) |
See also
- Jira connector — manifest reference + routes
- Google Workspace setup — the equivalent page for Google, same pattern
- MCP clients — how Claude Code and other MCP clients attach to the gateway
- Atlassian: OAuth 2.0 (3LO) apps
- Atlassian: scopes for OAuth 2.0 (3LO)