Using Jira API from simple javascript GET with token auth

Can’t seem to get this working, returning 404. URL on its own works fine from a browser tab.

	var jiraToken = '{MyToken}'

	const jiraUrl = 'https://{MyOrg}.atlassian.net/rest/api/2/issue/{IssueName}';
	
	fetch(jiraUrl,                            
	{	method: 'GET',
		withCredentials: true,    
		crossorigin: true,    
		mode: 'no-cors',
		headers: {'Authorization': jiraToken, 'Content-Type': 'application/json'}
	}).then(response => {
		debugger;
		var foo = response;
		});

Welcome to the Atlassian developer community @JodeePage,

The problem is in the construction of the Authorization header. This should use standard basic auth for HTTP, which means constructing the header like so:

'Authorization': 'Basic ' + btoa(userEmail + ":" + jiraToken))

Hope that solves the 404.

Thanks for assisting! Updated to this and still getting 404.

const userEmail = '{myemail}';
const jiraToken = '{mytoken}';

const jiraUrl = 'http://{myorg}.atlassian.net/rest/api/2/issue/FPA-620';

fetch(jiraUrl,                            
{	method: 'GET',
	crossorigin: true,    
	mode: 'no-cors',
	headers: {'Authorization': 'Basic ' + btoa(userEmail + ':' + jiraToken)}
}).then(response => {
	debugger;
	var foo = response;
	});

Also accidentally pasted full info in deleted reply but the history is still lingering around, can that please be permanently deleted?! Revoked and created a new token but would still like reply to be gone!

Is that HTTP a typo? You need to connect over HTTPS.

Remember, 404 errors are not authentication errors, they are resource errors. IE, you requested a resource at a URL that doesn’t exist.

Check at least that you’re authenticated by making a call to /rest/api/2/myself:

const jiraUrl = 'https://whatever_your_org_is.atlassian.net/rest/api/2/myself';

Tried both. And exact URL (with https) works fine directly in the browser. Changing URL to myself endpoint return 401. Again, URL works fine directly in browser.

	const userEmail = '{myemail}';
	const jiraToken = '{mytoken}';

	//const jiraUrl = 'http://{myorg}.atlassian.net/rest/api/2/issue/FPA-620';
	const jiraUrl = 'https://{myorg}.atlassian.net/rest/api/2/myself';
	
	fetch(jiraUrl,                            
	{	method: 'GET',
		crossorigin: true,    
		mode: 'no-cors',
		headers: {'Authorization': 'Basic ' + btoa(userEmail + ':' + jiraToken)}
	}).then(response => {
		debugger;
		var foo = response;
		});

OK, so a 401 is an authentication error, so that means the connection went through (valid URL / resource), but the authentication failed. You have something wrong with the authentication.

Ignore that connecting to a REST API endpoint works in a browser, since the session cookie is being used to authenticate. You can prove that by closing your web browser or logging off the web GUI, then trying to use the URL to the myself endpoint in the browser and you’ll see it failing with a 401 error.

Also, be pedantic in your code and type the URL / key / token in directly into the fetch function… don’t declare them using intermediate const variables, in case you’re doing something wrong with passing them to fetch.

I also strongly suggest using a REST API test tool like Postman to confirm you have a valid, working key + token combination. At least that way you can isolate if it’s a faulty key + token pair or a faulty authentication method in your code.

We’re using Axios like this:

let config: AxiosRequestConfig = {
    method: method,
    url: url,
    headers: { Authorization: `JWT ${token}` }
}
if (body) {
    config = { ...config, data: body }
}
const res: AxiosResponse = await axios(config)

I have done all of these things already. Browser works fine so url is good. Postman works fine so browser and token are good. Just something off with the javascript syntax that I can’t figure out. Tried every different variation. Current state:

	const userEmail = '{myemail}';
	const jiraToken = '{mytoken}';
	const auth = btoa('${userEmail}:{${jiraToken}');

	const jiraUrl = 'https://{myorg}.atlassian.net/rest/api/2/myself';
	
	fetch(jiraUrl,                            
	{	method: 'GET',
		crossorigin: true,    
		mode: 'no-cors',
		headers: {'Authorization': 'Basic ${auth}'}
	}).then(response => {
		debugger;
		var foo = response;
		});

This is meant to be a little single file tool that can be used by various folks on the team including non-technical p0eople.

Well, now that you know your JS is at fault, all I can suggest is that you the follow classic code debugging process.

Compare your JS code with the examples in the REST API documentation and all the others that exist. For example, in the above code you’ve provided, you’ve removed the Accept value from the header (ie 'Accept': 'application/json' ), which probably is detrimental.

Have fun.

Hoping to hear more from the folks at Atlassian. I wouldn’t think that they would want to leave the impression that their API is not working as documented and their only comment is “too bad and have fun trying to figure it out.” Not having these issues with any other APIs being used in this little tool. They all work as documented using their example code with an auth token.

@ibuchanan - Was hoping for additional input from you on this topic, as we are still blocked from making use of the API. Token auth works fine from postman using same email and token combo and I confirmed that the btoa function is resulting in the same value that postman sends when you add your auth info in there. I have reviewed all of your documentation and see no example in plain javascript. I only see curl and powershell examples. Basic auth for REST APIs

How are folks supposed to make use of your API if simple javascript fetch will not work?

@JodeePage,

I’m hardly an expert in JavaScript, let alone all the flavors of fetch. I don’t know what the problem could be. Is there more information you can provide than just the HTTP status codes? As you point out the REST APIs do work with your API Token so I think you’ll have to provide more context before anyone could help diagnose your problem.

It’s all in the thread. This is the javascript call returning 401. Using same url, email and token in postman works fine. Confirmed the btoa function is resulting in the same encoded string that postman uses.

	const userEmail = 'myemail';
	const jiraToken = 'mytoken';
	const auth = btoa(userEmail + ":" + jiraToken);
	const jiraUrl = 'https://myorg.atlassian.net/rest/api/2/myself';
					
	fetch(jiraUrl,                            
	{	
		headers:{'authorization': 'Basic ' + auth, 'content-type': 'application/json'},			
		method: 'get',
		withcredentials: true, 
		crossorigin: true, 		
		mode: "no-cors"
	}).then(response => {
		debugger;
		var foo = response;
		});

If this is true why don’t you just put this in your documentation instead of running users around in circles? This is super disappointing and is a huge limitation for an API.

@JodeePage,

Today I learned. I don’t know why this isn’t better documented. I’ve happily opened a doc bug for both the relevant end-user and developer docs.

So if basic javascript fetch is not an option, what is the most lightweigt way to access the API? We just need to create a very simple view that cross references LaunchDarkly flags and their status with linked Jira tickets. The LD portion took me just a few hours to complete with a simple javascript file, but now we have been roadblocked on this effort for the Jira portion for over a week. This shouldn’t require a full blown app/website to accomplish. It’s just a little internal tool, but one that will provide a big benefit for our flag tracking.

Does not really make sense that users can access the API from curl or postman using the token, but from javascript where you can actually do something useful with the results, access is blocked? Why?

@JodeePage,

You might not need to write any code at all. Have you tried the LaunchDarkly integration with Jira Software?

This does not give us the details we want. The view I am creating filters flags by specific team tags, then groups them by release # tags. From there is shows the status of each flag across each environment. The next piece would be to call the Jira API for each flag by the linked Jira ticker ID and display certain attributes of the ticket (status, fixed in, etc).

As I mentioned, the LaunchDarkly API was very fast to work with. Just enter your token and get back all your flags and apply view presentation on results in simple javascript.