How to fetch data from a REST API by using an API-Token - reactjs

I'm trying to fetch data from the Jira Rest API in my React application by using the Axios library for http requests. An API token is necessary, in order to access data via the Jira API. I generated an API token in my Jira account settings, but I can't figure out, how to include it in my http request to gain access.
This is the endpoint provided by the Jira documentation for getting an issue from the Jira board:
curl -u admin:admin http://localhost:8080/jira/rest/api/2/issue/TEST-10 | python -mjson.tool
This is the React state hook for setting the data to the fetched data:
const [jiraTicket, setJiraTicket] = useState([]);
This is the fetch function for the API request (${} will be filled with user input):
function getJiraTicket() {
axios.get(`${username}:${apiToken}#Content-Type:application/json/https:/${jiraSiteName}.atlassian.net/rest/api/2/issue/${projectKey}-${ticketId}`)
.then((res) => {
const data = res.data;
setJiraTicket(data);
})
}
The button inside the react component return should invoke the fetch function:
return(
<Container>
<Button onClick{getJiraTicket()}>Fetch Jira Ticket</Button>
</Container>
);
This is the error I'm currently getting, because the authorization is not working the way I did it
(I replaced the provided username, API token etc. for this example):
GET http://localhost:3000/username:apitoken#https:/sitename.atlassian.net/rest/api/2/issue/projectkey-ticketid 404 (not found)
Edit:
My current approach:
function getJiraTicket() {
axios.get(`${userName}:${apiToken}#https://${siteName}.atlassian.net/rest/api/2/issue/${projectId}-${ticketId}`,{
auth: {
username: userName,
password: apiToken,
},
withCredentials: true
})
.then((res) => {
const data = res.data;
console.log(data);
setJiraTicket(data);
})
.catch(err => {
// This error means: The request was made and the server responded with a status code
if(err.res) {
console.log(err.res.data);
console.log(err.res.status);
console.log(err.res.headers);
console.log("request was made and server responded with status");
// The request was made but no response was received
} else if (err.request) {
console.log(err.request);
console.log("request was made, but no response was received");
// Something happened in setting up the request that triggered an error
} else {
console.log("Error", err.message);
console.log("request is note set up correctly");
}
console.log(err.config);
})
Current error, which I defined accordingly to the axios doc: "request was made, but no response was received"
Endpoint that works well in Postman (Basic auth is provided in Postman):
https://sitename.atlassian.net/rest/api/2/issue/projectid-ticketid

Update: CORS access isn't allowed, when an application tries to access the Jira API endpoints directly. This restriction takes place in order to prevent random authenticated requests to the specific Jira site, because the access is based on session based authentication. However the API endpoints can be accessed, if OAuth 2.0 is used instead of Basic auth, because the application will redirect the user to the Jira auth itself via this link:
https://auth.atlassian.com/authorize? audience=api.atlassian.com&
client_id=YOUR_CLIENT_ID&
scope=REQUESTED_SCOPE_ONE%20REQUESTED_SCOPE_TWO&
redirect_uri=https://YOUR_APP_CALLBACK_URL&
state=YOUR_USER_BOUND_VALUE& response_type=code& prompt=consent
Source: https://developer.atlassian.com/cloud/jira/platform/oauth-2-3lo-apps/#known-issues

Axios uses a headers config for get/post so you should not include them in your URL. Here is a general example of how you should construct the URL and apply headers:
let axiosUrl = `https://${jiraSiteName}.atlassian.net/rest/api/2/issue/${projectKey}-${ticketId}`
axios({
baseURL: axiosUrl,
method: 'get',
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin", "*"
},
//timeout: 2000,
auth: {
username: userName,
password: apiToken,
}
})
.then((res) => {
setJiraTicket(res.data);
})
.catch(function (error) {
console.log(error);
});

Related

Redirect from React ASP.NET application to SSO login page blocked by CORS Policy

My application is set up as of follows:
Frontend is React (SPA),
Backend is ASP.NET Core 6, and
User will be authenticated via SSO using SAML2 protocol (the SAML code is implemented on the ASP.NET side, not React)
When the React page is loaded, it will send a POST request via fetch API to the ASP.NET server which then will trigger to load the SSO page (I'm actually confused by this as I'm unsure how this would work with React since React handles all the routing piece here). However, I keep getting an error that is saying:
"Access to fetch at 'https://sso.example.com/saml/idp/profile/redirectorpost/sso?SAMLRequest=xxxx&RelayState=ReturnUrl%3D%252Fexample%252Fexampleapp%252FGetLoggedInUser' (redirected from 'https://forms.test.com/test/testapp/GetLoggedInUser') from origin 'https://forms.test.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request."
I attempted to fix this by changing the attributes in the fetch headers by all resulted in the same CORS error.
Here's my fetch api code on the frontend:
fetch("testapp/GetLoggedInUser", {
method: "POST",
headers: {
'Accept': 'application/json',
'Access-Control-Allow-Origin': '*',
},
body: data
}).then((response) => {
const contentType = response.headers.get("content-type");
if (contentType && contentType.indexOf("application/json") !== -1) {
return response.json().then((data) => {
return data;
}).catch((err) => {
console.log(err);
})
}
else {
return response.text().then((data) => {
return data;
}).catch((err) => {
console.log(err);
})
}
});
My backend (ASP.NET Core 6)
//[Authorize] is an attribute from Microsoft.AspNetCore.Authorization.AuthorizeAttribute
[Authorize]
[HttpPost("GetLoggedInUser")]
public string GetLoggedInUserData()
{
this.CheckSession();
Person Person = new ActiveUser(this.ID, GlobalVariables.ProcessCode);
dynamic P = Person.GetSimple();
User User = new User(this.WhitworthID);
P.LastAccess = DateTime.Now;
User.SetLastAccess();
return JsonConvert.SerializeObject(P);
}
Can anyone advise me on how to get past the CORS error when redirecting from React to the SSO page?
Modify your code to check if the response is redirected,if so redirect the browser to the new url.
fetch(url, { method: 'POST', redirect: 'manual'})
.then(response => {
// HTTP 301 response
// HOW CAN I FOLLOW THE HTTP REDIRECT RESPONSE?
if (response.redirected) {
window.location.href = response.url;
}
})
.catch(function(err) {
console.info(err + " url: " + url);
});

Expressjs Server cannot handle Requests from the Outside

I have a ExpressJs Server with React Components. And the Server should handle Requests from Outside and one request should play a Song from the Spotify API when not currently playing.
app.post("/play", (req, res) => {
try {
// requesting to play uses query params
id = req.query.id;
currPlayingID = 0;
// get the currently playing song from the SPotify API
axios({
url: "https://api.spotify.com/v1/me/player/currently-playing",
method: "get",
headers: {
authorization: `Bearer ${access_token}`,
},
})
// set the currently Playing ID or to zero if nothing is playing
.then((response) => {
if (response.data !== null) {
currPlayingID = response.data.id;
} else {
currPlayingID = 0;
}
});
// only play the song if its not currently playing
if (id !== currPlayingID) {
// making a axios request to the Spotify API to play the Song with the ID
axios({
url: "https://api.spotify.com/v1/me/player/play/",
method: "put",
headers: {
authorization: `Bearer ${access_token}`,
},
data: {
uris: [`spotify:track:${id}`],
},
});
res.status(204);
}
} catch (error) {
res
.status(404)
.json({ message: "Couldn't get Info from Spotify API", error: error });
}
});
The Problem:
The Code works when I start the server on the device itself (so a local server on my Desktop PC), but when I start the Server on my RaspberryPI i cannot handle Requests to this endpoint /play. Yeah I updated all the IP Adresses, everywhere.
But the moer ointeresting part is using the React Client I get this error:
Failed to load resource: net::ERR_CONNECTION_REFUSED
Requesting with POSTMAN I get the following:
Mixed Content Error: The request has been blocked because it requested an insecure HTTP resource
And from a request using a python script I get on the server side:
[UnhandledPromiseRejection: This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason "AxiosError: Request failed with status code 400".] {
code: 'ERR_UNHANDLED_REJECTION'
}
I have no clue how to fix each error and if it is one fix. Basically I found out it is a Problem with rejeccting requests from outside localhost, because with cURL on my ssh terminal it works.
I'm learning express, so I m not an expert, but I'm looking at your errors. I will suggest you try asyncHandler module. It handles asynchronous requests and exceptions.
I faced a similar issue because while I'm sending the API request via
Axios, my token is null/empty/wrong, so make sure your token is correct
this is my request format
axios({
method:"POST",
url:"https://graph.facebook.com/v13.0/"+phon_no_id+"/message?access_token="+token,
data:{
messaging_product:"whatsapp",
to:from,
text:{
body:"Hi.. I'm Prasath"
}
},
headers:{
"Content-Type":"application/json"
}
});

Understanding Next.JS with-iron-sessions requirements for use in own environment

I am trying to get some of the examples located in the with-ireon-sessions github account to work with my own back-end: https://github.com/vercel/next.js/tree/canary/examples/with-iron-session
I can sign in using const { user, mutateUser } = useUser(); with useUser() being from the example: https://github.com/vercel/next.js/blob/canary/examples/with-iron-session/lib/useUser.js
My sign-in method looks like this;
const signIn = async ({ email, password, remember_me }) => {
try {
await mutateUser(
fetchJson(`${API.baseURL}/${API.signIn}`, {
method: "POST",
headers: {
"Accept": 'application/json',
"Content-Type": "application/json"
},
body: JSON.stringify({
email,
password
})
})
);
} catch (error) {
console.error("An unexpected error happened:", error);
setErrorMessage((<p className="error">{error.data.message}</p>));
}
};
I can see my user change, but I still have the following issues:
I don't see any cookies get created. Does with-iron-sessions require the site to be deployed to the vercel cloud in order for cookies to get added, or am I right in thinking I can use my own server and API endpoints?
What's the pattern for using the /api/user endpoint in useUser.js; does the endpoint look for the cookies (that are not getting created for me) and do it's own validation, or is there validation I need to do in my version of that endpoint? Is there an example of what that endpoint looks like server-side you might be able to point me to?
Is there a way to refresh the cookie (once I get them to appear) so they are X days since last using the site instead of X days from first login so it's a sliding cookie lifespan, or does that happen automatically?
When I sign out my sign_out endpoint returns a 204 status code but the UI doesn't change like it does when I sign in. Any tips for me there?
Thank you!

reactjs make https (not http) requests with axios

I'm trying to make https requests to the server using axios. Most of the tutorials regarding axios specify how to make http requests.
I make the requests whenever users login. Here is my current request:
axios.post('/api/login/authentication', {
email: email,
password: password
})
.then(response => {
this.props.history.push('/MainPage')
})
.catch(error => {
console.log(error)
})
Can anyone help me convert this to an https request?
All URLs have two parts
Domain - http://yourdomain.com
Path - /path-to-your-endpoint
1. Use default domain
In axios, if you specify just the path, it will use the domain in the address bar by default.
For example, the code below will make a call to whatever domain is in your address bar and append this path to it. If the domain is http, your api request will be a http call and if the domain is https, the api request will be a https call. Usually localhost is http and you will be making http calls in localhost.
axios.post('/api/login/authentication', {
2. Specify full URL with domain
On the other hand, you can pass full URL to axios request and you will be making https calls by default.
axios.post('https://yourdomain.com/api/login/authentication', {
2. Use axios baseURL option
You can also set baseURL in axios
axios({
method: 'post',
baseURL: 'https://yourdomain.com/api/',
url: '/login/authentication',
data: {
email: email,
password: password
}
}).then(response => {
this.props.history.push('/MainPage')
})
.catch(error => {
console.log(error)
});

fetch always pass with OPTIONS method

I made API server with flask-restplus.
Also use cors module for avoid CSP issue.
And frontend is React.js.
My code is here.
class ArticleList(Resource):
def post(self):
print(1)
return {"status":"true", "result":"article write success"}, 200
React.js code is here.
_writeArticle = () => {
const { title, body, tags, password } = this.state;
const data = {title: title, body: body, tags: tags, password: password};
fetch("http://127.0.0.1:5000/article/", {
method: "POST",
mode: "cors",
headers: {
"Content-Type": "application/json"
},
body: data
})
.then(res => {
if(res.status === 200) {
return <Redirect to='/' />
} else {
alert("error");
}
})
.catch(err => console.log(err))
}
I defined method to POST. But, it request with OPTIONS method.
After searched in google, that issue cause by CORS.
So I defined cors to main code like this.
from flask import Flask
from flask_restplus import Api, Resource
from api.board import ArticleList, Article
from flask_restplus import cors
app = Flask(__name__)
api = Api(app)
api.decorators=[cors.crossdomain(origin='*')]
api.add_resource(ArticleList, '/article')
api.add_resource(Article, '/article/<int:article_no>')
if __name__ == '__main__':
app.run(debug=True)
But it still request with OPTIONS.
How can I solve this issue?
That OPTIONS request is called pre-flight request.
Under some circumstances relating to CORS the web browser will first send a pre-flight request to server to check if your domain is allowed to make requests to the server or not. If the server says yes then your actual POST request will be sent. Otherwise, no additional requests will be sent and the web browser will spit an error at you.
Here is documentation on pre-flight request:
https://learn.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-2.1#preflight-requests
And according to the documentation:
The pre-flight request uses the HTTP OPTIONS method.

Resources