I'm trying to write a simple Wikipedia Search App with included 'Feel Lucky' button.
Is it possible to send request for Wikidata by given pageid? Just like below:
async function luckySearch(){
cleanResults();
try{
let random = Math.floor(Math.random()*10000 + 1);
let endpoint = `https://en.wikipedia.org/w/api.php?action=parse&format=json&formatversion=2&pageid=${random}`;
let response = await fetch(endpoint,{
method:'GET',
headers:{
accept:'application/json',
},
type:'cors',
});
if(!response.ok){
throw new Error(`Error! status: ${response.status}`);
}
else{
let json = await response.json();
}
}
catch(err){
console.log(err.message);
}
}
and always throws 'Failed to Fetch'. Frankly, I'm not sure if either request is wrong, or CORS does not allow to fetch without origin set up. Can somebody explain that to me slowly with mercy, please?
I've changed properties of endpoint to make sure that request has right method. I've checked as well if API contains any action that replies to pageid of Wikipedia article
Yes, you are right: it's a CORS error : the browser does not let you access remote data on Wikipedia server because the server did not mark the request as safe for your domain. The Access-Control-Allow-Origin header is missing, as explained in this MDN article.
You should explicitly ask the wikipedia server to add this header using the origin parameter (see mediawiki API doc for details).
Changing your endpoint to this should work :
let endpoint = `https://en.wikipedia.org/w/api.php?action=parse&format=json&origin=*&formatversion=2&pageid=${random}`;
Related
I'll keep it short, I am getting a CSP (Content Security Policy) error when using the Fetch API in my client-side code. I cannot change the CSP because the request CSP is more strict than connect-src 'self' http://localhost:5000 (the meta tags of the page and 'use' functions in the middleware had no effect on the request CSP).
Maybe I'm missing something, there must be a way for client-side code to call an API?
Error:
Relevant code:
let USER_DETAILS = null;
async function get_by_api(url, data) {
const res = await fetch(url, {
method: "POST",
headers: {'Content-Type': 'application/json; charset=UTF-8'},
body: JSON.stringify(data)
});
// res.catch(function (_) {
// alert("Internal error. Please try again later.\nWe are sorry for the inconvenience.");
// localStorage.clear();
// window.location.replace("https://example.com");
// });
return res;
}
async function update_user_display() {
let user_email = localStorage.email;
let user_key = localStorage.app_key;
console.log("User email: " + user_email);
console.log("User key: " + user_key);
let user_res_data = await get_by_api("http://localhost:5000/v1/info", {
"email": user_email,
"key": user_key
});
user_res_data.then(async function (res) {
if (!(res.status === 200)) {
alert("Internal error. Please try again later.\nWe are sorry for the inconvenience.");
localStorage.clear();
window.location.replace("https://example.com");
return;
}
USER_DETAILS = await res.json();
document.getElementById("tb_user").innerHTML = USER_DETAILS.name;
});
}
fyi: localhost:5000 is what the test API is running on and localhost:5555 is what the app is running on
Thanks for any help.
Check the response headers when your page (response with content type "text/html") loads. You will likely see a CSP header with "default-src 'self'" there. This is the policy you need to change. First you will need to identify where it is set and then how your can change or override it.
Maybe I'm missing something, there must be a way for client-side code to call an API?
By default you just need the API server to grant permission to access it's data across origins via CORS.
In this case http://localhost:5000 has a CSP which prevents code in its pages from accessing anything other than http://localhost:5000. That's an explicit extra level of security that http://localhost:5000 has turned on (one key benefit is that it helps against XSS attacks). If you want to access http://localhost:5555 then you need to change the CSP to say that http://localhost:5555 is trusted (i.e. that you know it isn't a malicious site being used for XSS).
You say you can't change the CSP (it isn't clear why; http://localhost:5000 is your local development environment!) so you can't do that. This means that in your case it isn't possible to call that API.
I am using fetch in my react project to fetch data from an API which is authenticated using a token and my login end-point in the postman return the token in authorization header, you can see
and this's my login funtion in reactjs project
async login(dataLogin) {
const response = await fetch(`${API_URL}/login`, {
method: "post",
headers: {
"Content-Type": "application/json"
},
body: dataLogin
});
const data = await response
console.log(response.headers);
console.log(response.headers.Authorization);
console.log(response.headers.get('Authorization'));
return data;}
you can see that response.headers.authorization return undefined and
response.headers.get('Authorization') return null.
and you can see in my browsers' Network panel
please anyone know how to get the authorization token from the headers?
When you are trying to login using API, then you should receive data i.e. Authorization token or anything else in the response of call.
Check what is the response you're getting when you called an API, it should probably be like
response.data
First you need to check the same in Postman.
To access value of response header server must return header name in Access-Control-Expose-Headers header. Without it Authorization is inaccessible in browser.
response.headers.get('Authorization')
Edit:
Since you are getting null, consider that:
The Authorization header is usually, but not always, sent after the
user agent first attempts to request a protected resource without
credentials.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization
Therefore, instead of using postman, in order to see the response header, use the browsers' Network panel.
I need to get the access token using fetch() method but i am unable to do so with the fetch() method. Tried allowinng Cors-policy or cross-Access-Origin to all but nothing seems to working.
Access to fetch at 'https://login.microsoftonline.com/xxxxxxxxxxxxxxxxxxxxxxxxxxxx/common/oauth2/v2.0/token' from origin 'http://localhost:3050' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
graphService.ts:81 POST https://login.microsoftonline.com//common/oauth2/v2.0/token net::ERR_FAILED
Thanks in Advance:)
You are getting cors error because Azure AD rejects the request when you include Origin header while using client_credentials. To start with You are using the client_credentials flow the wrong way.
Consider reading through this guide on client credentials flow to help you understand why its preferred for server side / daemon applications.
To see the error just add Origin header to postman and do the request again.
Also read here to understand the oauth2 flows that you can use
For your case, you can use authorization code flow because you have an SPA.
It is not the flow or configuration that is causing the issue. The real issue is front-end or SPA. IF you want to call the API for getting token with client Credential flow,You must follow either of the two approaches that is a mandatory thing I guess.
1.Daemon Services
2.Server side Implementation
I have called the API with Node and with same configuration as mention in the docs its working fine now.
msal-node npm package is an alternate to call the api or you can call the graph api by yourself.
async getAppTokenFromAzureAD() : Promise <any | Error> {
const requestHeaders : HeadersInit = new Headers();
var details = {
'client_secret' : 'xxxxxxxxxxxxxxxxxxxxxx',
'client_id':'xxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
'scope':'https://graph.microsoft.com/.default',
'grant_type':"client_credentials"
};
let formBody:any = [];
for (var property in details) {
var encodedKey = encodeURIComponent(property);
var encodedValue = encodeURIComponent(details[property]);
formBody.push(encodedKey + "=" + encodedValue);
}
formBody = formBody.join("&");
requestHeaders.set('Content-Type', 'application/x-www-form-urlencoded');
requestHeaders.set('Host','login.microsoftonline.com');
return new Promise((resolve,reject)=>{
this.connection.transaction(async (entityManager) => {
try {
let tokenResponse = fetch('https://login.microsoftonline.com/xxxxxxxxxxxxxxxxxxxx9/oauth2/v2.0/token',{
method : 'POST',
headers : requestHeaders,
body : formBody
})
tokenResponse.then(data=>data.json()).then(responses=>{
resolve({
statusMessage: getMessageByKey('apllicationTokenSuccess'),
responses,
})
}).catch(error=>{
reject(error);
})
} catch (error) {
reject(error)
}
})
})
}
Thanks
Good Day All,
I'm trying to do a POST request using the puppeteer headless chrome library. I can't seem to get the below code to work.
// Get csrf token
let token = await page.evaluate(() => document.querySelector('[name="CSRFToken"]').value);
let postResponse = await page.evaluate(async(token, cookies) => {
let response = fetch("/loyalty/points", {
method : 'POST',
cookie : cookies,
postData : 'CSRFToken=' + token,
}).then(response => response.text()).catch(error => console.log(error));
return response;
});
console.log('Final response');
console.log(postResponse);
I keep on getting an error that the CSRF token has not been set or that the cookie is invalid.
My question is, am I using the correct method in puppeteer to do a POST? If so, is there any way for me to do some debugging that I can see the actual POST request that was sent?
I appreciate any advice or help. Thanks
You are not creating a request body: hence the error. The postData attribute you set on the request object is not any known attribute, so it won't be set on the request either, meaning that the server will never see your CSRF token. You should look into the MDN docs on fetch().
I believe you should be all good by simply replacing postData with body, but it's hard to know without access to your endpoint. For all we know it might require special headers.
Given that you only post normal form data (which is implied by your key=value code), I would also start using the FormData objects provided by your browser to avoid manual coding of implementation details.
const formData = new FormData();
formData.append("CSRFToken", token);
const response = fetch("/loyalty/points", {
method : 'POST',
cookie : cookies,
body : formData,
headers : {
'cookie' : cookies,
/* other headers you need, possibly content-type (see below) */
},
}).then(response => response.text()).catch(error => console.log(error));
return response;
});
Caveat: using the FormData API will always set the content-type of the data to multipart/form-data. If your server for some reason doesn't support that encoding, and you need to use application/x-www-form-urlencoded (see here for difference),
you can't blindly change the Content-Type: you also need to url encode the content.
For debugging I would simply use a normal Chrome instance to see this. You should be able to run the code there and see the network requests in DevTools (where it would be immediately noticeable that you POST an empty request).
I am trying to call Twitters API and get a my tweets back so I can post them on a website I am creating.
When I run the following code I get an error.
XMLHttpRequest cannot load https://api.twitter.com/1.1/search/tweets.json?q=%SamSchaeferSays. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3333' is therefore not allowed access. The response had HTTP status code 400." And "bundle.js:30041 Uncaught (in promise) Error: Network Error.
I am new to API calls not using PHP - not sure what I am doing wrong here.
const tweet = 'https://api.twitter.com/1.1/search/tweets.json?q=%SamSchaeferSays';
function getUserTweet() {
return axios.get(`${tweet}`).then(function(response){
console.log(response.data)
console.log(response.status)
});
}
sample OAuth string
const DST = `OAuth oauth_consumer_key="${consumerKey}",
oauth_nonce="${}",
oauth_signature="${}",
oauth_signature_method="${}",
oauth_timestamp="${}",
oauth_token="${}",
oauth_version="1.0"
`;
A 400 Bad Request error means that the server doesn't understand your request. In your case there's a typo that prevents the request from going through (extra %). Try this:
const tweet = 'https://api.twitter.com/1.1/search/tweets.json?q=SamSchaeferSays';
function getUserTweet() {
return axios.get(`${tweet}`, { headers: { 'Authorization': 'YOUR_OAUTH_HEADER' } }).then(function(response){
console.log(response.data)
console.log(response.status)
});
}
This will fix the 400 Bad Request error, but you won't get any data back yet. The Twitter API requires you to authorize your request. Find out more in their documentation.
To allow applications to provide this information, Twitter’s API relies on the OAuth 1.0a protocol. At a very simplified level, Twitter’s implementation requires that requests needing authorization contain an additional HTTP Authorization header with enough information to answer the questions listed above. A version of the HTTP request shown above, modified to include this header, looks like this (normally the Authorization header would need to be on one line, but has been wrapped for legibility here):