Skip to main content

Check out Port for yourselfย 

Jira Server (self-hosted)

Port's Jira Server integration allows you to model Jira Server resources in your software catalog and ingest data into them.

Jira Server Support

This integration is specifically designed for Jira Server (Self-Hosted) installations. For Jira Cloud, use Port's Jira Cloud integration.

Overviewโ€‹

This integration allows you to:

  • Watch for Jira Server object changes (create/update/delete) via scheduled resync, and automatically apply the changes to your software catalog.
  • Define self-service actions that can create/delete Jira Server objects or perform any other logic on Jira Server resources.

Supported Resourcesโ€‹

The resources that can be ingested from Jira Server into Port are listed below.
It is possible to reference any field that appears in the API responses linked below in the mapping configuration.

  • Project - Get all projects visible to the user
  • User - Search for users using username query
  • Issue - Search for issues using JQL (Jira Query Language)

Setupโ€‹

Choose one of the following installation methods:

This workflow will run the Jira Server integration and update Port in real time using scheduled polling.

Prerequisites

To install the integration, you need a Kubernetes cluster that the integration's container chart will be deployed to.

Please make sure that you have kubectl and helm installed on your machine, and that your kubectl CLI is connected to the Kubernetes cluster where you plan to install the integration.

Troubleshooting

If you are having trouble installing this integration, please refer to these troubleshooting steps.

For details about the available parameters for the installation, see the table below.

To install the integration using Helm, run the following command:

helm repo add --force-update port-labs https://port-labs.github.io/helm-charts
helm upgrade --install jira-server port-labs/port-ocean \
--set port.clientId="YOUR_PORT_CLIENT_ID" \
--set port.clientSecret="YOUR_PORT_CLIENT_SECRET" \
--set port.baseUrl="https://api.getport.io" \
--set initializePortResources=true \
--set scheduledResyncInterval=1440 \
--set integration.identifier="jira-server" \
--set integration.type="jira-server" \
--set integration.eventListener.type="POLLING" \
--set integration.config.jiraServerHost="https://jira.yourdomain.com" \
--set integration.secrets.token="YOUR_JIRA_TOKEN"

This table summarizes the available parameters for the installation.

ParameterDescriptionExampleRequired
port.clientIdYour port client idโœ…
port.clientSecretYour port client secretโœ…
port.baseUrlYour Port API URL - https://api.getport.io for EU, https://api.us.getport.io for USโœ…
integration.secrets.tokenPersonal Access Token for your Jira Server. Either token or username/password must be provided.your_jira_server_personal_access_token_hereโŒ
integration.secrets.usernameUsername for Jira Server authentication. Required if token is not provided.adminโŒ
integration.secrets.passwordPassword for Jira Server authentication. Required if token is not provided.โŒ
integration.config.jiraServerHostThe URL of your Jira Serverhttps://jira.yourdomain.comโœ…
integration.eventListener.typeThe event listener type. Read more about event listenersPOLLINGโœ…
integration.typeThe integration to be installedjira-serverโœ…
scheduledResyncIntervalThe number of minutes between each resync. When not set the integration will resync for each event listener resync event. Read more about scheduledResyncInterval1440 (24 hours)โŒ
initializePortResourcesDefault true, When set to true the integration will create default blueprints and the port App config Mapping. Read more about initializePortResourcestrueโŒ
sendRawDataExamplesEnable sending raw data examples from the third party API to port for testing and managing the integration mapping. Default is truetrueโŒ
Advanced integration configuration

For advanced configuration such as proxies or self-signed certificates, click here.

Authenticationโ€‹

The Jira Server integration supports two authentication methods:

Token authentication recommended

We recommend using Personal Access Token authentication for better security and easier management.

Personal Access Tokens provide a more secure authentication method and are the recommended approach.

  1. Create a Personal Access Token in Jira Server:

    • Log in to your Jira Server as an administrator
    • Go to Jira Administration โ†’ System โ†’ User Management
    • Select the user account that will be used for the integration
    • Click Personal Access Tokens in the left menu
    • Click Create token
    • Enter a name for the token and click Create
    • Important: Copy the token value immediately as it won't be shown again
  2. Configure the integration:

    • Use the token parameter in your integration configuration
    • Do not provide username and password when using token authentication

Option 2: Basic Authentication (Username/Password)โ€‹

Basic authentication uses a username and password combination.

  1. Use an existing Jira user account:

    • Ensure the user has appropriate permissions to read projects, issues, and users
    • The user should have Browse Projects and Browse Users permissions
  2. Configure the integration:

    • Use the username and password parameters in your integration configuration
    • Do not provide the token parameter when using basic authentication
Security Recommendation

Personal Access Tokens are more secure than username/password authentication as they can be easily revoked and have limited scope. We strongly recommend using Personal Access Tokens for production environments.

Configurationโ€‹

Port integrations use a YAML mapping block to ingest data from the third-party api into Port.

The mapping makes use of the JQ JSON processor to select, modify, concatenate, transform and perform other operations on existing fields and values from the integration API.

For the default mapping configuration and blueprints that come with this integration, see the examples page.

JQL support for issuesโ€‹

The Ocean Jira Server integration supports querying objects from the issue kind using JQL (Jira Query Language), making it possible to specifically filter the issues that are queried from Jira Server and ingested to Port.

To use JQL filtering, add to the selector object a jql key with your desired JQL query as the value. For example:

resources:
- kind: issue # JQL filtering can only be used with the "issue" kind
selector:
query: "true" # JQ boolean expression. If evaluated to false - this object will be skipped.
jql: "status != Done" # JQL query, will only ingest issues whose status is not "Done"
port:

Examplesโ€‹

To view and test the integration's mapping against examples of the third-party API responses, use the jq playground in your data sources page. Find the integration in the list of data sources and click on it to open the playground.

Additional examples of blueprints and the relevant integration configurations can be found on the jira server examples page

Alternative option - using the webhook integrationโ€‹

In this alternative approach, you can create a webhook integration between your Jira Server and Port instead of using the Ocean integration. The webhook integration will facilitate the ingestion of Jira project and issue entities into Port through real-time webhook events.

Port configurationโ€‹

Create the following blueprint definitions:

Jira project blueprint
{
"identifier": "jiraProject",
"description": "This blueprint represents a project in Jira",
"title": "Jira Project",
"icon": "Jira",
"schema": {
"properties": {
"url": {
"title": "Project URL",
"type": "string",
"format": "url"
},
"description": {
"title": "Description",
"type": "string"
},
"type": {
"title": "Type",
"type": "string"
},
"lead": {
"title": "Project Lead",
"type": "string"
},
"issueCount": {
"title": "Issue Count",
"type": "number"
}
},
"required": []
},
"mirrorProperties": {},
"calculationProperties": {},
"relations": {}
}
Jira issue blueprint
{
"identifier": "jiraIssue",
"description": "This blueprint represents a Jira issue",
"title": "Jira Issue",
"icon": "Jira",
"schema": {
"properties": {
"url": {
"title": "Issue URL",
"type": "string",
"format": "url"
},
"status": {
"title": "Status",
"type": "string"
},
"issueType": {
"title": "Issue Type",
"type": "string"
},
"priority": {
"title": "Priority",
"type": "string"
},
"assignee": {
"title": "Assignee",
"type": "string"
},
"reporter": {
"title": "Reporter",
"type": "string"
},
"creator": {
"title": "Creator",
"type": "string"
}
},
"required": []
},
"mirrorProperties": {},
"calculationProperties": {},
"relations": {
"project": {
"title": "Project",
"target": "jiraProject",
"required": false,
"many": false
}
}
}
Blueprint Properties

You may modify the properties in your blueprints depending on what you want to track in your Jira projects and issues.

Create the following webhook configuration using Port's UI

Jira webhook configuration
  1. Basic details tab - fill the following details:
    1. Title : Jira mapper;
    2. Identifier : jira_mapper;
    3. Description : A webhook configuration to map Jira projects and issues to Port;
    4. Icon : Jira;
  2. Integration configuration tab - fill the following JQ mapping:
mappings:
- blueprint: jiraProject
filter: .webhookEvent == "project_created" or .webhookEvent == "project_updated"
entity:
identifier: .project.key
title: .project.name
properties:
url: .project.self
description: .project.description
type: .project.projectTypeKey
lead: .project.lead.displayName // null
issueCount: 0
- blueprint: jiraIssue
filter: .webhookEvent | startswith("jira:issue")
entity:
identifier: .issue.key
title: .issue.fields.summary
properties:
url: .issue.self
status: .issue.fields.status.name
issueType: .issue.fields.issuetype.name
priority: .issue.fields.priority.name // null
assignee: .issue.fields.assignee.displayName // null
reporter: .issue.fields.reporter.displayName // null
creator: .issue.fields.creator.displayName // null
relations:
project: .issue.fields.project.key
note

Take note of, and copy the Webhook URL that is provided in this tab

  1. Click Save at the bottom of the page.

Create a webhook in Jiraโ€‹

  1. Log in to Jira as a user with the Administer global permission;
  2. Click the gear icon at the top right corner;
  3. Choose System;
  4. At the bottom of the sidebar on the left, under Advanced, choose WebHooks;
  5. Click on Create a WebHook
  6. Input the following details:
    1. Name - use a meaningful name such as Port Webhook;
    2. Status - be sure to keep the webhook Enabled;
    3. Webhook URL - enter the value of the url key you received after creating the webhook configuration in Port;
    4. Description - enter a description for the webhook;
    5. Issue related events - enter a JQL query in this section to filter the issues that get sent to the webhook (if you leave this field empty, all issues will trigger a webhook event);
    6. Under Issue - mark created, updated and delete;
    7. Under the Project related events section, go to Projects and mark created, updated and deleted;
  7. Click Create at the bottom of the page.
tip

In order to view the different payloads and events available in Jira webhooks, look here

Done! any change you make to a project or an issue (open, close, edit, etc.) will trigger a webhook event that Jira will send to the webhook URL provided by Port. Port will parse the events according to the mapping and update the catalog entities accordingly.

Import Jira Historical Issues (Python Script)โ€‹

In addition to real-time webhook events, you can use the following Python script to fetch existing data from the Jira Server API and ingest it to Port.

Prerequisitesโ€‹

This example utilizes the same blueprint and webhook definition from the previous section.

In addition, you require the following environment variables:

  • PORT_CLIENT_ID - Your Port client id
  • PORT_CLIENT_SECRET - Your Port client secret
  • JIRA_API_URL - Your Jira server host such as https://jira.yourdomain.com
  • JIRA_USERNAME - Your Jira username to use when accessing the Jira Software (Server) resources
  • JIRA_PASSWORD - Your Jira account password or token to use when accessing the Jira resources
Port credentials

Find your credentials using these instructions.

Use the following Python script to ingest historical Jira issues into port:

Jira Python script for historical issues
import requests
import json
import os
from requests.auth import HTTPBasicAuth

# Port API configuration
PORT_CLIENT_ID = os.getenv("PORT_CLIENT_ID")
PORT_CLIENT_SECRET = os.getenv("PORT_CLIENT_SECRET")
PORT_API_URL = "https://api.getport.io"

# Jira configuration
JIRA_API_URL = os.getenv("JIRA_API_URL")
JIRA_USERNAME = os.getenv("JIRA_USERNAME")
JIRA_PASSWORD = os.getenv("JIRA_PASSWORD")

def get_port_token():
"""Get Port access token"""
response = requests.post(
f"{PORT_API_URL}/v1/auth/access_token",
json={
"clientId": PORT_CLIENT_ID,
"clientSecret": PORT_CLIENT_SECRET
}
)
response.raise_for_status()
return response.json()["accessToken"]

def get_jira_projects():
"""Fetch all projects from Jira"""
auth = HTTPBasicAuth(JIRA_USERNAME, JIRA_PASSWORD)
response = requests.get(
f"{JIRA_API_URL}/rest/api/2/project",
auth=auth
)
response.raise_for_status()
return response.json()

def get_jira_issues(project_key):
"""Fetch all issues for a specific project"""
auth = HTTPBasicAuth(JIRA_USERNAME, JIRA_PASSWORD)
start_at = 0
max_results = 100
all_issues = []

while True:
response = requests.get(
f"{JIRA_API_URL}/rest/api/2/search",
auth=auth,
params={
"jql": f"project = {project_key}",
"startAt": start_at,
"maxResults": max_results,
"fields": "summary,status,issuetype,priority,assignee,reporter,creator,project"
}
)
response.raise_for_status()
data = response.json()

all_issues.extend(data["issues"])

if len(data["issues"]) < max_results:
break

start_at += max_results

return all_issues

def create_port_entity(entity_data, blueprint_id, port_token):
"""Create an entity in Port"""
headers = {
"Authorization": f"Bearer {port_token}",
"Content-Type": "application/json"
}

response = requests.post(
f"{PORT_API_URL}/v1/blueprints/{blueprint_id}/entities",
headers=headers,
json=entity_data
)

if response.status_code == 409:
# Entity already exists, update it
entity_identifier = entity_data["identifier"]
response = requests.put(
f"{PORT_API_URL}/v1/blueprints/{blueprint_id}/entities/{entity_identifier}",
headers=headers,
json=entity_data
)

response.raise_for_status()
return response.json()

def main():
# Get Port token
port_token = get_port_token()
print("Got Port token")

# Fetch projects from Jira
projects = get_jira_projects()
print(f"Found {len(projects)} projects")

for project in projects:
# Create project entity in Port
project_entity = {
"identifier": project["key"],
"title": project["name"],
"properties": {
"url": project["self"],
"description": project.get("description", ""),
"type": project.get("projectTypeKey", ""),
"lead": project.get("lead", {}).get("displayName", ""),
"issueCount": 0
}
}

try:
create_port_entity(project_entity, "jiraProject", port_token)
print(f"Created/updated project: {project['key']}")
except Exception as e:
print(f"Error creating project {project['key']}: {e}")

# Fetch and create issues for this project
issues = get_jira_issues(project["key"])
print(f"Found {len(issues)} issues for project {project['key']}")

for issue in issues:
issue_entity = {
"identifier": issue["key"],
"title": issue["fields"]["summary"],
"properties": {
"url": issue["self"],
"status": issue["fields"]["status"]["name"],
"issueType": issue["fields"]["issuetype"]["name"],
"priority": issue["fields"]["priority"]["name"] if issue["fields"]["priority"] else None,
"assignee": issue["fields"]["assignee"]["displayName"] if issue["fields"]["assignee"] else None,
"reporter": issue["fields"]["reporter"]["displayName"] if issue["fields"]["reporter"] else None,
"creator": issue["fields"]["creator"]["displayName"] if issue["fields"]["creator"] else None
},
"relations": {
"project": issue["fields"]["project"]["key"]
}
}

try:
create_port_entity(issue_entity, "jiraIssue", port_token)
print(f"Created/updated issue: {issue['key']}")
except Exception as e:
print(f"Error creating issue {issue['key']}: {e}")

if __name__ == "__main__":
main()

Done! you can now import historical issues from Jira into Port. Port will parse the issues according to the mapping and update the catalog entities accordingly.