How to use API token for REST calls in Python.

Marvin Hoffman March 28, 2018

I'm currently intending to use the Jira API to pull data for more robust reporting. I am using Python 3.6, and the Python requests library.

Currently this works:

r = requests.get(jira_url_critquery, auth=('[username]','[password]'))

But I'd rather use the API token I've created. I've tried several different variations, but so far nothing has worked.

Here is an example of a url which works (with the username/password).

https://[our company account].atlassian.net/rest/api/2/search?jql=assignee=[my jira username]

 

Any thoughts?

6 answers

3 accepted

22 votes
Answer accepted
Rob Echlin April 5, 2019

Hi Marvin, 

If you use the Jira Python library, just put the key where the password would go.

Example code (worked with the SAAS version of Jira, my user, my apikey)

#!/usr/bin/python3.6

# library modules
from jira import JIRA

user = 'me@here.com'
apikey = 'your0api0key0here'
server = 'https://SITE_NAME.atlassian.net'

options = {
'server': server
}

jira = JIRA(options, basic_auth=(user,apikey) )

ticket = 'KRP-11697'
issue = jira.issue(ticket)

summary = issue.fields.summary

print('ticket: ', ticket, summary)
Omantha Prasad June 26, 2019

Thank you for the answers, how can I get the users any sample python code to get user details who are in cloud Jira account?

Like Florent Robert likes this
Dilip Arsid August 30, 2019

Thanks. This worked perfectly.

Dominique Boutin September 27, 2019

Page for creating your tokens: 

https://id.atlassian.com/manage/api-tokens#

Like Ilja Brier likes this
John Gomez November 7, 2019

I was struggling with outh but this solution is easier. Thank you! 

Ventsislav February 10, 2020

Can you authenticate for multiple servers in the same time? Something like

#!/usr/bin/python3.6

# library modules
from jira import JIRA

user = 'me@here.com'
apikey = 'your0api0key0here'
server1 = 'https://SITE_NAME1.atlassian.net'
server2 = 'https://SITE_NAME2.atlassian.net'


options = {
'server': [server1, sever2]
}

jira = JIRA(options, basic_auth=(user,apikey) )

(Obviously if the user has access to both)

Is this even possible? Or is there a workaround so it is achievable?

Like pradnya.ramtirthakar likes this
Purven Dudhaiya March 17, 2020

Can anyone help me out on how can I handle invalid username and password entered by the user. Thus, how can handle the calling of JIRA constructor using basic_auth but with wrong credentials ? ( not exception handling)

Jose Luis Casarrubias July 2, 2021

I confirm the solution works fine!

anunes July 13, 2022

@Rob Echlin Is it possible that the user isn't an email? I'm trying to authenticate using a an Organization Id and an API key, if not, as I assume it is because I have tried it. How does one fix this situation? https://support.atlassian.com/organization-administration/docs/manage-an-organization-with-the-admin-apis/  this was the guide used to create the API key in case it helps.

Thank you.

5 votes
Answer accepted
John McGehee April 5, 2019

Standing on the shoulders of @Rob Echlin the Giant, here is my version:

import jira

jira = jira.JIRA('https://example.atlassian.net', basic_auth=('username@example.com', 'usernames_api_key'))

# print all of the project keys as an example
for project in jira.projects():
print(project.key)
karim.belhadj April 3, 2020

Hello @John M 

it gives me this error : AttributeError: module 'jira' has no attribute 'JIRA'

 

Regards

Karim

Emmanuel Mondragon February 2, 2021

Thanks Jhon McGehee.

Oskar Austegard February 3, 2021

As mentioned here, should note that this is for Cloud only - Server & Datacenter use a different header (yay!):
https://github.com/pycontribs/jira/issues/993

Since the Python Jira API doesn't yet support personal access tokens directly, for Jira Server & Datacenter a workaround is in this thread:  
https://github.com/pycontribs/jira/issues/989#issuecomment-772683446

TL;DR:

host = "YOUR_JIRA_URL"
pat = "YOUR_PERSONAL_ACCESS_TOKEN"

headers = JIRA.DEFAULT_OPTIONS["headers"].copy()
headers["Authorization"] = f"Bearer {pat}"
jira=JIRA(server=host, options={"headers": headers})

 

Like # people like this
Deleted user May 11, 2021

Thanks @Oskar Austegard this worked for me. I have been trying to figure out the way to get the PAT working, and this was the only one that got it going. Kudos!

Like Oskar Austegard likes this
Bill Sim June 9, 2021

Perfect @Oskar Austegard ! Nice work.

Like Oskar Austegard likes this
1 vote
Answer accepted
Kurt Klinner
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.
March 28, 2018
Marvin Hoffman March 29, 2018

Thank you sir. I shall give this a go.

Rob Echlin November 7, 2018

Hi Marvin, 

If you use the Jira Python library, just put the key where the password would go.

 

Example code (worked with my server, user, apikey)

 

#!/usr/bin/python3.6

# library modules
from jira import JIRA

user = 'me@here.com'
apikey = 'your0api0key0here'
server = 'https://SITE_NAME.atlassian.net'

options = {
'server': server
}

jira = JIRA(options, basic_auth=(user,apikey) )

ticket = 'KRP-11697'
issue = jira.issue(ticket)

summary = issue.fields.summary

print('ticket: ', ticket, summary)

 

Like # people like this
John McGehee February 26, 2019

Standing on the shoulders of giant Rob, here is my version:

import jira

jira = jira.JIRA('https://example.atlassian.net', basic_auth=('username@example.com', 'usernames_api_key'))

# print all of the project keys as an example
for project in jira.projects():
print(project.key)
Like Jason Fernandes likes this
Jason Huang June 7, 2021

Hi @Andy Heinzer

This is for the cloud, doest there is also a way for Jira Server?

 

Thanks,

Jason

Andy Heinzer
Atlassian Team
Atlassian Team members are employees working across the company in a wide variety of roles.
June 9, 2021

Hi @Jason Huang at the time this was originally created, Jira Server did not have these kinds of tokens.  But in Jira server you could still use the username and password to manage authentication.

Jira 8.14 and higher though, do now have personal access tokens, which function in much of the same way as REST API tokens do in Jira Cloud today.

Jason Huang June 10, 2021

Hi @Andy, thanks for your response.

I am trying the PAT, but encounter the websudo problem to create a user with the  python-jira package

Do you have any solution for it?

Bill Sim June 10, 2021

Hey @Jason Huang see the post from @Oskar Austegard above .

3 votes
Colie Ryan February 28, 2022

To use python requests library and token (rather than the jira python library), this works for me:

 

headers = {
        "Accept": "application/json",
        "Content-Type": "application/json",
        "Authorization": "Bearer " + token
         }
r = requests.get(url, headers=headers, verify=False)
Weronika Goracy September 5, 2022

Works for me! Thanks a lot!

Sam Li October 16, 2023

Not working for me. I'm using v9.4.11

Bill Sim October 16, 2023

There are a bunch of things that could be wrong... if you want help you need to pop in some more context... Are you running Cloud or DC? What is the error message if any? Are you using Requests (my assumption) or the JIRA module? What call are you making? Have you had any calls work? Etc...

Sam Li October 17, 2023

Hi Bill thanks for the following up. Yes I should provide more context. We're not in cloud yet so it's DC. I do read the thread and the Jira document closely and try every senarios I can think of, including manually logon to disable captacha. The error messages I have imply authentication failure using PAK:

 

Response code: 400, Response contents: {"errorMessages":[],"errors":{"summary":"Field 'summary' cannot be set. It is not on the appropriate screen, or unknown.","description":"Field 'description' cannot be set. It is not on the appropriate screen, or unknown."}}

Jira issue creation failure: b'{"errorMessages":[],"errors":{"summary":"Field \'summary\' cannot be set. It is not on the appropriate screen, or unknown.","description":"Field \'description\' cannot be set. It is not on the appropriate screen, or unknown."}}'

Here is the python code partial that make the rest api call:

 

class JiraClient:

def __init__(self, env, file):

self.env = env

self.env_pattern = re.compile( r'^\<%= ENV\[\'(.*)\'\] %\>(.*)$' )

self.conf_dir = dirname(realpath(__file__)) + "/conf/"

if not is_directory(self.conf_dir):

mkdir(self.conf_dir)

self.conf_file = file if file else self.conf_dir + "jira_integration.yaml"

self.conf_dict = self.load_yaml(self.conf_file)

self.jira_headers = {

"Accept": "application/json",

"Content-Type": "application/json",

"Authorization": "Bearer " + self.conf_dict[self.env]["api-token"]

}

res = requests.post(self.conf_dict[self.env]['api-uri'] + '/issue/', \

headers=self.jira_headers, json=json_data, \

#auth=(self.conf_dict[self.env]['username'], \

#self.conf_dict[self.env]['password']), \

verify=False)

print(f'Response code: {res.status_code}, Response contents: {res.text}')

if res.status_code == 201:

print(f'Jira issue is sucessfully create: {res.status_code}')

else:

print(f'Jira issue creation failure: {res.content}')

return res.status_code
Bill Sim October 18, 2023

Hi Sam,

No, that looks like you have successfully authenticated/authorized.

  • To confirm I am right, always start with a read operation (GET) as that is less prone to configuration issues. Make sure the user can browse/view an issue. Then attempt to GET that issue via the API. If this works then it has nothing to do with your auth.
  • The response above suggests that the user/token that is doing the API call cannot 'see' the fields on one of the screens required to carry out the call. Again, you can confirm this by making sure you can execute the operation you are trying manually as that user (after having logged into Jira as that user).
  • Your auth header code looks fine to me.

  • I've seen this type of error tonnes of times in the past, and it was always to do with the project/screen configuration or user authorisation at that point. Nothing do to with authentication
Sam Li October 18, 2023

Hi Bill, thanks for the following up. This makes no sense to me - I don't understand what's the configurations could be wrong. The same code would work if I switch to the test user name and password, such as below:

 

res = requests.post(self.conf_dict[self.env]['api-uri'] + '/issue/', \

headers=self.jira_headers, json=json_data, \

auth=(self.conf_dict[self.env]['username'], \

self.conf_dict[self.env]['password']), \

verify=False)

Note the token is generated under the SAME test user. 
Screen Shot 2023-10-18 at 12.08.35 PM.png
Bill Sim October 18, 2023
  • Did you try a read/get an issue request per my suggestion?
  • The token above has never been used ("Last authenticated - Never") so that suggests that something is wrong with the request you're sending (contrary to what I said above)... so I'd check that the Authorization part of the header dict is indeed producing "Bearer TOKEN......." into the headers.
Sam Li October 18, 2023

Thank you Bill. Yes you're right this time. It's the Jira headers problem. Somehow the code below did not work:

self.jira_headers = {

"Accept": "application/json",

"Content-Type": "application/json",

"Authorization": "Bearer " + self.conf_dict[self.env]["api-token"]

}

Once I split the last line into 2 it works like a magic:

 

self.token = self.conf_dict[self.env]["api-token"]

self.jira_headers = {

"Accept": "application/json",

"Content-Type": "application/json",

"Authorization": "Bearer " + self.token

}
Like Bill Sim likes this
Bill Sim October 18, 2023

Good to hear!

1 vote
Andy Heinzer
Atlassian Team
Atlassian Team members are employees working across the company in a wide variety of roles.
April 5, 2019

@Rob Echlin and @John McGehee Thanks for posting your own solutions to this post.  If you could repost these as an answer, instead of a comment, we could then accept your answer for this question.  It would help other users that come across this thread to see more clearly other potential solutions.  

I could post your answers again myself, but it feels super disingenuous to claim your solution as my own, which is how it would appear if I just copy/pasted it.

Thanks

Andy

Rob Echlin April 5, 2019

Thanks for the suggestion.
I created an answer from my comment.

Sincerely,
Rob

Like Andy Heinzer likes this
0 votes
Andrew Sear January 9, 2022

The answers above seem to rely upon the jira pthon library, which is useful but then how do you place a REST query after authentication, e.g. request = "https://xx.atlassian.net/rest/agile/1.0/sprint/L8C_1.1"

for example, the library does not return the sprint report from JIRA cloud to my knowledge, or from JIRA server.

So my question is

1. how to authenticate for the requests libary with a JIRA token.

2. How to then place a query, and catch the response.

currently my approach is failing with "{"message":"Client must be authenticated to access this resource.","status-code":401}"

 

Regards

Andrew

Rafe G April 21, 2022
Andrew,
I have the following python snippet that shows how to get the token into a base64 string, and then into the headers so that it can be used with requests:
import requests
import base64

user = 'user.email'
token = 'token.here'
url = 'URL_HERE'

auth = user + ":" + token
encoded = base64.b64encode(bytes(auth, "utf-8"))
encodedAuth = encoded.decode("utf-8")

headers = {
  "Accept":"application/json",
  "Content-Type":"application/json",
  "Authorization":"Bearer " + encodedAuth
}

r = requests.get(url, headers=headers)
print(r)

 

Rafer

Like Federico Scheu likes this
brian.zaranyika April 24, 2022

Hi Rafer thanks for this solution, quite helpful in solving this jira authentication error:

basic authentication with passwords is deprecated

Like Rafe G likes this

Suggest an answer

Log in or Sign up to answer