API Methods

You can retrieve and set encrypted custom field values and attachments using Jira REST and Java APIs. This lets you copy your unencrypted data over to other fields or use it with third-party integrations, automations, or scripts.

You can see the most up-to-date code examples in our Encryption for Jira Examples repository

Getting encrypted custom fields from Jira's Rest API

curl -D- -u {user}:{password} -X GET -H "X-Atlassian-Token: nocheck" {Jira base url}/rest/api/2/issue/{issue id or key}


Example:

curl -D- -u admin:admin -X GET -H "X-Atlassian-Token: nocheck" http://localhost:2990/jira/rest/api/2/issue/10121

Response:

{"expand":"renderedFields,names,schema,operations,editmeta,changelog,versionedRepresentations","id":"10001","self":"http://localhost:2990/jira/rest/api/2/issue/10001","key":"TEST-2","fields":{"issuetype":{"self":"http://localhost:2990/jira/rest/api/2/issuetype/10000","id":"10000","description":"A task that needs to be done.","iconUrl":"http://localhost:2990/jira/secure/viewavatar?size=xsmall&avatarId=10318&avatarType=issuetype","name":"Tarea","subtask":false,"avatarId":10318},"components":[],"timespent":null,"timeoriginalestimate":null,"description":null,"project":{"self":"http://localhost:2990/jira/rest/api/2/project/10000","id":"10000","key":"TEST","name":"TEST","projectTypeKey":"business","avatarUrls":{"48x48":"http://localhost:2990/jira/secure/projectavatar?avatarId=10324","24x24":"http://localhost:2990/jira/secure/projectavatar?size=small&avatarId=10324","16x16":"http://localhost:2990/jira/secure/projectavatar?size=xsmall&avatarId=10324","32x32":"http://localhost:2990/jira/secure/projectavatar?size=medium&avatarId=10324"}},"fixVersions":[],"aggregatetimespent":null,"resolution":null,"timetracking":{},"archiveddate":null,"customfield_10005":null,"attachment":[],"aggregatetimeestimate":null,"resolutiondate":null,"workratio":-1,"summary":"My issue","lastViewed":"2022-10-31T10:37:43.320+0100","watches":{"self":"http://localhost:2990/jira/rest/api/2/issue/TEST-2/watchers","watchCount":1,"isWatching":true},"creator":{"self":"http://localhost:2990/jira/rest/api/2/user?username=admin","name":"admin","key":"admin","emailAddress":"admin@admin.com","avatarUrls":{"48x48":"https://www.gravatar.com/avatar/64e1b8d34f425d19e1ee2ea7236d3028?d=mm&s=48","24x24":"https://www.gravatar.com/avatar/64e1b8d34f425d19e1ee2ea7236d3028?d=mm&s=24","16x16":"https://www.gravatar.com/avatar/64e1b8d34f425d19e1ee2ea7236d3028?d=mm&s=16","32x32":"https://www.gravatar.com/avatar/64e1b8d34f425d19e1ee2ea7236d3028?d=mm&s=32"},"displayName":"admin","active":true,"timeZone":"Europe/Madrid"},"subtasks":[],"created":"2022-10-28T09:34:57.929+0200","reporter":{"self":"http://localhost:2990/jira/rest/api/2/user?username=admin","name":"admin","key":"admin","emailAddress":"admin@admin.com","avatarUrls":{"48x48":"https://www.gravatar.com/avatar/64e1b8d34f425d19e1ee2ea7236d3028?d=mm&s=48","24x24":"https://www.gravatar.com/avatar/64e1b8d34f425d19e1ee2ea7236d3028?d=mm&s=24","16x16":"https://www.gravatar.com/avatar/64e1b8d34f425d19e1ee2ea7236d3028?d=mm&s=16","32x32":"https://www.gravatar.com/avatar/64e1b8d34f425d19e1ee2ea7236d3028?d=mm&s=32"},"displayName":"admin","active":true,"timeZone":"Europe/Madrid"},"customfield_10000":null,"aggregateprogress":{"progress":0,"total":0},"priority":{"self":"http://localhost:2990/jira/rest/api/2/priority/3","iconUrl":"http://localhost:2990/jira/images/icons/priorities/medium.svg","name":"Medium","id":"3"},"customfield_10100":"sample value","customfield_10001":null,"customfield_10002":[],"customfield_10003":null,"customfield_10102":null,"labels":[],"customfield_10004":null,"environment":null,"timeestimate":null,"aggregatetimeoriginalestimate":null,"versions":[],"duedate":null,"progress":{"progress":0,"total":0},"comment":{"comments":[],"maxResults":0,"total":0,"startAt":0},"issuelinks":[],"votes":{"self":"http://localhost:2990/jira/rest/api/2/issue/TEST-2/votes","votes":0,"hasVoted":false},"worklog":{"startAt":0,"maxResults":20,"total":0,"worklogs":[]},"assignee":null,"archivedby":null,"updated":"2022-10-31T10:37:43.188+0100","status":{"self":"http://localhost:2990/jira/rest/api/2/status/1","description":"The issue is open and ready to start working on it.","iconUrl":"http://localhost:2990/jira/images/icons/statuses/open.png","name":"Open","id":"1","statusCategory":{"self":"http://localhost:2990/jira/rest/api/2/statuscategory/2","id":2,"key":"new","colorName":"default","name":"To do"}}}}

Where our encrypted custom field value is: "customfield_10100":"sample value"

If the user does not have permission to access encrypted custom fields, then the response returns the encrypted values. For instance: "customfield_10100":"Lt1pEM0Uq04PhMK+SBj7og=="

Setting encrypted custom fields from Jira's Rest API

curl -D- -u {user}:{password} -X PUT -H "X-Atlassian-Token: nocheck" {Jira base url}/rest/api/2/issue/{issue id or key} -H "Content-Type: application/json" -d '{"fields": {"{custom field ID}":"{new custom field value}"}}'

Example:

curl -D- -u admin:admin -X PUT -H "X-Atlassian-Token: nocheck" http://localhost:2990/jira/rest/api/2/issue/TEST-2 -H "Content-Type: application/json" -d '{"fields": {"customfield_10100":"Value from Rest"}}'

If the user does not have permission to access encrypted custom fields, then the custom field is not updated.

Getting encrypted custom fields from Jira's Java API

This is an example in Groovy for a ScriptRunner's script:

groovy
import com.atlassian.jira.component.ComponentAccessor def issueManager = ComponentAccessor.issueManager def customFieldManager = ComponentAccessor.customFieldManager def issueKey = 'TEST-2' def issue = issueManager.getIssueObject(issueKey) assert issue: "Could not find issue with key $issueKey" def cFieldName = "EncryptedSingleLine" def cField = customFieldManager.getCustomFieldObjectByName(cFieldName) assert cField: "Could not find custom field with name $cFieldName" issue.getCustomFieldValue(cField)

If the user does not have permission to access to encrypted custom fields, then the response returns the encrypted values.

Setting encrypted custom fields from Jira's Java API

This method to set the custom field value doesn't update the issue's change log. So the corresponding history record is not generated and doesn't appear in the history tab.

This is an example in Groovy for a ScriptRunner's script:

groovy
import com.atlassian.jira.component.ComponentAccessor import com.atlassian.jira.issue.ModifiedValue import com.atlassian.jira.issue.util.DefaultIssueChangeHolder def issueManager = ComponentAccessor.issueManager def customFieldManager = ComponentAccessor.customFieldManager def issueKey = 'TEST-2' def issue = issueManager.getIssueObject(issueKey) assert issue: "Could not find issue with key $issueKey" def cFieldName = "EncryptedSingleLine" def cField = customFieldManager.getCustomFieldObjectByName(cFieldName) assert cField: "Could not find custom field with name $cFieldName" def newValue = "New value from script" ModifiedValue modifiedValue = new ModifiedValue(issue.getCustomFieldValue(cField), newValue) cField.updateValue(null, issue, modifiedValue, new DefaultIssueChangeHolder())

If the user does not have permission to access encrypted custom fields, then the custom field is not updated.

Best Practice

It is possible to set custom field values using the issue.setCustomFieldValue() and issueManager.updateIssue() methods. But for this is incompatible with E4J, so we strongly recommend not using it.

Getting attachments from Jira's Rest API

curl -D- -u {user}:{password} -X GET -H "X-Atlassian-Token: nocheck" {Jira base url}/rest/api/2/attachment/{attachment id}


Example:

curl -D- -u admin:admin -X GET -H "X-Atlassian-Token: nocheck" http://localhost:2990/jira/rest/api/2/attachment/10000

Response:
{"self":"http://localhost:2990/jira/rest/api/2/attachment/10000","filename":"parrots.png","author":{"self":"http://localhost:2990/jira/rest/api/2/user?username=admin","key":"admin","name":"admin","avatarUrls":{"48x48":"https://www.gravatar.com/avatar/64e1b8d34f425d19e1ee2ea7236d3028?d=mm&s=48","24x24":"https://www.gravatar.com/avatar/64e1b8d34f425d19e1ee2ea7236d3028?d=mm&s=24","16x16":"https://www.gravatar.com/avatar/64e1b8d34f425d19e1ee2ea7236d3028?d=mm&s=16","32x32":"https://www.gravatar.com/avatar/64e1b8d34f425d19e1ee2ea7236d3028?d=mm&s=32"},"displayName":"admin","active":true},"created":"2022-10-31T11:05:36.375+0100","size":27734,"mimeType":"image/png","properties":{},"content":"http://localhost:2990/jira/secure/attachment/10000/parrots.png","thumbnail":"http://localhost:2990/jira/secure/thumbnail/10000/thumb_10000.png"}


The "content" attribute contains the URL to download the actual file:
"content":"http://localhost:2990/jira/secure/attachment/10000/parrots.png"

Example with cURL:

curl -D- -u admin:admin -X GET -H "X-Atlassian-Token: nocheck" http://localhost:2990/jira/secure/attachment/10000/parrots.png --output /Users/antonio/Desktop/parrots.png

If the user does not have permission to access attachments and is not the owner of the requested attachment, then a padlock picture is returned instead of the actual file.

Setting attachments from Jira's Rest API

curl -D- -u {user}:{password} -X POST -H "X-Atlassian-Token: nocheck" -F "file=@{Path to file}" {Jira base url}/rest/api/2/issue/{issue id or key}/attachments


Example:

curl -D- -u admin:admin -X POST -H "X-Atlassian-Token: nocheck" -F "file=@/Users/antonio/Desktop/kittens.png" http://localhost:2990/jira/rest/api/2/issue/TEST-1/attachments

Add Attachment

groovy
/** * Replace `JIRA_URL`, `JIRA_USERNAME`, `JIRA_PASSWORD`, `ISSUE_KEY`, `ATTACHMENT_PATH` and 'FILE_NAME' with the correct * values for your Jira instance. * * This script adds an attachment to a given Jira issue. */ import java.nio.charset.StandardCharsets import java.nio.file.Files def jiraUrl = 'JIRA_URL' def username = 'JIRA_USERNAME' def password = 'JIRA_PASSWORD' def issueKey = 'ISSUE_KEY' def attachmentPath = 'ATTACHMENT_PATH' def fileName = 'FILE_NAME' def url = new URL("${jiraUrl}/rest/api/2/issue/${issueKey}/attachments") def auth = "${username}:${password}".getBytes().encodeBase64().toString() def boundary = "FormBoundary${UUID.randomUUID().toString()}" def fileBytes = Files.readAllBytes(new File(attachmentPath + fileName).toPath()) def connection = url.openConnection() as HttpURLConnection connection.setDoOutput(true) connection.setRequestMethod('POST') connection.setRequestProperty('X-Atlassian-Token', 'no-check') connection.setRequestProperty('Accept', 'application/json') connection.setRequestProperty('Content-Type', "multipart/form-data; boundary=${boundary}") connection.setRequestProperty('Authorization', "Basic ${auth}") def outputStream = connection.getOutputStream() def CR = '\r' def LF = '\n' def writer = new PrintWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8), true) writer.print("--${boundary}${CR}${LF}") writer.print("Content-Disposition: form-data; name=\"file\"; filename=\"${fileName}\"${CR}${LF}") writer.print("Content-Type: application/octet-stream${CR}${LF}") writer.print("${CR}${LF}") writer.flush() outputStream.write(fileBytes) outputStream.flush() writer.print("${CR}${LF}") writer.print("--${boundary}--${CR}${LF}") writer.close() def responseCode = connection.getResponseCode() if ( responseCode == 200 ) { println 'Attachment has been uploaded successfully' println "Response headers: ${connection.getHeaderFields()}" println "Response body: ${connection.getContent()}" } else { println "Failed to upload file. Response code: ${responseCode}" println "Response message: ${connection.getContent()}" }

Get Custom Field

groovy
/** * Replace `JIRA_URL`, `JIRA_USERNAME`, `JIRA_PASSWORD`, `ISSUE_KEY`, and `CUSTOM_FIELD_ID` with the correct values for * your Jira instance. * * This script gets the Jira issue and fetches the value of the specific custom field. */ import groovy.json.JsonSlurper def jiraUrl = 'JIRA_URL' def username = 'JIRA_USERNAME' def password = 'JIRA_PASSWORD' def issueKey = 'ISSUE_KEY' def customFieldId = 'CUSTOM_FIELD_ID' def url = new URL("${jiraUrl}/rest/api/2/issue/${issueKey}") def auth = "${username}:${password}".getBytes().encodeBase64().toString() def connection = url.openConnection() as HttpURLConnection connection.setRequestMethod('GET') connection.setRequestProperty('Content-Type', 'application/json') connection.setRequestProperty('Authorization', "Basic ${auth}") def responseCode = connection.getResponseCode() if ( responseCode == 200 ) { def responseContent = new JsonSlurper().parse(connection.getInputStream()) println "Issue Key: ${responseContent.key}" println "Custom Field Value: ${responseContent.fields."customfield_${customFieldId}"}" } else { println "GET request failed with response code: ${responseCode}" println "Response message: ${connection.getResponseMessage()}" }


Get Issue with Custom Fields

groovy
/** * Replace `JIRA_URL`, `JIRA_USERNAME`, `JIRA_PASSWORD`, and `ISSUE_KEY` with the correct values for your Jira instance. * * This script fetches an issue from a Jira server given an issue key and prints the issue key, summary, and description * to the console. The issue includes encrypted custom fields. */ import groovy.json.JsonSlurper def jiraUrl = 'JIRA_URL' def username = 'JIRA_USERNAME' def password = 'JIRA_PASSWORD' def issueKey = 'ISSUE_KEY' def url = new URL("${jiraUrl}/rest/api/2/issue/${issueKey}") def auth = "${username}:${password}".getBytes().encodeBase64().toString() def connection = url.openConnection() as HttpURLConnection connection.setRequestMethod('GET') connection.setRequestProperty('Content-Type', 'application/json') connection.setRequestProperty('Authorization', "Basic ${auth}") def responseCode = connection.getResponseCode() if ( responseCode == 200 ) { def responseContent = new JsonSlurper().parse(connection.getInputStream()) println "Issue Key: ${responseContent.key}" println "Summary: ${responseContent.fields.summary}" println "Description: ${responseContent.fields.description}" println "Description: ${responseContent}" } else { println "GET request failed with response code: ${responseCode}" println "Response message: ${connection.getResponseMessage()}" }


Update Custom Field

groovy
/** * Replace `JIRA_URL`, `JIRA_USERNAME`, `JIRA_PASSWORD`, `ISSUE_KEY`, `CUSTOM_FIELD_ID`, and `NEW_VALUE` with the * correct values for your Jira instance. * * This script updates the specified custom field for a given Jira issue. */ import groovy.json.JsonOutput def jiraUrl = 'JIRA_URL' def username = 'JIRA_USERNAME' def password = 'JIRA_PASSWORD' def issueKey = 'ISSUE_KEY' def customFieldId = 'CUSTOM_FIELD_ID' def newValue = 'NEW_VALUE' def url = new URL("${jiraUrl}/rest/api/2/issue/${issueKey}") def auth = "${username}:${password}".getBytes().encodeBase64().toString() def connection = url.openConnection() as HttpURLConnection connection.setRequestMethod('PUT') connection.setRequestProperty('Content-Type', 'application/json') connection.setRequestProperty('Authorization', "Basic ${auth}") connection.setDoOutput(true) def payload = JsonOutput.toJson([fields: [(customFieldId): (newValue)]]) connection.getOutputStream().withWriter("UTF-8") { writer -> writer.write(payload) } def responseCode = connection.getResponseCode() if ( responseCode == 204 ) { println "Issue updated successfully!" } else { println "Failed to update issue. Response code: ${responseCode}" println "Response message: ${connection.getResponseMessage()}" }
On this page