Using this server configuration
import Cors from 'cors';
const cors = Cors({
methods: ['GET', 'POST', 'HEAD'],
allowedHeaders: 'X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version, X-Api-Authorize, X-Authorize',
credentials: true,
origin: (origin, callback) => {
console.log("*** TESTING", origin);
return callback(null, true); // debug, otherwise nothing works
},
optionsSuccessStatus: 200 // some legacy browsers (IE11, various SmartTVs) choke on 204
});
const applyCors = async (req, res) => new Promise((resolve, reject) => {
cors(req, res, (result) => {
if (result instanceof Error) {
reject(result);
} else {
resolve(result);
}
});
});
export const apiMiddleware = handler => async (req, res) => {
await applyCors(req, res);
// ... req is extended with utils
return handler(req, res);
};
And a client fetch request like
const response = await fetch(`/api/data`, {
credentials: 'same-origin', // also tried "include"
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'X-Api-Authorize': 'secret'
},
method: 'GET'
});
The server console.log always prints
*** TESTING undefined
When inspecting the request, I see the X-Api-Authorize header, but not Origin. What's missing?
fetch(`/api/data`
That's a relative URL, so you are making a same-origin request.
The origin header is only included in cross-origin requests.
(That's a simplification, as jub0bs points out, there are other times it will be included, but your code doesn't meet any of those conditions).
Related
NodeJs Code:
const express = require('express');
const port = 3000;
const router = express();
router.get('/', (req, res) => {
res.send('Hi');
})
var request = require('request');
var options = {
'method': 'GET',
'url': 'URL',
'headers': {
'Authorization': 'API_KEY'
}
};
request(options, function (error, response) {
if (error) throw new Error(error);
console.log(response.body);
});
router.listen(port, function(err) {
if(err) return;
console.log('Server Up');
})
JavaScript Code:
const options = {
method: 'GET',
headers: {
'Authorization': 'API_KEY'
}
};
fetch('URL', options)
.then(response => response.json())
.then(response => console.log(response))
.catch(err => console.error(err));
Error:
has been blocked by CORS policy: Response to preflight request doesn't
pass access control check: 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.
Am I missing a Header in JS or is the syntax wrong?
Note: The API I call to Get request is not my own.
This may solve your problem:
Install cors and add the following line to the node server file:
router.use(cors())
If it doesn't work, remove any headers config and try again.
I am working in a tiny project in react and express.js
the express.js code (Backend)
app.post('/api/search', (req, res) => {
//
res.setHeader("Access-Control-Allow-Origin", "*");
axios.get("[REDACTED]" + req.body.searchtxt + "&limit=100").then((response) => {
res.json({status: "ok", result: response.data})
})
})
and here the front-end
function SearchPage() {
const { searchText } = useParams()
const [SearchTxt, setSearchTxt] = useState(searchText)
useEffect(()=>{
fetch('http://localhost:8080/api/search', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
mode: 'cors',
body: JSON.stringify({searchtxt: searchText})
}).then((res) => {
res.json().then((resjson) => {
console.log(resjson)
})
})
},[])
}
but it shows this :
Access to fetch at 'http://localhost:8080/api/search' from origin 'http://localhost:3000'
has been blocked by CORS policy: Response to preflight request doesn't pass access control
check: 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.
I've tried with Access-Control-Allow-Origin set to localhost:3000 but it don't work
Browser sends OPTIONS preflight requests by default when sending a request. So, you should send Access-Control-Allow-Origin header for that request as well.
The easiest solution is to use cors middleware package. You can use it like this:
const cors = require('cors');
app.post('/api/search', cors(), (req, res) => {
res.setHeader("Access-Control-Allow-Origin", "*");
axios.get("[REDACTED]" + req.body.searchtxt + "&limit=100").then((response) => {
res.json({status: "ok", result: response.data})
})
})
In an Azure Function as a backend for my webpage, I requested an Azure AD publisher's authorization token as per this page instructed.
This is the line of codes of my Azure Functions:
// Stringfy request body
const postData = querystring.stringify({
'grant_type': 'client_credentials',
'client_id': client_id,
'client_secret': client_secret,
'resource': resource,
});
// Initiate options
var httpAgent = new http.Agent();
httpAgent.maxSockets = 200;
const options = {
hostname: 'login.microsoftonline.com',
path: `/${tenantId}/oauth2/token`,
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
agent: httpAgent,
}
const tokenReq = http.request(options, (res) => {
console.log(`STATUS: ${res.statusCode}`);
console.log(`HEADERS: ${JSON.stringify(res.headers)}`);
res.setEncoding('utf-8')
res.on('data', (chunk) => {
console.log(chunk);
body += chunk;
});
res.on('end', () => {
console.log('No more data in response.');
console.log("body:" + body);
context.res = {
status: 200,
body: body,
};
});
});
tokenReq.on('error', (e) => {
console.log(`problem with request: ${e.message}`);
context.res = {
status: 500,
body: `problem with request: ${e.message}`,
}
});
// write data to request body
tokenReq.write(postData);
tokenReq.end();
The expected response was the access token that I require, however running it locally I got STATUS 302, and a header containing a location and some other parameters, as a response. In my understanding STATUS 302 states that the URL is moved temporarily to the location provided in the header. Now, I don't know what I'm supposed to do, the request that I have to make is supposed to be a POST request so a redirection would not work. I've also tried to make a new request after receiving the redirect URL, but I got an error message saying: getaddrinfo ENOTFOUND {redirect URL from header}. What did I do wrong here?
The 302 error was caused by http module, you use require('http'); and http.request(options, (res).... to do the request, so it shows 302 error.
I suggest you to use var request = require('request'); to do the request, below is my function code for your reference (before use request module, you need to run npm install request to install it first):
module.exports = async function (context, req) {
context.log('JavaScript HTTP trigger function processed a request.');
var result = await generatetoken(context);
context.res = {
body: result
};
}
function generatetoken(context){
var request = require('request');
var options = {
'method': 'POST',
'url': 'https://login.microsoftonline.com/<your tenant id>/oauth2/token',
'headers': {
'Content-Type': 'application/x-www-url-form-urlencoded'
},
form: {
'client_id': 'xxxxxx',
'grant_type': 'client_credentials',
'resource': 'xxxxx',
'client_secret': 'xxxxx'
}
};
return new Promise(function(resolve, reject) {
request(options, function(err, res) {
if (err) {
reject(err);
} else {
context.log(res.body);
resolve(res.body);
}
})
})
}
I have method
router.post('/user',passport.authenticate('jwt', { session: false }), function (request, res) {
res.send(request.user);
});
and authorization token
"JWT eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyIkX18iOnsic3RyaWN0TW9kZSI6dHJ1ZSwic2VsZWN0ZWQi"
when i send request to this route from postman everything is working.
but when i send request from angular application with same token its throw with error unauthorized
getUser() {
const headers = new Headers();
headers.append('Content-Type', 'application/json');
headers.append('Authorization', localStorage.getItem('token'));
return this.http.post('localhost:8000/api/user/', {
headers
})
.map((data: Response) => data.json())
.catch((error: Response) => Observable.throw(error.json()));
}
Instead of sending headers like an header object, use RequestOptions to wrap it and then send it via your post request.
your code will be like:
import { Http, Headers, RequestOptions } from '#angular/http';
getUser() {
let headers = new Headers();
headers.append('Content-Type', 'application/json');
headers.append('Authorization', localStorage.getItem('token'));
let options = new RequestOptions({ headers: headers });
return this.http.post('https://dropali.com/api/user/',options)
.map((data: Response) => data.json())
.catch((error: Response) => Observable.throw(error.json()));
}
Also a suggestion instead of getting your token while your post request retrieve it first in a variable and check if it's there or not, If not then do whatever is necessary if it is successfully retrieved then make post request.
1.) Check at the server side you are getting the token or not.
2.) if you are not getting the token then check Developer option > Network > your request's header tag and see whether the token is going or not
3.) if not going the problem is in a front and else it can because of cross origin..
FRONT END CODE EXAMPLE
var token = localStorage.Authorization
var options = {
url: '/user',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': token
}
}
$http(options)
.then((data) => console.log(data.data))
.catch((error) => console.log(error));
if front end is ok then you should check CROSS
app.use((req, res, next) => {
res.header('Access-Control-Expose-Headers', 'Authorization');
next();
})
OR
npm install cors --save
app.use(cors());
Using Axios
export function sendAll() {
return (dispatch) => {
dispatch(requestData());
return axios({
method: 'POST',
url: `${C.API_SERVER.BASEURL}/notification/sendAll`,
data: {prop: 'val'},
// responseType: 'json',
headers: {
'Content-Type': 'application/json'
},
withCredentials: true
}).then((response) => {
dispatch(receiveData(response));
}).catch((response) => {
dispatch(receiveError(response));
// dispatch(pushState(null, '/error'));
})
}
};
Result using Axios
Using $.ajax
$.ajax({
url: " http://local.example.com:3001/api/notification/sendAll",
method: "post",
data: {},
crossDomain: true,
xhrFields: {
withCredentials: true
}
})
Result using $.ajax
I am unable to force Axios to send a POST when trying to attach data to POST (cookie doesnt get sent either way).
My server setup (express):
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", `${C.PROTOCOL}://${C.DOMAIN}:${C.PORT}`);
res.header("Access-Control-Request-Headers", "*");
res.header('Access-Control-Allow-Methods', 'GET, POST, DELETE, OPTIONS');
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");
res.header("Access-Control-Allow-Credentials", "true");
next();
});
I do not have a OPTIONS route defined. I want Axios to send POST with cookie.
router.post('/notification/sendAll', function (req, res, next) {
res.sendStatus(204);
// ...
});
I was facing a similar issue. Making a get/post request through Axios did not sent the same headers as a straight XHR request.
Then I just added the following just after the Axios require statement:
axios.defaults.withCredentials = true;
After that Axios started sending my cookie like the regular XHR request did.
Working example using Danielo515's answer:
import * as axios from 'axios';
axios.defaults.withCredentials = true;
export function getAll() {
const url = 'https://example.com';
return axios.get(url);
}