I'm developing on webpack-dev-server.
When I try to access http://api.openweathermap.org/data/2.5/forecast?id=2848756&appid={api_key}, I couldn't access and I can see a this log.
XMLHttpRequest cannot load http://api.openweathermap.org/data/2.5/forecast?id={api_key}. Response for preflight has invalid HTTP status code 405
I try to set on webpack.config.js. it's like bellow setting.
devServer: {
contentBase: 'dist',
inline: true,
hot:true,
port: 8081,
proxy: {
'/**': {
target: 'http://api.openweathermap.org',
secure: false
}
}
But It still doesn't work. do you know how to resolve it?
Let me know about that. thanks!
Try removing the headers property from your axios.create() call, they don't make sense (the Access-Control-* ones are response headers, not request headers, and withCredentials is an option, not a header) and may confuse the browser into thinking it needs to perform a CORS preflight that doesn't look like it's supposed by the OpenWeather API server:
const apiClient = API_URL => {
return axios.create({
baseURL : API_URL,
timeout : 100000,
withCredentials : 'true'
});
};
You will have to Register on open weather API website after that you will get API key which you will have to use for calling API
in your case while calling
http://api.openweathermap.org/data/2.5/forecast?id=2848756&appid={api_key}
please insert api_key after registration in above call.
suppose after registration you get api_key as =xxxxxxx
use it in above call
http://api.openweathermap.org/data/2.5/forecast?id=2848756&appid=xxxxxxx
then and then you will receive data in JSON response.
for more information visit
https://openweathermap.org/appid
Related
I am working on a small project where users authenticate using their email and password before accessing their profile. The backend uses cookies which are set when correct email and password are submitted to the auth API. I have created an instance of axios to handle the api calls and here is how it looks:
// Step-1: Create a new Axios instance with a custom config.
// The timeout is set to 10s. If the request takes longer than
// that then the request will be aborted.
const customAxios = axios.create({
...apiConfig,
timeout: 10000,
withCredentials: true,
// custom headers can be added here as shown below
// headers: { 'api-key': 'eyJz-CI6Ikp-4pWY-lhdCI6' }
});
// Step-2: Create request, response & error handlers
const requestHandler = (request) => {
request.headers["Accept"] = "application/json";
request.headers["Content-Type"] = "application/json";
return request;
};
const errorHandler = (error) => {
return Promise.reject(error);
};
customAxios.interceptors.request.use(
(request) => requestHandler(request),
(error) => errorHandler(error)
);
customAxios.interceptors.response.use(
(response) => responseHandler(response),
(error) => errorHandler(error)
);
The point is, whenever I try to call the auth API with correct credentials, it returns success but the Set-Cookie header in the response has a warning and the cookies are not set in the browser. Here is the warning:
"The attempt to set cookie using a Set-Cookie was block because it had the "SameSite=Strict" attribute but came from a cross-site response which was not the response to the top-level navigation"
Bear in mind that I am testing the API locally on port 3000 while the endpoint is deployed on a testing server using Chrome.
Thanks
Sounds like your dev setup with two different origins is the problem (and hey, your security policies are working!) Disable the SameSite=Strict in development mode, or extend it to also accept cookies from localhost:3000 (the API domain), not just the same domain where the frontend is served. Also make sure this will be disabled only in the dev setup
From my React JS app , I need to fetch data from servers in other domains.
However, I am prevented by CORS policy and not able to fetch the data.
Let us assume that my React app is running on localhost:3000 during the development.
I want to make get/post call to another server running on http://myserver.com
The URL through which I want to fetch the data is http://ext-server.com/data/records?name=xyz
I have installed http-proxy-middleware thru npm and using it in my react app.
Created a setupProxy.js file under src folder with below content :
const { createProxyMiddleware} = require("http-proxy-middleware")
module.exports = app => {
app.use(
createProxyMiddleware('/data/records' , {
target:'http://ext-server.com',
changeOrigin: true
})
)
}
On the landing page of my react app (firstpage.js) when http://localhost:3000 is hit , I have added below piece of code to the button event that makes the get call to the http://ext-server.com
getTheData() {
let url = "http://ext-server.com/data/records?name=" + encodeURIComponent(this.state.name);
axios.get(url,
{
headers: {
"Content-Type":"application/json;charset=UTL-8",
"Access-Control-Allow-Origin": "*",
Accept: "application/json",
},
baseURL: 'http://ext-server.com'
}
).then((response) => {
console.log(response["access_token"]);
}).catch(error) => {
console.log("Error: ", error)
}).then(function () {
console.log("always call it")
});
}
In the package.json , I have added :
"proxy": "http://ext-server.com",
"homepage":"http://localhost:3000",
But I am still getting below error:
Access to XMLHttpRequest at 'http://ext-server.com/data/records?name= ' from origin 'http://localhost:3000' has been blocked by CORS policy.
Is there anything that I am missing here ? what is the correct way to use this http-proxy-middleware?
Any help will be very useful!
Thanks
As you can see from MDN the "Access-Control-Allow-Origin": "*" header is a response type header, this means that it should go to in your server response. Also I advise you to not use the * symbol, instead I would rather match it with the origin header in your Request.
The CORS policy is one and only administered by the web server and its settings. To allow CORS requests it has to be implemented on server side. No chance to do it from your client application.
Basically its just a header setting (below example for NodeJS):
res.header("Access-Control-Allow-Origin", "*")
Sending that header will allow requests from every domain.
In this test case am sending an axios post request with userId and password to ExpressJS server running with passportjs local. Server respond with status code 200, and send appropriate header with set-cookie.
I need subsequent request to be treated as authorized request, for that tried following options, but none seems to be working. It getting rejected with status code 401.
First call with userid and password, responded with status 200
const userDoc = {
userId: 'test-user-1',
userName: 'Test User 1',
emailId: 'test.user.1#abc.xom',
password: 'test-password'
} ;
let resp
resp = await axios({method : 'post', url : 'http://localhost:4040/auth/local', data : {userId: userDoc.userId, password: userDoc.password },withCredentials: true })
following options are used to send next request
send cookies received as part of 1st request
const headers = { headers : {Cookie: resp.headers['set-cookie'][0] } };
send header as it is received as part of 1st request
const headers = { headers : resp.headers};
send withCredentials: true along with above headers.
Second call is made with either of above option
resp = await axios({method : 'post', url : 'http://localhost:4040/v1/master/account', data : accountDoc , headers, withCredentials: true})
used httpAgent, keepAlive with axios instance
const axios = require('axios')
const http = require("http")
const httpAgent = new http.Agent({keepAlive : true , timeout :1000})
const instance = axios.create({httpAgent})
const resp1 = await instance({method : 'post', url : 'http://localhost:4040/auth/local', data : {userId: userDoc.userId, password: userDoc.password, } , withCredentials: true })
const resp2 = await instance({method : 'post', url : 'http://localhost:4040/v1/master/account', data : accountDoc , withCredentials: true })
Rejected with status code 401
-- Error: Request failed with status code 401
at createError (/home/Projects/FinAccounts2003/node_modules/axios/lib/core/createError.js:16:15)
at settle (/home/Projects/FinAccounts2003/node_modules/axios/lib/core/settle.js:17:12)
at IncomingMessage.handleStreamEnd (/home/Projects/FinAccounts2003/node_modules/axios/lib/adapters/http.js:269:11)
at IncomingMessage.emit (events.js:412:35)
at endReadableNT (internal/streams/readable.js:1334:12)
at processTicksAndRejections (internal/process/task_queues.js:82:21)
Server code is standard passport-js local code, which working well with browser.
It may be duplicate of some of the questions, solutions given are 1) withCredentials: true, already tried above 2) Authorization: Bearer ${token} - not applicable in this case, in passport js, cookie is directly set, and not getting token.
One solution that worked for me was using the modules tough-cookie and axios-cookiejar-support. I combined them in a persistent-client.js file, and then I was able to maintain the session between requests (commonJS):
const axios = require('axios').default;
const { CookieJar } = require('tough-cookie');
const { wrapper } = require('axios-cookiejar-support');
module.exports = function () {
const jar = new CookieJar();
const client = wrapper(axios.create({ jar }));
return client;
}
There are two different ways to send the session authorization token from the server to the client (web browser)
Via (HttpOnly) response headers.
Via the response body.
And there are two different ways to authorize client requests (send the session token from the web browser to the server.)
A. Automatic: HttpOnly headers
B. Manual: Authorization: Bearer [TOKEN]
Usually method 1 is used with method A, and method 2 is used with method B. I think you are mixing them up.
If the server is using Set-Cookie to send the session token, then I think the browser automatically sends the session token automatically on all future requests (to the same domain).
Can you confirm what the actual contents of the set-cookie header are from the server? Note you will probably not be able to check this via JS if these are HttpOnly cookies; inspect the dev console "Network" tab. You can also check to see if any new cookies were set from the "Application" tab.
If the client does actually need to manually send the token via headers, the header needs to fit a specific Authorization cookie format. (Which you are not doing. You are simply echoing the headers received from the server.)
See my response to a similar question.
I don't believe you should be using any third party packages for this, especially not if they're directly accessing the cookies using javascript (which is an XSS security vulnerability). Cookies should be set using secure and http-only and never be accessed using Document.cookie directly.
Make sure that passport is actually setting your cookie and that you're correctly sending back the cookie on the login. Verify that it's been set in your browser.
Make sure that you have CORS enabled in express, that you've specified the domain you're making requests from and that you've enabled credentials in CORS.
Make sure that you're using withCredentials on your axios requests.
Make sure that you've set the cookie using the correct domain and path.
I have created CORS middleware using CORS package. This middleware will be called before each call. Here is my implementation.
const corsMiddleware = async (req, callback) => {
const { userid } = req.headers|| req.cookies {};
let whiteList = await getWhiteListDomains(userid)
return callback(null, {
origin: whiteList,
credentials: true,
allowedHeaders: ["userid", "authorization", "content-type"]
});
};
And added this middleware before route initialization as
app.use(cors(corsMiddleware));
app.options("*", cors(corsMiddleware));
app.get("/user", (req, res, next)=>{
// code
})
From Browser I am trying to call the API as
axios({ method: "get", url: "http://localhost:3000/user", headers: {userId:"1234"} });
While debugging on the server I see
access-control-request-headers:"userid"
in the headers of the request object.
I am not able to read the custom header. This might be happening because I am trying to read the custom header before CORS initialization. But still, I want to read that custom header.
You have mainly two problems in your code.
First one, and easier to solve is that you are missing access-control-allow-origin in the option that sets the Access-Control-Allow-Headers:
return callback(null, {
origin: whiteList,
credentials: true,
allowedHeaders: [
"access-control-allow-origin",
"authorization",
"content-type",
"userid"
]
});
The second one is the most important because it is related to how CORS works.
This problem you are having is that CORS is already rejecting the petition in the pre-flight OPTIONS request. It never allows the browser to execute the GET request.
You say that you want to read the custom header userId in the pre-flight OPTIONS request but you can't. The reason is because the pre-flight OPTIONS request is created by the browser automatically and it won't use the custom headers you are setting up in the Axios call. It will only send these headers for the CORS:
Origin // URL that makes the request
Access-Control-Request-Method // Method of the request is going to be executed
Access-Control-Request-Headers // Headers allowed in the request to be executed
Because your custom header is not being sent so in the pre-flight OPTIONS when you try to access the value of userId, you get an undefined value:
const { userid } = req.headers|| req.cookies;
console.log(userid); // undefined
And because you are using that value that is not matching in your async function getWhiteListDomains probably getting another undefined, the value set up in the origin option of the CORS middleware is undefined that provokes the CORS middleware rejects the pre-flight OPTIONS request.
let whiteList = await getWhiteListDomains(userid); // userid === undefined
console.log(whitelist); // undefined
return callback(null, {
origin: whiteList, // undefined
credentials: true,
allowedHeaders: ["userid", "authorization", "content-type"]
});
I am not totally sure which is your goal trying to use your custom header as CORS check, but my advise would be when dealing with customised CORS configuration to only check the Origin header because that's its purpose: to limit and control which URLs can access to your server and resources.
If you are interested in creating any kind of authorisation or limited by user implementation in the requests received by your server, I suggest you to use a different custom middleware and not involve CORS at all like you are trying now.
you must parse your request
try this
npm i body-parser
and
const bodyParser = require('body-parser');
app.use(bodyParser.json())
I use axios for calling API (in front-end).
I use the method "GET" :
import axios from 'axios';
import querystring from 'querystring';
var url = "mydomain.local",
token = "blablabla...blabla";
var configs = {
headers: {
'Authorization': 'Bearer ' + token,
'Agency': 'demo0'
}
};
var testapi = axios.create({
baseURL: 'http://api.' + url
});
testapi.get( '/relativeUrl', configs
).then(function (response) {
console.log(response);
}).catch(function (error) {
console.log(error);
});
I got a 405 Method Not Allowed. The method is "OPTIONS" but I use the method ".get()".
405 Method Not Allowed. Method OPTIONS
I test call api with postman and I get 200 OK :
postman 200 OK screenshot
Anyone has an idea ?
Like #Shilly says, OPTIONS method is pre-flight on modern browsers when Preflighted requests conditions (MDN) :
In the response header I had Allow:"GET, HEAD, POST, PUT, DELETE".
So OPTIONS method is not available and need to configure it on in the server (Apache).
I do the change on apache (/etc/apache2/sites-available/000-default.conf) :
Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Headers "*"
Header set Access-Control-Allow-Methods "PUT, GET, POST, DELETE, OPTIONS"
In Request headers I have :
Origin: "null" is a problem. The cause is :
file:// URLs produce a null Origin which can't be authorized via
echo-back. Don't trying to perform a CORS request from a file:// URL (see this post for more details)
After put my javascript file on a apache server, the Origin was not null but I need to add NelmioCorsBundle to my Symfony project to allow preflight
So the way to solve this npm install qs.
Then:
import qs from 'qs'
function send(params) {
return axios.post('/api/create/', qs.stringify(params))
}