Jira

Jira is Atlassian's work-tracking product, hosted on a Jira Cloud site. ZombieLicenseHunter connects through an OAuth 2.0 (3LO) app to sync the Atlassian user accounts on that site, enabling review of who still holds a Jira account and whether it is active.

Prerequisites

  • A Jira Cloud site (e.g., acme.atlassian.net). Jira Data Center and Server are not supported
  • An Atlassian account with access to that site to authorize the connection, and access to the Atlassian developer console to create the app
  • ZLH running with a reachable callback URL

Step 1: Create an OAuth 2.0 Integration in the Atlassian Developer Console

  1. Go to developer.atlassian.com/console/myapps and click Create > OAuth 2.0 integration
  2. Name it ZombieLicenseHunter, accept the terms and create it
  3. Under Permissions, find Jira API, click Add, then Configure, and add this classic scope:
    • read:jira-user — read user accounts, including active status and (where not hidden) email address
  4. Under Authorization, next to OAuth 2.0 (3LO) click Add and set the Callback URL to {YOUR_ZLH_BASE_URL}/integrations/jira/callback
  5. Under Settings, copy the Client ID and Secret

Atlassian may warn on the consent screen that the app has not been reviewed. That is expected for a private integration.

Step 2: ZLH-Side Values

  • The Callback URL must be exactly {YOUR_ZLH_BASE_URL}/integrations/jira/callback — protocol, host, port and path
  • Scopes requested: read:jira-user offline_access. The first must be added under Permissions in Step 1; offline_access is a token-refresh scope that Atlassian grants without configuration. Self-hosted deployments can override the list with JIRA_SCOPES
  • The Client ID and Secret are entered per integration in the UI, not in environment variables

Step 3: Connect via the ZLH UI

  1. In ZLH, navigate to Integrations > Add Integration
  2. Select Jira
  3. Enter the Client ID and Client Secret from Step 1
  4. Enter your Jira Site URL as the site host, e.g. acme.atlassian.net (https://acme.atlassian.net also works). No path, port or query string
  5. Click Connect — you are redirected to Atlassian to sign in
  6. On the consent screen choose the site that matches the URL you entered and click Accept
  7. You are redirected back to ZLH with the integration active and a first sync queued

After consent, ZLH checks that the site you entered is one the authorizing account can reach with Jira. One integration covers one site; connect each site separately.

What Gets Synced

ZLH lists users through the Jira user search API, 50 per page. Only Atlassian user accounts are imported; app and customer (portal) accounts are skipped. For each user it captures:

  • Atlassian account ID (used as the stable identifier) and email address
  • Display name
  • Active status, so deactivated accounts show as inactive

Jira does not expose login timestamps, so last-login data is not available. Users who hide their email in their Atlassian profile are imported with an account ID only and show as unmatched.

License types (which Jira products a user holds a seat for) are not collected by default. Reading them needs the Application Roles API, which Atlassian restricts to the admin scope manage:jira-configuration; many organizations decline that on a consent screen. A self-hosted deployment that wants license types can add the scope to the app in Step 1 and set JIRA_SCOPES to read:jira-user manage:jira-configuration offline_access, then click Reconnect. Without it the sync logs that application roles were unavailable and continues.

A self-hosted deployment configured with an Atlassian organization admin API key (JIRA_ORG_ID and JIRA_ORG_ADMIN_API_KEY) also backfills hidden emails and records whether each account is managed by your organization.

Troubleshooting

Issue Fix
"invalid site_url: ..." when saving Enter the site host only, e.g. acme.atlassian.net. Paths, ports and query strings are rejected, and a host that does not resolve is rejected as "failed to resolve host" — check the spelling
Atlassian shows an error instead of the consent screen The Callback URL in the developer console does not match {YOUR_ZLH_BASE_URL}/integrations/jira/callback exactly, or read:jira-user was not added under Permissions. A scope that is not on the app is refused by Atlassian before the consent screen
"Authorization failed: ..." after Atlassian redirects back The consent was declined. Retry and click Accept
"Failed to complete OAuth handshake. Please check your credentials and try again." Either the Client ID or Secret is wrong, or the site you entered is not one the authorizing account can reach with Jira. Enter the site exactly as it appears in the consent screen's site list, or authorize with an account that has Jira access on that site
Sync fails with jira: unexpected status 401 The refresh token expired or was revoked. Atlassian refresh tokens expire after 90 days without use. Click Reconnect on the integration's card on the ZLH home page
Sync fails with jira: unexpected status 403 The scope was removed from the app, or the authorizing account lost access to the site. Re-add read:jira-user in the developer console and click Reconnect
Users have no email address Those users hide their email in their Atlassian profile. They are still imported by account ID; see the enrichment note above
Users have no license type Expected with the default scopes; see "What Gets Synced" for how to enable license types
The site moved to a new URL Edit the integration, change the Site URL, then click Reconnect so syncs move to the new site