Using the Nextjs getServerSideProps function I make a fetch request to my API. My API checks origin headers for CORS but gets the origin header as undefined. Why is this happening and is there a way around this?
I get origin headers while making fetch requests normally from the browser in Next. This issue only occurs when the request is made to the API via the server from Nextjs getServerSideProps.
What I did was adding the Origin parameter to the header object in the fetch request and adding the url from the .env file to easily change it for production.
//Create fetch's options
const options = {
mode: 'cors',
method: 'GET',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
Origin: `${process.env.NEXT_PUBLIC_FRONT_URL}`,
},
};
//Fetch data from the API
const res = await fetch('changeForYouURL', options);
Related
I am trying out the new Fetch API but is having trouble with Cookies. Specifically, after a successful login, there is a Cookie header in future requests, but Fetch seems to ignore that headers, and all my requests made with Fetch is unauthorized.
Is it because Fetch is still not ready or Fetch does not work with Cookies?
I build my app with Webpack. I also use Fetch in React Native, which does not have the same issue.
Fetch does not use cookie by default. To enable cookie, do this:
fetch(url, {
credentials: "same-origin"
}).then(...).catch(...);
In addition to #Khanetor's answer, for those who are working with cross-origin requests: credentials: 'include'
Sample JSON fetch request:
fetch(url, {
method: 'GET',
credentials: 'include'
})
.then((response) => response.json())
.then((json) => {
console.log('Gotcha');
}).catch((err) => {
console.log(err);
});
https://developer.mozilla.org/en-US/docs/Web/API/Request/credentials
Have just solved. Just two f. days of brutforce
For me the secret was in following:
I called POST /api/auth and see that cookies were successfully received.
Then calling GET /api/users/ with credentials: 'include' and got 401 unauth, because of no cookies were sent with the request.
The KEY is to set credentials: 'include' for the first /api/auth call too.
If you are reading this in 2019, credentials: "same-origin" is the default value.
fetch(url).then
Programmatically overwriting Cookie header in browser side won't work.
In fetch documentation, Note that some names are forbidden. is mentioned. And Cookie happens to be one of the forbidden header names, which cannot be modified programmatically. Take the following code for example:
Executed in the Chrome DevTools console of page https://httpbin.org/, Cookie: 'xxx=yyy' will be ignored, and the browser will always send the value of document.cookie as the cookie if there is one.
If executed on a different origin, no cookie is sent.
fetch('https://httpbin.org/cookies', {
headers: {
Cookie: 'xxx=yyy'
}
}).then(response => response.json())
.then(data => console.log(JSON.stringify(data, null, 2)));
P.S. You can create a sample cookie foo=bar by opening https://httpbin.org/cookies/set/foo/bar in the chrome browser.
See Forbidden header name for details.
Just adding to the correct answers here for .net webapi2 users.
If you are using cors because your client site is served from a different address as your webapi then you need to also include SupportsCredentials=true on the server side configuration.
// Access-Control-Allow-Origin
// https://learn.microsoft.com/en-us/aspnet/web-api/overview/security/enabling-cross-origin-requests-in-web-api
var cors = new EnableCorsAttribute(Settings.CORSSites,"*", "*");
cors.SupportsCredentials = true;
config.EnableCors(cors);
This works for me:
import Cookies from 'universal-cookie';
const cookies = new Cookies();
function headers(set_cookie=false) {
let headers = {
'Accept': 'application/json',
'Content-Type': 'application/json',
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
};
if (set_cookie) {
headers['Authorization'] = "Bearer " + cookies.get('remember_user_token');
}
return headers;
}
Then build your call:
export function fetchTests(user_id) {
return function (dispatch) {
let data = {
method: 'POST',
credentials: 'same-origin',
mode: 'same-origin',
body: JSON.stringify({
user_id: user_id
}),
headers: headers(true)
};
return fetch('/api/v1/tests/listing/', data)
.then(response => response.json())
.then(json => dispatch(receiveTests(json)));
};
}
My issue was my cookie was set on a specific URL path (e.g., /auth), but I was fetching to a different path. I needed to set my cookie's path to /.
If it still doesn't work for you after fixing the credentials.
I also was using the :
credentials: "same-origin"
and it used to work, then it didn't anymore suddenly, after digging much I realized that I had change my website url to http://192.168.1.100 to test it in LAN, and that was the url which was being used to send the request, even though I was on http://localhost:3000.
So in conclusion, be sure that the domain of the page matches the domain of the fetch url.
I am trying out the new Fetch API but is having trouble with Cookies. Specifically, after a successful login, there is a Cookie header in future requests, but Fetch seems to ignore that headers, and all my requests made with Fetch is unauthorized.
Is it because Fetch is still not ready or Fetch does not work with Cookies?
I build my app with Webpack. I also use Fetch in React Native, which does not have the same issue.
Fetch does not use cookie by default. To enable cookie, do this:
fetch(url, {
credentials: "same-origin"
}).then(...).catch(...);
In addition to #Khanetor's answer, for those who are working with cross-origin requests: credentials: 'include'
Sample JSON fetch request:
fetch(url, {
method: 'GET',
credentials: 'include'
})
.then((response) => response.json())
.then((json) => {
console.log('Gotcha');
}).catch((err) => {
console.log(err);
});
https://developer.mozilla.org/en-US/docs/Web/API/Request/credentials
Have just solved. Just two f. days of brutforce
For me the secret was in following:
I called POST /api/auth and see that cookies were successfully received.
Then calling GET /api/users/ with credentials: 'include' and got 401 unauth, because of no cookies were sent with the request.
The KEY is to set credentials: 'include' for the first /api/auth call too.
If you are reading this in 2019, credentials: "same-origin" is the default value.
fetch(url).then
Programmatically overwriting Cookie header in browser side won't work.
In fetch documentation, Note that some names are forbidden. is mentioned. And Cookie happens to be one of the forbidden header names, which cannot be modified programmatically. Take the following code for example:
Executed in the Chrome DevTools console of page https://httpbin.org/, Cookie: 'xxx=yyy' will be ignored, and the browser will always send the value of document.cookie as the cookie if there is one.
If executed on a different origin, no cookie is sent.
fetch('https://httpbin.org/cookies', {
headers: {
Cookie: 'xxx=yyy'
}
}).then(response => response.json())
.then(data => console.log(JSON.stringify(data, null, 2)));
P.S. You can create a sample cookie foo=bar by opening https://httpbin.org/cookies/set/foo/bar in the chrome browser.
See Forbidden header name for details.
Just adding to the correct answers here for .net webapi2 users.
If you are using cors because your client site is served from a different address as your webapi then you need to also include SupportsCredentials=true on the server side configuration.
// Access-Control-Allow-Origin
// https://learn.microsoft.com/en-us/aspnet/web-api/overview/security/enabling-cross-origin-requests-in-web-api
var cors = new EnableCorsAttribute(Settings.CORSSites,"*", "*");
cors.SupportsCredentials = true;
config.EnableCors(cors);
This works for me:
import Cookies from 'universal-cookie';
const cookies = new Cookies();
function headers(set_cookie=false) {
let headers = {
'Accept': 'application/json',
'Content-Type': 'application/json',
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
};
if (set_cookie) {
headers['Authorization'] = "Bearer " + cookies.get('remember_user_token');
}
return headers;
}
Then build your call:
export function fetchTests(user_id) {
return function (dispatch) {
let data = {
method: 'POST',
credentials: 'same-origin',
mode: 'same-origin',
body: JSON.stringify({
user_id: user_id
}),
headers: headers(true)
};
return fetch('/api/v1/tests/listing/', data)
.then(response => response.json())
.then(json => dispatch(receiveTests(json)));
};
}
My issue was my cookie was set on a specific URL path (e.g., /auth), but I was fetching to a different path. I needed to set my cookie's path to /.
If it still doesn't work for you after fixing the credentials.
I also was using the :
credentials: "same-origin"
and it used to work, then it didn't anymore suddenly, after digging much I realized that I had change my website url to http://192.168.1.100 to test it in LAN, and that was the url which was being used to send the request, even though I was on http://localhost:3000.
So in conclusion, be sure that the domain of the page matches the domain of the fetch url.
I'm trying to consume this endpoint at the api-football.com
Here is their documentation: https://www.api-football.com/documentation-beta#section/Authentication
The error is: Access to XMLHttpRequest at 'https://v3.football.api-sports.io/teams?id=40' from origin 'http://localhost:4200' has been blocked by CORS policy: Request header field x-rapidapi-host is not allowed by Access-Control-Allow-Headers in preflight response.
Here is my code:
httpOptions.headers = new HttpHeaders({
// 'Access-Control-Allow-Origin': '*',
// 'Access-Control-Allow-Methods': 'GET',
// 'Accept': '*/*',
'Content-Type': 'application/json',
'x-rapidapi-host': 'v3.api-football.com',
'x-rapidapi-key': this._publicKey,
});
const url = 'https://v3.football.api-sports.io/teams?id=40';
return this.http.get<any>(url, httpOptions)
.pipe(
catchError(this.handleError('getLiverpool', []))
);
I understand what CORS is, but not how to fix it in this case? I am using Angular 9.
Ehy!
the easiest solution would be to use your back-end as middleware to send the request to the 3rd party API. This and other more complex alternatives here
the problem is the server, it needs to accept your request.
If once deployed they are going to be in the same server, you can disable cors in your browser, if not, you have to update the server
I'm making a POST request to a node.js server and I'm having trouble getting it to work. Here's my request:
const headers = {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': 'this-can-be-anything',
};
export const postVote = (id, vote) =>
fetch(`${uri}/posts/${id}`, {
method: 'POST',
headers,
body: JSON.stringify({options: vote}),
}).then(response => response.json())
.then(data => data)
.catch(err => console.log(err));
The function accepts an 'id' and a 'vote', both strings. The id is being used as part of the URI in the request, and the vote is being supplied as options so the API knows what to do with it. Both of the arguments are being passed correctly:
id = '8xf0y6ziyjabvozdd253nd'
vote = 'upVote'
Here's a link to the GitHub repository for the server/API:
Udacity Readable API
and a screenshot of the network when firing the request:
UPDATE: Added the second screenshot which shows status 200. Though it shows this and appears to have been successful, it still doesn't post to the server and the information stays the same.
What you are looking at is the OPTIONS request in the network tab. For cross origin requests, every request if preceeded by an OPTIONS request which tells the calling client (browser, for example) if those HTTP methods are supported by the remote server for use in crosss origin context.
Check the other requests out. If the OPTIONS request was responded to correctly by the server, the browser must automatically follow up with your POST request
EDIT:
Also, the docs specify the param name to be option whereas in your screenshot it is coming up as options.
Further reading: CORS
Try declaring the headers as such:
var headers = new Headers({
'Content-Type': 'application/json',
'Authorization': 'this-can-be-anything',
})
I am trying to add a custom header, X-Query-Key, to a HTTP request using Fetch API or request but when I add this to the header of the request it appears to fail at setting the headers and the Request Method is set to OPTIONS for some reason.
When I remove the header it goes back to being GET as it should do.
Sample code looks like below:
const options = {
url: url,
headers: {
'Accept': 'application/json',
'X-Query-Key': '123456' //Adding this breaks the request
}
};
return request(options, (err, res, body) => {
console.log(body);
});
Try this:
const headers = new Headers({
"Accept": "application/json",
"X-Query-Key": "123456",
});
const options = {
url: url,
headers: headers
};
return request(options, (err, res, body) => {
console.log(body);
});
If that does not solve the issue, it may be related to CORS.
Custom headers on cross-origin requests must be supported by the
server from which the resource is requested. The server in this
example would need to be configured to accept the X-Custom-Header
header in order for the fetch to succeed. When a custom header is set,
the browser performs a preflight check. This means that the browser
first sends an OPTIONS request to the server to determine what HTTP
methods and headers are allowed by the server. If the server is
configured to accept the method and headers of the original request,
then it is sent. Otherwise, an error is thrown.
So you will have 2 requests if use custom headers, first one with method OPTIONS to check if server allows custom headers and after that if the server response is 200 OK and allows your originary request the second one will be send
Working with the Fetch API