withCredentials and wildcard * - 'Access-Control-Allow-Origin' header issue - javascript

I have an app in nodejs that will serve as a proxy to connecting to various social platforms. The flow is like this:
Click on a button, open a new window
Before closing a window, add access token to cookie (for now the app is on localhost, so the token is on that domain) as a nonce and add it to database.
Once the modal closes, go to another endpoint that will take that nonce from cookie, search in db, and return the token.
Here is the issue, after sending AJAX request for step 3, CORS issue occurs. This is the code:
jQuery.ajax({
url: "http://localhost:9057/facebook/gettoken",
type: 'GET',
dataType: "json",
xhrFields: {
// -->> In order to access the cookie, we have to have this set as true.
withCredentials: true
},
crossDomain: true,
success: function (res) {
console.log(res);
}
});
In my NodeJS app, I have cors set up as:
if (config.getOption('PORT')) {
const corsOptions = {
credentials: true
};
app.use(cors(corsOptions));
// -->> I cannot have * here here, withCredentials cannot be set to true and have *, see the error below
app.options('*', cors(corsOptions));
}
This is the error:
Access to XMLHttpRequest at 'http://localhost:9057/facebook/gettoken' from origin 'http://something.test:8080' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
I cannot whitelist the domains that 'http://something.test:8080' represents as they will be user websites.
Anyone knows a workaround, if there is one?

See the docs.
They give an example of how to use a dynamic origin:
var whitelist = ['http://example1.com', 'http://example2.com']
var corsOptions = {
origin: function (origin, callback) {
if (whitelist.indexOf(origin) !== -1) {
callback(null, true)
} else {
callback(new Error('Not allowed by CORS'))
}
}
}
If you can't whitelist, then just remove the test for the whitelist!
var corsOptions = {
origin: function (origin, callback) {
callback(null, true)
}
}

Related

Getting error to make an API Post Call using simple HTML

Without adding mode as 'no-cors':
Error : APICALL.html:1 Access to fetch at 'http://url' from origin 'null' 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 have added mode as 'no-cors' but then i get another error of Bad Request.
Error : APICALL.html:66 POST http://url net::ERR_ABORTED 400 (Bad Request)
Code :
var data = {
Name: "Test",
Category: "Test-Category",
Mobile: "999999999999",
Email: "test#gmail.com",
Question: "Test Question",
};
var options = {
method: "POST",
mode: "no-cors",
origin: "*",
cache: "no-store",
headers: {
"Cache-Control": "no-store",
"Content-Type": "application/json",
},
body: data,
};
fetch("http://url", options)
.then((data) => {
if (!data.ok) {
throw Error(data.status);
}
return data.json();
})
.then((update) => {
console.log(update);
})
.catch((e) => {
console.log(e);
});
Chinese: 因为存在跨域情况,需要后端服务器开启跨域,允许你访问。
English: The server is not enabled to allow this port to cross domains because of cross domain conditions

Firebase authorization bearer token not registering

Error message: No Firebase ID token was passed as a Bearer token in the Authorization header. Make sure you authorize your request by providing the following HTTP header: Authorizaiton: Bearer or by passing a "__session" cookie
There actually is a valid token. This same setup works in other functions but not here. The main difference is that this is a delete instead of a post.
firebase
.auth()
.currentUser.getIdToken(true)
.then((token) => {
console.log(token)
return axios.delete(
`${FunctionsDir}/deleteMessage`,
{
messageID: messageID,
},
{
headers: {
Authorization: `Bearer ${token}`,
'content-type': 'application/octet-stream',
},
}
)
})
and the cors setup...
var corsOptions = {
origin: function (origin, callback) {
if (whitelist.indexOf(origin) !== -1 || !origin) {
callback(null, true)
} else {
callback(new Error('Not allowed by CORS'))
}
},
allowedHeaders: 'Content-Type,Authorization',
methods: 'GET,POST,DELETE',
preflightContinue: false,
optionsSuccessStatus: 200,
}
app.options('*', cors())
app.use(cors(corsOptions))
Update: Fixed, turned out to be the cors thing plus the axios.delete() sig was wrong.
This is likely a CORS issue that needs to be solved on the server.
This is because DELETE requests need to make a pre-flight request to the server asking what is acceptable to send. Because you got a response from your server, it is likely that you have already added DELETE to your Access-Control-Allow-Methods header. However, Authorization isn't considered a "safe header" by default. So you must also explicitly allow it, otherwise browsers will remove it from the request as they send it off. You can do this by adding Authorization to your Access-Control-Allow-Headers header.
If you are using Express on your server, you can allow the cors package to do this for you:
import express from "express";
import cors from "cors";
const app = express();
app.options("/deleteMessage", cors()); // enable preflight request for DELETE
app.use(cors({ origin: ["https://yourapp.com"] })); // enable CORS for all routes
// ...
If you don't like making use of third-party dependencies, you can manually add the headers as shown in this answer.
For non-express requests, like a HTTP Request Cloud Function, you can use the following code:
import express from "express";
import cors from "cors";
const corsMiddleware = cors({ origin: ["https://yourapp.com"] }); // or your manual (req, res, next) function
export const someFunction = functions.https.onRequest((req, res) => {
corsMiddleware(req, res, (err) => {
if (err) {
res.status(500).send('CORS check failed');
return;
}
// your code here
}
})

Authorized Firebase request to Cloud Functions HTTP return preflight request does not pass control check (No Access-Control-Allow-Origin)

I am trying to send authorized Firebase requests to HTTP Cloud Functions following the official documentation.
However, I keep getting the error message:
Access to XMLHttpRequest at '[CLOUD-FUNCTION-SOURCE-URL]' from origin
'http://127.0.0.1:8080' 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.
I tried the following:
def cors_enabled_function_auth(request):
# For more information about CORS and CORS preflight requests, see
# https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request
# for more information.
# Set CORS headers for preflight requests
if request.method == 'OPTIONS':
# Allows POST requests from origin * Authorization header
headers = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST',
'Access-Control-Allow-Headers': ['Authorization', 'Content-Type'] ,
'Access-Control-Max-Age': '3600',
'Access-Control-Allow-Credentials': 'true'
}
return ('', 204, headers)
# Set CORS headers for main requests
headers = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': 'true'
}
print('core logic here')
return ('Hello World!', 200, headers)
On the front (using AngularJS) I make a request as follows:
self.getDownloadUrl = function(gcs_reference) {
var url = '[CLOUD-FUNCTION-URL]';
var params = {'param1': 'hello'};
var headers = {
'Content-Type': 'application/json'
}
return firebase.auth().onAuthStateChanged().then(
function (user) {
headers['Authorization'] = user['refreshToken']
return postRequestHTTP(params, url, headers)
},
function (error) {
console.log('error', error)
return error;
}
)
};
function postRequestHTTP(params, url, headers) {
// Generic HTTP post request to an url with parameters
var q = $q.defer();
var body = params;
var req = {
headers: headers
};
$http.post(url, body, req).then(
function(response) {
q.resolve(response)
}, function(error) {
q.reject(error)
}
);
return q.promise;
}
Does anyone know what is the cause of this heresy?
I can't reproduce this. With your function and a request like:
function reqListener () {
console.log(this.responseText);
}
xhr = new XMLHttpRequest();
xhr.open('POST', "[CLOUD-FUNCTION-URL]");
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.addEventListener("load", reqListener);
xhr.send('test');
I get a successful request. Perhaps the latest version of your function is not actually deployed, or your frontend is pointing at a different endpoint?

Angular 6 Http request fails with authorization headers

I'm deploying and angular 6 application that works with a tomcat server in localhost, when I try to execure this http request
this.http
.post<LoginResult>( API_URL + '/login', JSON.stringify(json)/*, { headers: myHeader }*/).pipe(
catchError(this.handleError('get-token', []))).subscribe((response) => {
if(response['result_code'] == 'result_ok') {
this.auth.doSignIn(response['token'], response['name']);
this.router.navigate(['user_manager']);
return true;
}else {
return false;
}
});
everitying works well, but when I add header field
let myHeader = new HttpHeaders().append("Authorization", 'Basic' + this.session.getAccessToken());
this.http
.post<LoginResult>( API_URL + '/login', JSON.stringify(json), { headers: myHeader }).pipe(
catchError(this.handleError('get-token', []))).subscribe((response) => {
if(response['result_code'] == 'result_ok') {
this.auth.doSignIn(response['token'], response['name']);
this.router.navigate(['user_manager']);
return true;
}else {
return false;
}
});
this is my output error:
Access to XMLHttpRequest at 'http://localhost:8095/login' from origin 'http://localhost:4200' 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.
HttpErrorResponse
I checked also that the request doesn't arrive to my tomcat server, it is blocked before, that oesn't allow angular to check response headers
Thank you for your help
I'm providing you a generic answer as you have not mention that your server side code is written in which language. You should provide a header from your server code. Provide Access-Control-Allow-Origin header with value as localhost:4200 which will resolve your issue. Or if you want to allow every origin then change its value from localhost:4200 to *.
After reading all the comments I have change something for you.
change your this code let myHeader = new HttpHeaders().append("Authorization", 'Basic' + this.session.getAccessToken()); with const myHeader = new HttpHeaders({'Authorization': 'Bearer ' + localStorage.getItem('api_token')});
and make your post request as
this.http
.post<LoginResult>( API_URL + '/login', json, myHeader).pipe(
catchError(this.handleError('get-token', []))).subscribe((response) => {
if(response['result_code'] == 'result_ok') {
this.auth.doSignIn(response['token'], response['name']);
this.router.navigate(['user_manager']);
return true;
}else {
return false;
}
});
You need to configure CORS on your tomcat server.
You need to tell tomcat which headers the application is allowed to send, so it can include it in the preflight response:
<init-param>
<param-name>cors.allowed.headers</param-name>
<param-value>Authorization,Content-Type,...</param-value>
</init-param>
Take a look at
cors.allowed.methods under CORS Filter section here:
https://tomcat.apache.org/tomcat-7.0-doc/config/filter.html

AngularJS ignoring set-cookie header

I am receiving an http response with a set-cookie header that I can see in Chrome Devloper tools. I can even see the cookie listed under the network header, however the cookie is not being set in the browser. The browser will set same origin cookies but not ones from CORS requests.
I have tried exposing the header, to find out it is forbidden
I have tried setting withCredentials to true and setting the Access-Control-Allow-Credentials header to true, I am not using a wildcard for my Access-Control-Allow-Origin header and I have the cookie path set to '/'
I tried making this POST request with jQuery, but I could still not console log the set cookie header visible in the Chrome Developer Tools:
How do I make the browser set this cookie?
Here are some relevant parts of my project (Node/Express backend w/ AngularJS frontend):
var cors = require('cors');
app.use(cors({credentials: true, origin: 'http://localhost:8000'})
app.use(session({
secret: 'A_SECRET',
resave: false,
saveUninitialized: false,
store: sessionStore,
cookie: {
secure: false,
path: '/',
domain: 'http://localhost:8000',
maxAge: 1000 * 60 * 24
}
}))
app.use((req,res,next) => {
res.header('Access-Control-Allow-Credentials', true);
res.header('Access-Control-Allow-Origin', 'http://localhost:8000');
next();
})
And in the front end (port 8000) -
angular.module('signIn', [
'core.company',
'signUp'
])
.config(function($httpProvider){
$httpProvider.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
$httpProvider.defaults.withCredentials = true;
});
Sign-in component:
$http({
method: 'POST',
url: 'http://xxx.xx.xx.xxx:3000/login',
data: self.user
}).then(function successCallback(response, status, headers, config) {
console.log(response.headers('Set-Cookie')) // logs null
console.log(response.headers('set-cookie')) // logs null
}, function errorCallback(response) {
return response
});

Categories

Resources