Forums

Articles
Create
cancel
Showing results for 
Search instead for 
Did you mean: 

How do I upload attachment to JIRA Issue via REST API?

Loïc GRIVEAU
Contributor
January 8, 2014

Is it possible to upload attachment in java using REST API without using cURL ?

Is it possible to upload a file using REST API BROWSER ?

11 answers

1 accepted

7 votes
Answer accepted
Loïc GRIVEAU
Contributor
January 9, 2014

Here my code for upload and download attachment :

public boolean addAttachmentToIssue(String issueKey, String fullfilename) throws IOException{

		CloseableHttpClient httpclient = HttpClients.createDefault();
		
		HttpPost httppost = new HttpPost(jira_attachment_baseURL+"/api/latest/issue/"+issueKey+"/attachments");
		httppost.setHeader("X-Atlassian-Token", "nocheck");
		httppost.setHeader("Authorization", "Basic "+jira_attachment_authentication);
		
		File fileToUpload = new File(fullfilename);
		FileBody fileBody = new FileBody(fileToUpload);
		
		HttpEntity entity = MultipartEntityBuilder.create()
				.addPart("file", fileBody)
				.build();
		
		httppost.setEntity(entity);
        String mess = "executing request " + httppost.getRequestLine();
        logger.info(mess);
        
        CloseableHttpResponse response;
		
        try {
			response = httpclient.execute(httppost);
		} finally {
			httpclient.close();
		}
        
		if(response.getStatusLine().getStatusCode() == 200)
			return true;
		else
			return false;

	}
	
	public boolean getAttachmentFromIssue(String contentURI, String fullfilename) throws IOException {
        
		CloseableHttpClient httpclient = HttpClients.createDefault();
        
        try {
            HttpGet httpget = new HttpGet(contentURI);
            httpget.setHeader("Authorization", "Basic "+jira_attachment_authentication);
                        
            System.out.println("executing request " + httpget.getURI());

            CloseableHttpResponse response = httpclient.execute(httpget);
            
            int status = response.getStatusLine().getStatusCode();
            if (status >=200 && status < 300) {
            	HttpEntity entity = response.getEntity();
            	if (entity.isStreaming()) {
            		byte data[] = EntityUtils.toByteArray(entity);
            		FileOutputStream fout = new FileOutputStream(new File(fullfilename));
            		fout.write(data);
            		fout.close();
            	}
            }
		} finally {
            httpclient.close();
        }
        
        return true;
	}

jira_attachment_authentication is define elsewhere as :

jira_attachment_authentication = new String(org.apache.commons.codec.binary.Base64.encodeBase64((user+":"+pass).getBytes()));

J D
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
November 5, 2014

Can you show me your which is getting the file? File fileToUpload = new File(fullfilename); FileBody fileBody = new FileBody(fileToUpload);

Yagnesh Bhat August 11, 2016

Loïc GRIVEAU, if I try to use the same code to move attachments from one JIRA instance to another, it gives 415 error. : 415 Unsupported Media Type.

 

Any idea?

Like 2 people like this
Murugavel Parthasarathy
I'm New Here
I'm New Here
Those new to the Atlassian Community have posted less than three times. Give them a warm welcome!
January 11, 2017

Hi, can you pls share the jar/lib that you used in your program?

Guillermo Meert
I'm New Here
I'm New Here
Those new to the Atlassian Community have posted less than three times. Give them a warm welcome!
February 22, 2019

you save my day, thanks!!

5 votes
Danut M _StonikByte_
Atlassian Partner
February 15, 2019

I managed to make it work with PostMan.

Header must contain:

Content-Type: multipart/form-data

X-Atlassian-Token: no-check 

PM_Headers.jpg

Body must be of type "form-data" and must contain a key named "file" with value a specified file (I had to use the file picker, see the picture).

PM_Body.jpg

Ramandeep Singh Nagi
I'm New Here
I'm New Here
Those new to the Atlassian Community have posted less than three times. Give them a warm welcome!
July 14, 2020

Thanks, this worked for me.

parthiban.selvaraj October 19, 2020

Hi @Danut M _StonikByte_  , @Ramandeep Singh Nagi ,

 

I tried to attach the attachment via postman by using your above Info. When I used Content-Type as "multipart/form-data" am getting the below error.

error.PNG

But I removed Content-Type and my postman was successful.

success.PNG

 

Did I missed anything with "Content-Type" ?

 

Regards,

Parthiban

Ramandeep Singh Nagi
I'm New Here
I'm New Here
Those new to the Atlassian Community have posted less than three times. Give them a warm welcome!
November 1, 2020

Hello Parthiban,

 

I used the following settings in my Postman:

 

POST Url:

https://jira.your.url.com/rest/api/latest/issue/ABCD-1234/attachments

Headers:

Content-Type: multipart/form-data,

X-Atlassian-Token: no-check,

charset: UTF-8,

Accept-Encoding: gzip, deflate, br

Body -> form-data:

file: <give path to your file to be attached>

 

I hope this helps.

 

Regards,

Ramandeep Singh

Ana Dimitrioglo
I'm New Here
I'm New Here
Those new to the Atlassian Community have posted less than three times. Give them a warm welcome!
November 6, 2020

Thanks! Worked like a charm.

Chris Fortmueller
Contributor
March 29, 2021

@Ramandeep Singh Nagi Could you kindly post a screenshot of your solution?

2 votes
Brian Richardson
I'm New Here
I'm New Here
Those new to the Atlassian Community have posted less than three times. Give them a warm welcome!
July 19, 2017

This works for me:

 

  const auth = 'Basic ' + new Buffer(props['jiraAppUserName'] + ':' + props['jiraAppPassword']).toString('base64');
var options = {
url: 'https://JIRAUAT.xx.xx/rest/api/latest/issue/XEA-1255/attachments',
headers: {
'Authorization': auth,
'X-Atlassian-Token': 'nocheck'
}
};

var r = request.post(options, function (err, res, body) {
if (err) {
console.error(err);
resOut.status(500).json({
messages: 'outch',
obj: {}
});
} else {
console.log('Upload successful! Server responded with:', body);
resOut.status(200).json({
messages: 'successfully updated jira ticket',
obj: {}
});
}
}
);

var form = r.form();
form.append('file', fs.createReadStream('./somefile.png'));

 

jiracloud1 jira
I'm New Here
I'm New Here
Those new to the Atlassian Community have posted less than three times. Give them a warm welcome!
December 28, 2017

Can you please attach the complete file/code?

Like Ian Keller likes this
1 vote
Ivo
I'm New Here
I'm New Here
Those new to the Atlassian Community have posted less than three times. Give them a warm welcome!
May 21, 2019
HttpRequestFactory requestFactory = new NetHttpTransport().createRequestFactory(parameters);

MultipartContent content = new MultipartContent().setMediaType(
new HttpMediaType("multipart/form-data").setParameter("boundary", "__END_OF_PART__"));


for(Attachment attachment : attachments) {
File attachmentFile = ComponentAccessor.getAttachmentManager().
streamAttachmentContent(attachment, new FileInputStreamConsumer(attachment.getFilename()));

String mimeType = URLConnection.guessContentTypeFromName(attachmentFile.getName());

FileContent fileContent = new FileContent(mimeType, attachmentFile);
MultipartContent.Part part = new MultipartContent.Part(fileContent);
part.setHeaders(new HttpHeaders().set(
"Content-Disposition",
String.format("form-data; name=\"file\"; filename=\"%s\"", attachmentFile.getName())));
content.addPart(part);
}


HttpRequest request = requestFactory.buildPostRequest(jiraUrl, content);
request.getHeaders().set("X-Atlassian-Token", "no-check");
return request.execute();

Java code using google-http to POST attachments to /rest/api/2/issue/{issueIdOrKey}/attachments using OAuth. Still trying to figure out format for posting attachments on issue create.

Saurabh_Gupta
I'm New Here
I'm New Here
Those new to the Atlassian Community have posted less than three times. Give them a warm welcome!
July 18, 2019 edited

What will be body for this endpoint i am using postman and it is not working for me : /rest/api/2/issue/{issueIdOrKey}/attachments

can anyone share postman body.

LostInMadness Forever December 2, 2019

neither for me.... i have try all :(

Dobrivoje Prtenjak March 24, 2020

Hi guys ! I've managed to POST attachment via Postman. An example :
https://jira-dev.server_url.com/rest/api/2/issue/NOC-618/attachments
Everything works fine.

However, I need to implement via Java service which use OAuth1.
First, there is a need to manipulate header, that is, to insert

"X-Atlassian-Token", "no-check"

and then, to upload actual input streams.

Any ideas ?

mcander
I'm New Here
I'm New Here
Those new to the Atlassian Community have posted less than three times. Give them a warm welcome!
March 24, 2020

My example has it shown 

request.getHeaders().set("X-Atlassian-Token", "no-check");

What is the problem? 

Dobrivoje Prtenjak March 24, 2020

Hi ! Thanks for a quick response !
Well, I've done authentication via OAuth, from a Jira tutorial, and have this method for post request, and i don't know how to manipulate header :

public HttpResponse executePrimitivePostRequest(@NonNull String url, @NonNull GenericData contentGenericData) {
String apiCallUrlPath = JIRA_HOME_URL + url;

try {
OAuthParameters parameters = jiraOAuthClient.getParameters( JIRA_ACCESS_TOKEN, JIRA_SECRET_KEY, JIRA_CONSUMER_KEY, JIRA_PRIVATE_KEY );
HttpContent content = new JsonHttpContent( new JacksonFactory(), contentGenericData );
HttpResponse response = postResponseFromUrl( parameters, new GenericUrl( apiCallUrlPath ), content );

return response;
} catch (HttpResponseException hre) {
String errMsg = "Executing Post Request Error. " + hre;
LOGGER.log( Level.SEVERE, errMsg, hre );
throw new RuntimeException( errMsg, hre );
} catch (Exception e) {
String errMsg = "Executing Get Request, no result.";
LOGGER.log( Level.INFO, errMsg, e );
throw new RuntimeException( errMsg, e );
}
}
1 vote
Aleksander Mierzwicki _
Atlassian Team
Atlassian Team members are employees working across the company in a wide variety of roles.
January 8, 2014

Yes it's possible. For example JIRA REST Java Client does that: https://bitbucket.org/atlassian/jira-rest-java-client/src/bd758b52f53978033bdd0d8071edd75d7bdcc607/core/src/main/java/com/atlassian/jira/rest/client/internal/async/AsynchronousIssueRestClient.java?at=master#

You'll have to send multipart request - the code will depend on HTTP client that you use.

There is already answer for that question here: http://stackoverflow.com/questions/18631361/add-attachment-to-jira-via-rest-api

Loïc GRIVEAU
Contributor
January 8, 2014

I copy paste the answer from the stackoverflow.comlink, but some dependencies are missing (MultipartEntity, HttpEntity, ...)

Can you help me ?

RambanamP
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
January 9, 2014

you can download dependencies from here

http://hc.apache.org/downloads.cgi

RambanamP
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
January 9, 2014

@Loïc GRIVEAU, are you able to attach to issues using sample in stackoverflow link?

if yes then can you sahre your code here?

J D
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
November 5, 2014

+1

Yagnesh Bhat
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
August 11, 2016

@Aleksander Mierzwicki, is there a way we can copy ALL attachments from one JIRA issue in one server to another JIRA issue in another server? I have been trying all the code snippets given for this question and am getting 415 Unsupported media type error.

0 votes
Dobrivoje Prtenjak March 30, 2021

I've done the other way, by pure "spring-like" flow so to speak.
Actually, I have a complete git project, however, for the attachment, I still need to add functionality, however, I'll give you fast and dirty solution until I add in project.

For details please visit : https://github.com/dobrivoje/jiraintegration


Here is :

REST :
..

@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.APPLICATION_JSON)
@Path("createIssueWithAttachment")
ResponseEntity<ResponseIssueCreationDto> createIssueWithAttachmentStreamForSupport(
@FormDataParam("summary") String summary,
@FormDataParam("nmeTeam") @NonNull String nmeTeam,
@FormDataParam("handOverDate") @NonNull Date handOverDate,
@FormDataParam("supportType") @NonNull String supportType,
@FormDataParam("description") String description,
@FormDataParam("siteAddress") String siteAddress,
@FormDataParam("siteContacts") String siteContacts,
@FormDataParam("topology") String topology,

@FormDataParam("file") InputStream attachment,
@FormDataParam("file") FormDataContentDisposition fileDetail,
@FormDataParam("file") FormDataBodyPart body);

...

 

REST implementation :

@Override
public ResponseEntity<ResponseIssueCreationDto> createIssueWithAttachmentStreamForSupport(
String summary, String nmeTeam,
Date handOverDate, String supportType, String description,
String siteAddress, String siteContacts, String topology,
InputStream attachment,
FormDataContentDisposition fileDetail,
FormDataBodyPart body) {

return ResponseEntity.status( HttpStatus.OK )
.contentType( APPLICATION_JSON )
.body(
service.createNocIssueWithStreamAttachmentForSupport(
supportType, nmeTeam, handOverDate, siteAddress,
siteContacts, topology, description,
summary, attachment, fileDetail, body ) );
}

 

Custom service (interface) :

ResponseIssueCreationDto createIssueWithStreamAttachmentForSupport(@NonNull String supportType, @NonNull String nmeTeam,
Date handOverDate, String siteAddress,
String siteContacts, String topology,
String description, String summary,
InputStream attachment,
FormDataContentDisposition fileDetail,
FormDataBodyPart body);


Custom service implementation :

@Override
public ResponseIssueCreationDto createIssueWithStreamAttachmentForSupport(String supportType, String nmeTeam,
Date handOverDate, String siteAddress,
String siteContacts, String topology,
String description, String summary,
InputStream attachment,
FormDataContentDisposition fileDetail,
FormDataBodyPart body) {

ResponseIssueCreationDto newIssue = createBasicIssueWithoutAttachmentForSupport(
supportType, nmeTeam, handOverDate, siteAddress, siteContacts, topology, description, summary );

addAttachmentToIssue( attachment, fileDetail, body, newNocIssue.getIssueKey() );

return newNocIssue;
}

 

@Override
public ResponseIssueCreationDto createBasicIssueWithoutAttachmentForSupport(
String supportType, String nmeTeam, Date handOverDate, String siteAddress,
String siteContacts, String topology, String description, String summary) {

//<editor-fold desc="Stylized error message, for only missing mandatory fields">
boolean isErrSupportType = supportType == null;
boolean isErrNmeTeam = !NocNMETeam.isValidTeam( nmeTeam );
boolean isErrHandOverDate = handOverDate == null;
String errNew = (isErrSupportType ? "Support type, " : "")
+ (isErrNmeTeam ? "NME team, " : "")
+ (isErrHandOverDate ? "Handover date " : "");
String errorMessage = errNew.substring( 0, ((isErrSupportType || isErrNmeTeam) && !isErrHandOverDate) ?
errNew.length() - 2 : errNew.length() ).concat( " must be defined." );
//</editor-fold>

Commons.ensureNonNullsWithMessageFor( errorMessage, supportType, nmeTeam, handOverDate );

//<editor-fold desc="Service desk id, and Request type id">
ServiceDesksDto serviceDeskProjectDto = getAllServiceDesks().orElseThrow( () -> new JiraAllServiceDesksException( errorMessage ) );

ServiceDeskProjectDto sdp = serviceDeskProjectDto
.getValues()
.stream()
.filter( p -> JiraNocProjectKey.equalsIgnoreCase( p.getProjectKey() ) )
.findFirst()
.orElseThrow( () -> new JiraServiceDeskProjectException( errorMessage ) );
String projectIdStr = Optional.ofNullable( sdp.getId() ).orElseThrow( RuntimeException::new );

ServiceDesksRequestTypeDto serviceDesksReqTypeDto = getServiceDeskWithRequestTypeForDesk( Long.valueOf( projectIdStr ) )
.orElseThrow( () -> new JiraServiceDeskRequestTypeException( errorMessage ) );
ServiceDeskRequestTypeValueItemDto srvDesksReqTypeValDto = serviceDesksReqTypeDto
.getValues()
.stream()
.filter( f -> projectIdStr.equals( f.getServiceDeskId() ) )
.filter( n -> JiraNocSupport.equalsIgnoreCase( n.getName() ) )
.findFirst()
.orElseThrow( () -> new JiraServiceDeskRequestTypeValueException( errorMessage ) );
//</editor-fold>

GenericData rootNodeResult = new GenericData();
rootNodeResult.put( ServiceDeskId, projectIdStr );
rootNodeResult.put( RequestTypeId, srvDesksReqTypeValDto.getId() );

GenericData childrenRequestFieldValues = new GenericData();

Date hoDate3BDays = DateUtil.getEndBusinessDayFor( handOverDate, 3 );
String hoDate = new SimpleDateFormat( JIRA_MISTERY_DATETIME_PATTERN2 ).format( hoDate3BDays );
childrenRequestFieldValues.put( REQIRED_BY_DATE, hoDate );

childrenRequestFieldValues.put( SITE_ADDRESS, Commons.getFieldWithValidLengthOf255( siteAddress ) );
childrenRequestFieldValues.put( SITE_CONTACTS, siteContacts );
childrenRequestFieldValues.put( TOPOLOGY, topology );
childrenRequestFieldValues.put( SUMMARY, summary );
childrenRequestFieldValues.put( DESCRIPTION, description );

GenericData childReqNMETeam = new GenericData();
try {
childReqNMETeam.put( "value", NocNMETeam.getValidCode( nmeTeam ) );
childrenRequestFieldValues.put( NME_TEAM, childReqNMETeam );
} catch (UnsupportedOperationException nte) {
throw new JiraNOCTeamException( NocNMETeam.getValidTeams(), JIRA_HOME_URL, JiraNocReqCustPortalId, JiraNocReqCustomerPortalCreateId );
}

GenericData childReqSupportType = new GenericData();

try {
childReqSupportType.put( "value", NocSupportType.getValidCodeFor( supportType ) );
childrenRequestFieldValues.put( SUPPORT_TYPE, childReqSupportType );
} catch (UnsupportedOperationException nst) {
throw new JiraNOCSupportTypeException( NocSupportType.getValidTypes(), JIRA_HOME_URL, JiraNocReqCustPortalId, JiraNocReqCustomerPortalCreateId );
}

rootNodeResult.put( RequestFieldValues, childrenRequestFieldValues );

return jiraClient.executeBasicPost( ResponseIssueCreationDto.class, apiCallIssueCreateByRequestType, rootNodeResult, true );
}

 

This is what you actually need :

@Override
public List<ResponseItemAttachmentDto> addAttachmentToIssue(InputStream inputStream, FormDataContentDisposition fileDetail,
FormDataBodyPart body, @NonNull String issueKey) {

String urlParamCall = MessageFormat.format( jiraAddAttachmentToIssueKey, issueKey );

GenericData rootNodeResult = new GenericData();
rootNodeResult.put( ATTACHMENT, new AttachmentInfoHolderDto( inputStream, fileDetail, body ) );

GenericData headers = new GenericData();
headers.put( "X-Atlassian-Token", "no-check" );

return jiraClient.executePostExpectingList( ResponseItemAttachmentDto.class, urlParamCall,
headers, rootNodeResult, true );
}
0 votes
CMC Consulting September 28, 2020

Hello, just facing problem with UTF-8 characters in file name.
When uploading with postman, like in example everything is fine, but when uploading by java API, german umalut characters are converted as ???? 
Any suggestion?

0 votes
Dan Dickinson May 14, 2020 edited

Here's a working method from a Python 3.x module. The key things that aren't spelled out in many solutions:

  • all file data must be read as binary data, even plain text files
  • the multipart boundary string need not be anything fancy, but it must be a string that is unlikely to occur in the file data
  • multipart lines are separated by Carriage Return + Line Feed
  • all the multipart strings must be converted to binary, then wrapped around the binary file contents
  • when calculating "Content-Length", take the length of the entire multipart form, not just the length of the file contents
def add_attachment(self, path):
    '''Upload a file attachment from a local file path.
    '''
    error_messages = []
    try:
        f = open(path, 'rb'# all files, even plain text, must be read as binary data
        file_contents = f.read()
        f.close()
    except:
        error_messages.append('cannot read ' + path)

    if not error_messages:
        # create multipart/form-data as defined in RFC 1867 (see: https://www.ietf.org/rfc/rfc1867.txt)
        boundary = binascii.hexlify(os.urandom(16)).decode('ascii')
        separator = '\r\n' # CRLF is the standard separator in multipart/form-data
        # multipart/form-data consists of: prefix + file contents + suffix
        prefix = '--{}{}'.format(boundary, separator)
        prefix += 'Content-Disposition: form-data; name="file"; filename="{}"{}'.format(os.path.basename(path), separator)
        prefix += 'Content-Type: application/octet-stream{}'.format(separator)
        prefix += separator
        suffix = separator + '--{}--{}'.format(boundary, separator)

        # convert the prefix and suffix text to binary, and then join them around the binary file contents
        prefix = prefix.encode('utf-8')
        suffix = suffix.encode('utf-8')
        data = b''.join([prefix, file_contents, suffix])

        headers = {}
        headers['Content-Type'] = 'multipart/form-data; boundary={}'.format(boundary)
        headers['X-Atlassian-Token'] = 'no-check'
        headers['Content-Length'] = str(len(data)) # length must include the entire multipart/form-data, not just the file contents

        api = 'api/2/issue/' + self.key + '/attachments'
        (status, response) = self._session._call_api(api, headers=headers, data=data)
        if not (status >= 200 and status <= 299):
            error_messages += standard_errors(status, response)

    return error_messages

 

Lily Tran July 13, 2020

Hello;

Do you have sample code for downloading all attachments of all Jira issues reported in a Jira project? 

Thank you;

Lily

0 votes
Seema Itagi January 8, 2019

HttpPost postRequest = new HttpPost("URL+Post REST API");

does this mean like this

HttpPost postRequest = new HttpPost("https:/abc.atlassian.net/rest/api/2/issue+https://abc.atlassian.net/browse/MSAM-42?filter=-4");

0 votes
Sagar Kalburgi August 5, 2015

THIS CODE WORKS:

 

public class JiraRest {

public static void main(String[] args) throws ClientProtocolException, IOException
{
String pathname= "<Full path name of the attachment file>";
File fileUpload = new File(pathname);

HttpClient httpClient = HttpClientBuilder.create().build();
HttpPost postRequest = new HttpPost("URL+Post REST API");
BASE64Encoder base=new BASE64Encoder();
String encoding = base.encode ("username:password".getBytes());
postRequest.setHeader("Authorization", "Basic " + encoding);
postRequest.setHeader("X-Atlassian-Token","nocheck");

MultipartEntityBuilder entity=MultipartEntityBuilder.create();
entity.addPart("file", new FileBody(fileUpload));
postRequest.setEntity( entity.build());
HttpResponse response = httpClient.execute(postRequest);
}
}


Required JARs:

All JARs in lib folder of httpcomponents-client-4.5-bin and sun.misc.BASE64Decoder.jar

Test
I'm New Here
I'm New Here
Those new to the Atlassian Community have posted less than three times. Give them a warm welcome!
October 27, 2018

Awesome. This worked perfectly..

Natarajan Senthil Kumar
I'm New Here
I'm New Here
Those new to the Atlassian Community have posted less than three times. Give them a warm welcome!
November 21, 2018

Where is the ticket URL

?

Sagar Kalburgi November 22, 2018

Sorry I posted this answer more than 3 years back, I don't remember anything as of now 

0 votes
RambanamP
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
January 9, 2014

if you want to do it through perl then try with this

https://metacpan.org/pod/JIRA::Client::Automated#attach_file_to_issue

Suggest an answer

Log in or Sign up to answer
TAGS
atlassian, atlassian government cloud, fedramp, webinar, register for webinar, atlassian cloud webinar, fedramp moderate offering, work faster with cloud

Unlocking the future with Atlassian Government Cloud ☁️

Atlassian Government Cloud has achieved FedRAMP Authorization at the Moderate level! Join our webinar to learn how you can accelerate mission success and move work forward faster in cloud, all while ensuring your critical data is secure.

Register Now
AUG Leaders

Atlassian Community Events