Activiti REST returns 401 after GET request - angularjs

When i tried to send a GET request to Activiti REST URL, using POSTMAN and configuring an authorization parameter (kermit:kermit) it works like a charm.
But when i tried to do the same thing, only with Angular $http service, it returns the following error:
XMLHttpRequest cannot load http://localhost:8080/activiti-rest/service/repository/deployments. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8081' is therefore not allowed access. The response had HTTP status code 401.
Here is my controller:
(function() {
'use strict';
angular
.module('doktorat-app-test')
.controller('TestController', TestController);
TestController.$inject = ['$http', '$base64'];
function TestController($http, $base64) {
var tcr = this;
$http.defaults.headers.common['Authorization'] = 'Basic ' + $base64.encode('kermit:kermit');
tcr.text = 'ssdsds';
$http.get('http://localhost:8080/activiti-rest/service/repository/deployments')
.then(function(response){
tcr.text = response.data;
});
}
})();
Has anyone encountered on similar error?
Spent more then 2 days trying to resolve this issue, but without any success.
P.S. I am using NodeJS http-server to run my Angular App, which runs on port 8081.

Since you are trying to access rest api which is on http://localhost:8081/ From http://localhost:8080/, browser will check if your server implement CORS using preflight request. You can get detail about CORS on below url:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
Normally application hosted in one server will not be allowed to access the resources hosted in other sever.This restriction is implemented by all most all browser now a days.
In order to make it work, your rest api server has to tell that some other servers will also be allowed to call. For this , you need to implement CORS filer in your rest api server.
Since you didn't specify which langauge you are using in REST, i am providing an open source CORS filter library for JAVA:
http://software.dzhuvinov.com/cors-filter.html
which solves your problem.

To allow CORS for a specific domain you can use a middleware as below:
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "http://localhost:8081");
res.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
res.header("Access-Control-Allow-Credentials", "true");
res.header("Access-Control-Allow-Headers", "Content-Type, Accept, Authorization, X-Requested-With");
next();
});

Related

Getting Access-Control-Allow-Headers in preflight error

I have created angular js app in which I have integrate twitch api , the api is
return $http({
url: "https://api.twitch.tv/kraken/streams",
method: "GET",
params: { channel: channel, limit: 1 },
headers: { "Client-Id": "XXXXXXXXXXXXXXX" }
})
the problem is when I reload the page the api is working but when my state changes without page reload I am getting cross origin error from this api.
the error is
Failed to load https://api.twitch.tv/kraken/streams?channel=eliazOne&limit=1: Request header field RefreshToken is not allowed by Access-Control-Allow-Headers in preflight response.
anyone has idea how to resolve cross error
When you make a request to a different domain this is called a cross domain request. Also known as a CORS request.
When you POST / PUT data to a different domain it will make an OPTIONS request first. This is to ensure that the server has Access-Control-Allow-Headers in place on the response. These headers should permit access to the domain you are making the request from. If these headers are not present then when the OPTIONS request is made it will fail and the POST / PUT will never be made.
See here for more info https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Preflighted_requests
The simple answer is to just add these headers to your server.
I don't know if this is something Angular does on its own by default or if it's a bug elsewhere in your code, but you or Angular is sending a RefreshToken header as part of your failing request, which is not allowed per Access-Control-Allow-Headers response header in the pre-flight OPTIONS request.
$ curl -XOPTIONS https://api.twitch.tv/kraken/streams -is | grep Headers
Access-Control-Allow-Headers: Accept, Accept-Language, Authorization, Client-Id, Twitch-Api-Token, X-Forwarded-Proto, X-Requested-With, X-Csrf-Token, Content-Type, X-Device-Id
This is something all cross-origin requests do. The browser sends an OPTIONS request to make sure the real request it's about to make is allowed by the criteria set by the cross-origin server.
You need to add a ?callback=? with the URL you are passing along with a callback function. Please follow the link How to use JQuery to Access Twitch streams
This is JQuery example but the concept is same.
$.getJSON('https://api.twitch.tv/kraken/streams/' + name + '?callback=?',
function(channel){
if (channel["stream"] == null) {
$("#all").append("<p>" + channel._links.self + "</p>");
}
else {
$("#all").append("<p>Fail</p>");
}
});
});

CROS OPTIONS request when trying to upload a file with $http angularjs

I'm actually trying to implement a file upload system between my client side angularjs app and my server but i'm having difficulties to implement this feature.
The problem seems to come from the preflight OPTIONS request sent from Chrome.
When I test my route with postman everything work just fine.
Here is a few screen shots of the postman request execution:
First part of postman example
Second part of postman example
As you can see the route has two parameters a library id and a file to be uploaded and an authentification token.
The problems appear when I try to implement an upload feature in my angular web app.Indeed when I call my $http post request a OPTIONS preflight request is sent to my server.This OPTIONS request doesn't seem to have any of the parameters given to the post request it precedes making my authentification middleware (that has the function of validating the user/token) on my server side respond with a 401 error.
More exactly:
XMLHttpRequest cannot load ..... Response for preflight has invalid http status code 401
It seems that those preflight request are made by the browser when say detect a cross origin resource sharing. This is were I hit a brick wall. I cannot seem to understand how to:
- either send the token with the options request to validate this request
- or to bypass this options request to directly send my post request.
my upload function looks like this:
$http({
method: 'POST',
url: 'my-upload-url',
headers: {
'Content-Type': 'multipart/form-data'
},
data: {
library: my-library-id,
file: my-file-to-upload,
token: user-authentification-token
},
transformRequest: function (data, headersGetter) {
var formData = new FormData();
angular.forEach(data, function (value, key) {
formData.append(key, value);
});
var headers = headersGetter();
delete headers['Content-Type'];
return formData;
}
})
.success(function (data) {
})
.error(function (data, status) {
});
My questions are:
Is there a way to actually send my user token in the OPTIONS request to make it valid server side?
Is there a way of formatting my post request (header/data/params) to make it bypass this preflight browser request?
Is the formatting of my post request wrong in any way making it trigger the OPTIONS request from Chrome?
Thank you in advance for your help.
Martin
In cors, the OPTIONS method is used to tell the server what will your request do. The server must handle the OPTIONS correctly so your main request will send normally. The browser will send the OPTIONS request automatically when your request is a complex cross origin request.
To bypass the OPTIONS request your request should be POST and GET and content-type must be application/x-www-form-urlencoded, multipart/form-data, or text/plain and the headers only contain Accept, Accept-Language and Content-Language.
Your request is not wrong. The reason is that your request is a cross origin request and it isn't a simple request.
So the best way to solve this problem is to make your server handle the cors request correctly.
For express you can use https://github.com/expressjs/cors
see more: cors-mdn cors-w3c

Not able to get response from API through angular?

My code is as below
$scope.LoadSearchResults = function () {
$scope.hotels = '';
$scope.allData = '';
var mydata = '';
$http({
url: 'myurl',
Authorization : 'code',
method: 'POST',
header: { 'Content-type': 'text/json' }
})
.success(function (mydata) {
$scope.hotels = JSON.parse(JSON.stringify(mydata.SearchResponse.Hotels.Hotel));
$scope.allData = JSON.parse(JSON.stringify(mydata.SearchResponse.Hotels.Hotel));
$scope.AllLocality($scope.allData);
})
.error(function (mydata) {
$scope.hotels = "Failed";
console.log(JSON.stringify(mydata));
});
}
and getting error is
"Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://example.com/some-page. (Reason: CORS header 'Access-Control-Allow-Origin' missing)."
How could I solve this problem?
this is not an Angular problem.
the reason is you are firing a cross origin request (e.g. your app sits on a domain and the request specified by url: 'myurl' is for a different domain) and HTTP does not allow it unless permissions are specifically added by the server receiving the request by adding a CORS header to the response.
to solve your problem you please check here one of the 4 options (I am sure you can find more depending on your specific setup):
make your app fire the request to the same domain, which is normally the preferred and most secure approach (e.g. the web app hosting the angular code is also responsible of responding to the xhr you are doing via $http)
if you have control on how the server creates the response, it should be fairly easy to add such headers (I cannot add an example here as it is entirely dependent on the web server or application gateway you are using)
if you don't have control over the server response (and most importantly its headers) you can add your own server in the middle that would act as a request proxy, thus making your JS app firing the request to your server (not incurring CORS problems) and the server itself making the proxy request to the 3rd party provider
if you just need GET requests (which doesn't seem the case from your snippet) you can use angular's $http JSONP if the server supports this type of requests.
Hi I have got it same issue but now i have resolved it by using below:
header('Access-Control-Allow-Origin: *');
header("Access-Control-Allow-Headers: X-API-KEY, Origin, X-Requested-With, Content-Type, Accept, Access-Control-Request-Method, Authorization");
header("Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT, DELETE");
please pass header on controller after parent::__construct();

Issue with CORS after adding Stormpath Angular SDK

I am working on SPA MEAN app, I was developing it against Apiary mock APIs, which has the following CORS headers set:
Access-Control-Allow-Methods → OPTIONS,GET,HEAD,POST,PUT,DELETE,TRACE,CONNECT
Access-Control-Allow-Origin → *
Access-Control-Max-Age → 10
It all works fine and angular can access it using $http angular service just fine. However after adding Stormpath Angular SDK all these requests fail with following error:
XMLHttpRequest cannot load https://xxx.apiary-mock.com/workshops?type=favourite. Credentials flag is 'true', but the 'Access-Control-Allow-Credentials' header is ''. It must be 'true' to allow credentials. Origin 'http://localhost:8000' is therefore not allowed access.
I am trying to get to figure out why these requests are rejected and at what point these headers are added?
Thank you for finding this issue. The Stormpath Angular SDK does have an interceptor which sets the withCredentials: true flag for all requests. Please see the code here.
The intention is to ensure that our authentication cookies are always sent, even in a cross-domain situation. But I can see how this will be problematic if your Angular application is talking to other APIs that don't require cookies to be sent.
As a workaround, you can override our interceptor by simply adding another one:
angular.module('myapp', [
'stormpath',
'stormpath.templates'
]).config(function ($httpProvider) {
$httpProvider.interceptors.push(function() {
return {
request: function(config) {
config.withCredentials=false;
return config;
}
};
});
});
I've created an issue to discuss a better solution: https://github.com/stormpath/stormpath-sdk-angularjs/issues/72
Any time you have a SPA client served from one domain (e.g. localhost:8080) and you want that client to access an API on another domain (xxx.apiary-mock.com), the browser requires that the server domain add CORS headers correctly.
If the client and server domains are different, the browser's security model requires the server to indicate which client domains may access the server by setting the Access-Control-Allow-Origin response header (in addition to other relevant Access-Control-* headers).
I have how to work around it add these headers to apiary:
+ Response 200 (application/json)
+ Headers
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: OPTIONS,GET,HEAD,POST,PUT,DELETE,TRACE,CONNECT
Access-Control-Allow-Origin: http://localhost:8000
I am still trying to figure out where does Stormpath make those headers required though.

AngularJS Send a GET Request With Basic Authentication

I try to send a GET RESTful request to a server with basic authentication. I wrote the following code to achive this task:
module.controller("MainCtrl", ['$scope', '$http', function($scope, $http) {
$http.get('http://192.168.10.15:8080/web/services/api/records/20420?_type=json', {
headers: {
'Authorization' : 'Basic username:password'}
})
.success(function(response) {
console.log("my success");
$scope.values = response;
})
}]
);
When the request is processed, the given error is displayed on the browser console:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource on http://192.168.10.15:8080/web/services/api/records/20420?_type=json. (Reason: header CORS 'Access-Control-Allow-Origin' missing).
Any Idea?
Read this page http://amodernstory.com/2014/12/27/using-cors-headers-with-java-example/ and you should pay attention to this paragraph "The main idea to remember when writing your own filter is that, before any AJAX calls are made. The browser sends an OPTIONS AJAX request to the server. The server needs to reply to this OPTIONS call with the required permissions. " :D
Your server (http://192.168.10.15:8080/) doesn't allow you to send request from external (Or just your server origin server).
You have to allow CORS (Cross-origin resource sharing) on your server,
there are several ways to do it, in your server config.
Example
if you're using node.js & express you can allow CORS like this:
app.use(function (req, res, next) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
next();
});
in the express config file.

Resources