OAuth 1.0a is a deprecated authentication protocol and should not be used.
For new Jira Cloud integrations, you should use one of the recommended alternatives listed below. Additionally, if you have existing services that integrate with Jira Cloud using OAuth 1.0, you should look to replace it with one of the recommended authentication approaches listed:
See Integrating with Jira Software Cloud page for more information on the options for developing with Jira Software Cloud.
Clients authenticate against the Jira REST API using OAuth (1.0a). This tutorial explains how OAuth works with Jira and walks through an example of how to use OAuth to authenticate a Java application (consumer) against the Jira (resource) REST API for a user (resource owner).
Code for this walkthrough is in the java
directory of the
atlassian-oauth-examplesrepository.
To complete this tutorial, you need:
OAuth is an authentication protocol that enables a user (resource owner) to grant a third-party application (consumer/client) access to their information on another site (resource). Jira uses 3-legged OAuth (3LO), which means that the user is involved in the authentication process by authorizing access to their data on the resource (instead of 2-legged OAuth, where the user is not involved).
The roles in the OAuth authentication process, and how they relate to authenticating with Jira, are:
The authentication process, commonly known as the "OAuth dance," works by the resource owner granting access to their information on the resource by authenticating a request token. The consumer uses the request token to obtain an access token from the resource. Once the client has an access token, it uses it to make authenticated requests to the resource until the token expires or is revoked.
This diagram shows the process in more detail:
This walkthrough shows how the OAuth authentication process works. First, it configures Jira so that the example client can authenticate against it using OAuth. Then it uses the example client to initiate the "OAuth dance" before making an authenticated request to the Jira REST API.
java
directory:
1 2cd atlassian-oauth-examples/java
1 2mvn clean compile assembly:single
Ignore the exception in the output. This step generates the config.properties file, which is used later.1 2java -jar OAuthTutorialClient-1.0.jar requestToken
In Jira, OAuth consumers are represented by application links. Application links use OAuth with RSA-SHA1 signing for authentication. This means that a private key is used to sign requests rather than the OAuth token secret/consumer secret. The following steps generate an RSA public/private key pair and creates a new application link in Jira that uses the key.
Generate an RSA public/private key pair:
In a terminal, run these openssl commands. Do this anywhere in your file system:
1 2openssl genrsa -out jira_privatekey.pem 1024 openssl req -newkey rsa:1024 -x509 -key jira_privatekey.pem -out jira_publickey.cer -days 365 openssl pkcs8 -topk8 -nocrypt -in jira_privatekey.pem -out jira_privatekey.pcks8 openssl x509 -pubkey -noout -in jira_publickey.cer > jira_publickey.pem
This generates a 1024 bit private key, creates an X509 certificate, and extracts the private key
(PKCS8 format) to the jira_privatekey.pcks8
file. It then extracts the public key from the
certificate to the jira_publickey.pem
file.
Copy the private key from the jira_privatekey.pcks8
file.
Navigate to the target directory in the example OAuth client project. Edit the config.properties
file and make these changes:
private_key
field. Remove all line breaks.jira_home
to the URL of your Jira development instance, for example, https://example-dev1.atlassian.net
consumer_key
to OauthKey
.Save the config.properties
file.
Configure the client app as a consumer in Jira, using application links:
jira_publickey.pem
file and paste it into this field
The example client is now configured as an OAuth consumer in Jira.
The "OAuth dance" is a term used to describe the process of getting an access token from the resource that the consumer can use to access information on the resource. This involves a "dance" where different tokens are passed between the consumer, resource owner, and resource (see OAuth overview above).
In a terminal, navigate to the target directory of the example OAuth client project.
Run this command to request an unauthorized request token from your Jira instance.
1 2java -jar OAuthTutorialClient-1.0.jar requestToken
The outputs details of the new request token:
1 2Token: ec3dj4byySM5ek3XW7gl7f4oc99obAlo Token Secret: OhONj0eF7zhXAMKZLbD2Rd3x7Dmxjy0d Retrieved request token. go to https://jira101.atlassian.net/plugins/servlet/oauth/authorize?oauth_token=ec3dj4byySM5ek3XW7gl7f4oc99obAlo to authorize it
The request token persists for 10 minutes. When it expires, you request a new one.
In a browser, go to the URL specified in the output and this dialog shows:
Click Allow. This authorizes the request token and this output shows in the browser:
1 2Access Approved You have successfully authorized 'Example Jira app'. Your verification code is 'qTJkPi'. You will need to enter this exact text when prompted. You should write this value down before closing the browser window.
Make a copy of the verification code.
In a terminal, run this command replacing the example verification code (qTJkPi) with your verification code from the previous step.
1 2java -jar OAuthTutorialClient-1.0.jar accessToken qTJkPi
Output like this shows in your terminal:
1 2Access Token: W1jjOV4sq2iEqxO4ZYZTJVdgbjtKc2ye
Note, OAuth needs the consumer key, request token, verification code, and private key to get the
access token. However, in the example client, information such as the consumer key, request token,
and private key are stored in the config.properties
file when they are generated (check the file
when you complete this tutorial and you'll see the new values). You don't want to do this for a
production implementation, but this makes the example client easier to use.
The OAuth dance is complete and has provided an access token that is used to make an authenticated request to the Jira REST API.
An access code is all that is needed to make an authenticated request to the Jira REST API. Requests are made as the user who authorized the initial request token. The access token will persist for 5 years, unless it is revoked.
The example OAuth client only makes GET requests, but it's simple to use. Run this command,
substituting <URL for REST method>
with the URL of the REST method you want to call.
1 2java -jar OAuthTutorialClient-1.0.jar request <URL for GET method>
In the code, the example OAuth client stores the access code in the config.properties
file.
When a request is made, the example client passes the stored access code, rather than you entering it.
Here's an example of a request to get an issue using the example OAuth client, the command gets the issue,
JJ-2
, using the Jira REST API:
1 2java -jar OAuthTutorialClient-1.0.jar request https://example-dev1.atlassian.net/rest/api/latest/issue/JJ-2
The command returns an issue like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207{ "expand": "renderedFields,names,schema,operations,editmeta,changelog,versionedRepresentations", "self": "<a href="https://example-dev1.atlassian.net/rest/api/latest/issue/10300">https://example-dev1.atlassian.net/rest/api/latest/issue/10300</a>", "id": "10300", "fields": { "issuetype": { "avatarId": 10803, "name": "Bug", "self": "<a href="https://example-dev1.atlassian.net/rest/api/2/issuetype/1">https://example-dev1.atlassian.net/rest/api/2/issuetype/1</a>", "description": "A problem which impairs or prevents the functions of the product.", "id": "1", "iconUrl": "<a href="https://example-dev1.atlassian.net/secure/viewavatar?size=xsmall&avatarId=10803&avatarType=issuetype">https://example-dev1.atlassian.net/secure/viewavatar?size=xsmall&avatarId=10803&avatarType=issuetype</a>", "subtask": false }, "timespent": null, "project": { "avatarUrls": { "48x48": "<a href="https://example-dev1.atlassian.net/secure/projectavatar?pid=10200&avatarId=10700">https://example-dev1.atlassian.net/secure/projectavatar?pid=10200&avatarId=10700</a>", "24x24": "<a href="https://example-dev1.atlassian.net/secure/projectavatar?size=small&pid=10200&avatarId=10700">https://example-dev1.atlassian.net/secure/projectavatar?size=small&pid=10200&avatarId=10700</a>", "16x16": "<a href="https://example-dev1.atlassian.net/secure/projectavatar?size=xsmall&pid=10200&avatarId=10700">https://example-dev1.atlassian.net/secure/projectavatar?size=xsmall&pid=10200&avatarId=10700</a>", "32x32": "<a href="https://example-dev1.atlassian.net/secure/projectavatar?size=medium&pid=10200&avatarId=10700">https://example-dev1.atlassian.net/secure/projectavatar?size=medium&pid=10200&avatarId=10700</a>" }, "name": "Jira Junior", "self": "<a href="https://example-dev1.atlassian.net/rest/api/2/project/10200">https://example-dev1.atlassian.net/rest/api/2/project/10200</a>", "id": "10200", "key": "JJ" }, "fixVersions": [], "aggregatetimespent": null, "resolution": null, "customfield_10500": null, "customfield_10700": "com.atlassian.servicedesk.plugins.approvals.internal.customfield.ApprovalsCFValue@c8d588", "resolutiondate": null, "workratio": -1, "lastViewed": "2016-08-01T11:23:39.481+1000", "watches": { "self": "<a href="https://example-dev1.atlassian.net/rest/api/2/issue/JJ-2/watchers">https://example-dev1.atlassian.net/rest/api/2/issue/JJ-2/watchers</a>", "isWatching": true, "watchCount": 1 }, "created": "2013-05-29T13:56:24.224+1000", "customfield_10020": null, "customfield_10021": "Not started", "priority": { "name": "Major", "self": "<a href="https://example-dev1.atlassian.net/rest/api/2/priority/3">https://example-dev1.atlassian.net/rest/api/2/priority/3</a>", "iconUrl": "<a href="https://example-dev1.atlassian.net/images/icons/priorities/major.svg">https://example-dev1.atlassian.net/images/icons/priorities/major.svg</a>", "id": "3" }, "customfield_10300": null, "customfield_10102": null, "labels": [], "customfield_10016": null, "customfield_10017": null, "customfield_10018": null, "customfield_10019": null, "timeestimate": null, "aggregatetimeoriginalestimate": null, "versions": [], "issuelinks": [], "assignee": { "emailAddress": "alana@<a href="http://example.com">example.com</a>", "avatarUrls": { "48x48": "<a href="https://secure.gravatar.com/avatar/b259e2a7fd37a83b02015192ee247e96?d=mm&s=48">https://secure.gravatar.com/avatar/b259e2a7fd37a83b02015192ee247e96?d=mm&s=48</a>", "24x24": "<a href="https://secure.gravatar.com/avatar/b259e2a7fd37a83b02015192ee247e96?d=mm&s=24">https://secure.gravatar.com/avatar/b259e2a7fd37a83b02015192ee247e96?d=mm&s=24</a>", "16x16": "<a href="https://secure.gravatar.com/avatar/b259e2a7fd37a83b02015192ee247e96?d=mm&s=16">https://secure.gravatar.com/avatar/b259e2a7fd37a83b02015192ee247e96?d=mm&s=16</a>", "32x32": "<a href="https://secure.gravatar.com/avatar/b259e2a7fd37a83b02015192ee247e96?d=mm&s=32">https://secure.gravatar.com/avatar/b259e2a7fd37a83b02015192ee247e96?d=mm&s=32</a>" }, "displayName": "Alana Example", "name": "alana", "self": "<a href="https://example-dev1.atlassian.net/rest/api/2/user?username=alana">https://example-dev1.atlassian.net/rest/api/2/user?username=alana</a>", "active": true, "timeZone": "Australia/Sydney", "key": "alana" }, "updated": "2016-08-01T11:23:38.022+1000", "status": { "name": "Open", "self": "<a href="https://example-dev1.atlassian.net/rest/api/2/status/1">https://example-dev1.atlassian.net/rest/api/2/status/1</a>", "description": "The issue is open and ready for the assignee to start work on it.", "iconUrl": "<a href="https://example-dev1.atlassian.net/images/icons/statuses/open.png">https://example-dev1.atlassian.net/images/icons/statuses/open.png</a>", "id": "1", "statusCategory": { "colorName": "blue-gray", "name": "To Do", "self": "<a href="https://example-dev1.atlassian.net/rest/api/2/statuscategory/2">https://example-dev1.atlassian.net/rest/api/2/statuscategory/2</a>", "id": 2, "key": "new" } }, "components": [], "timeoriginalestimate": null, "description": "The logo is currently a light cerise. I'd like to see it with a deep pink color.", "customfield_10012": null, "customfield_10013": null, "customfield_10014": null, "timetracking": {}, "customfield_10015": null, "customfield_10600": null, "customfield_10006": "10", "customfield_10601": null, "customfield_10007": [ "com.atlassian.greenhopper.service.sprint.Sprint@dc6300[id=1,rapidViewId=<null>,state=CLOSED,name=Sprint 1,goal=<null>,startDate=2013-07-26T11:31:09.530+10:00,endDate=2013-08-09T11:31:09.530+10:00,completeDate=2013-07-26T11:31:46.489+10:00,sequence=1]", "com.atlassian.greenhopper.service.sprint.Sprint@6b3e17[id=2,rapidViewId=<null>,state=ACTIVE,name=Sprint 2,goal=<null>,startDate=2013-08-22T11:35:33.759+10:00,endDate=2013-12-12T11:35:00.000+11:00,completeDate=<null>,sequence=2]" ], "customfield_10008": null, "attachment": [], "aggregatetimeestimate": null, "summary": "Jira Junior logo is not pink enough", "creator": { "emailAddress": "admin@<a href="http://example.com">example.com</a>", "avatarUrls": { "48x48": "<a href="https://secure.gravatar.com/avatar/4beac5df66a475580809e0?d=mm&s=48">https://secure.gravatar.com/avatar/4beac5df66a475580809e0?d=mm&s=48</a>", "24x24": "<a href="https://secure.gravatar.com/avatar/4beac5df66a475580809e0?d=mm&s=24">https://secure.gravatar.com/avatar/4beac5df66a475580809e0?d=mm&s=24</a>", "16x16": "<a href="https://secure.gravatar.com/avatar/4beac5df66a475580809e0?d=mm&s=16">https://secure.gravatar.com/avatar/4beac5df66a475580809e0?d=mm&s=16</a>", "32x32": "<a href="https://secure.gravatar.com/avatar/4beac5df66a475580809e0?d=mm&s=32">https://secure.gravatar.com/avatar/4beac5df66a475580809e0?d=mm&s=32</a>" }, "displayName": "Administrator", "name": "admin", "self": "<a href="https://example-dev1.atlassian.net/rest/api/2/user?username=admin">https://example-dev1.atlassian.net/rest/api/2/user?username=admin</a>", "active": true, "timeZone": "Australia/Sydney", "key": "admin" }, "subtasks": [], "reporter": { "emailAddress": "admin@<a href="http://example.com">example.com</a>", "avatarUrls": { "48x48": "<a href="https://secure.gravatar.com/avatar/4beac5df66a475580809e0?d=mm&s=48">https://secure.gravatar.com/avatar/4beac5df66a475580809e0?d=mm&s=48</a>", "24x24": "<a href="https://secure.gravatar.com/avatar/4beac5df66a475580809e0?d=mm&s=24">https://secure.gravatar.com/avatar/4beac5df66a475580809e0?d=mm&s=24</a>", "16x16": "<a href="https://secure.gravatar.com/avatar/4beac5df66a475580809e0?d=mm&s=16">https://secure.gravatar.com/avatar/4beac5df66a475580809e0?d=mm&s=16</a>", "32x32": "<a href="https://secure.gravatar.com/avatar/4beac5df66a475580809e0?d=mm&s=32">https://secure.gravatar.com/avatar/4beac5df66a475580809e0?d=mm&s=32</a>" }, "displayName": "Administrator", "name": "admin", "self": "<a href="https://example-dev1.atlassian.net/rest/api/2/user?username=admin">https://example-dev1.atlassian.net/rest/api/2/user?username=admin</a>", "active": true, "timeZone": "Australia/Sydney", "key": "admin" }, "customfield_10000": null, "aggregateprogress": { "total": 0, "progress": 0 }, "customfield_10001": null, "customfield_10200": "0|10001s:", "customfield_10002": null, "customfield_10003": null, "customfield_10400": null, "environment": null, "duedate": null, "progress": { "total": 0, "progress": 0 }, "comment": { "total": 1, "comments": [{ "author": { "emailAddress": "admin@<a href="http://example.com">example.com</a>", "avatarUrls": { "48x48": "<a href="https://secure.gravatar.com/avatar/4beac5df66a475580809e0?d=mm&s=48">https://secure.gravatar.com/avatar/4beac5df66a475580809e0?d=mm&s=48</a>", "24x24": "<a href="https://secure.gravatar.com/avatar/4beac5df66a475580809e0?d=mm&s=24">https://secure.gravatar.com/avatar/4beac5df66a475580809e0?d=mm&s=24</a>", "16x16": "<a href="https://secure.gravatar.com/avatar/4beac5df66a475580809e0?d=mm&s=16">https://secure.gravatar.com/avatar/4beac5df66a475580809e0?d=mm&s=16</a>", "32x32": "<a href="https://secure.gravatar.com/avatar/4beac5df66a475580809e0?d=mm&s=32">https://secure.gravatar.com/avatar/4beac5df66a475580809e0?d=mm&s=32</a>" }, "displayName": "Administrator", "name": "admin", "self": "<a href="https://example-dev1.atlassian.net/rest/api/2/user?username=admin">https://example-dev1.atlassian.net/rest/api/2/user?username=admin</a>", "active": true, "timeZone": "Australia/Sydney", "key": "admin" }, "created": "2013-06-04T16:11:24.505+1000", "updateAuthor": { "emailAddress": "admin@<a href="http://example.com">example.com</a>", "avatarUrls": { "48x48": "<a href="https://secure.gravatar.com/avatar/4beac5df66a475580809e0?d=mm&s=48">https://secure.gravatar.com/avatar/4beac5df66a475580809e0?d=mm&s=48</a>", "24x24": "<a href="https://secure.gravatar.com/avatar/4beac5df66a475580809e0?d=mm&s=24">https://secure.gravatar.com/avatar/4beac5df66a475580809e0?d=mm&s=24</a>", "16x16": "<a href="https://secure.gravatar.com/avatar/4beac5df66a475580809e0?d=mm&s=16">https://secure.gravatar.com/avatar/4beac5df66a475580809e0?d=mm&s=16</a>", "32x32": "<a href="https://secure.gravatar.com/avatar/4beac5df66a475580809e0?d=mm&s=32">https://secure.gravatar.com/avatar/4beac5df66a475580809e0?d=mm&s=32</a>" }, "displayName": "Administrator", "name": "admin", "self": "<a href="https://example-dev1.atlassian.net/rest/api/2/user?username=admin">https://example-dev1.atlassian.net/rest/api/2/user?username=admin</a>", "active": true, "timeZone": "Australia/Sydney", "key": "admin" }, "self": "<a href="https://example-dev1.atlassian.net/rest/api/2/issue/10300/comment/10100">https://example-dev1.atlassian.net/rest/api/2/issue/10300/comment/10100</a>", "id": "10100", "body": "Hi [~william] Jira is *super fun* (see JJ-1). Alana is going to fix the logo.", "updated": "2013-06-12T21:55:34.882+1000" }], "maxResults": 1, "startAt": 0 }, "votes": { "hasVoted": false, "self": "<a href="https://example-dev1.atlassian.net/rest/api/2/issue/JJ-2/votes">https://example-dev1.atlassian.net/rest/api/2/issue/JJ-2/votes</a>", "votes": 0 } }, "key": "JJ-2" }
You now know how to use OAuth to make an authenticated request to the Jira REST API.
oob
(out of band) when creating the request token if you want to show the
token secret to the user:
See getAndAuthorizeTemporaryToken
in JiraOAuthClient.java
in the example OAuth client for an
example of this. You can then set the callback to another URL after the user authorizes the token,
so that Jira sends the token and secret to that URL.consumer_key
or other parameters using the authorization header.Rate this page: