I'm trying to access an API with AngularJS but I get the following error:
XMLHttpRequest cannot load http://www.football-data.org/alpha/soccerseasons/398/leagueTable?callback=JSON_CALLBACK. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://purepremier.com' is therefore not allowed access.
This is my code for the service:
angular.module('PremierLeagueApp.services', []).
factory('footballdataAPIservice', function($http) {
var footballdataAPI = {};
footballdataAPI.getTeams = function() {
$http.defaults.headers.common['Auth-Token'] = 'token';
return $http.get('http://www.football-data.org/alpha/soccerseasons/398/leagueTable?callback=JSON_CALLBACK');
};
return footballdataAPI;
});
I use an authentication token (api key) to access the api, but according the API owner this API key header is not sent or recognized. Do you have any idea how I can adapt the code to make this work? thanks!
You should hide that API key before posting on a public site such as this. I would advise you regenerate your key (if possible) just in case - better safe than sorry.
Assuming your site url is 'http://purepremier.com' from the error message, the API should add a 'Access-Control-Allow-Origin' header with your site URL to allow you access. Have a look here for more information.
This is not directly related to your problem, but I notice you are setting $http defaults every time getTeams() is called. You should either set this outside of the actual function call (preferably in a run block), or just send the GET request with that header specifically applied. As the API key is specific (I assume) to that call, you may not want to be sending it to anyone and everyone, every time you make a HTTP request.
Change your factory code like this:
factory('footballdataAPIservice', function($http) {
return {
getTeams: function(){
return $http({
url:'http://www.football-data.org/alpha/soccerseasons/398/leagueTable',
headers: { 'X-Auth-Token': 'your_token' },
method: 'GET'
}).success(function(data){
return data;
});
}
}
});
Inject factory in your controller and retreive the data:
.controller('someController',function(footballdataAPIservice,$scope){
footballdataAPIservice.getTeams().then(function(data){
$scope.teams=data;
console.log($scope.teams)
});
});
Here is the working plunker
You change the Auth-Token To Authorization
$http.defaults.headers.common['Authorization'] = 'token';
Because token is send via headers using Authorization
try jsonp
angular.module('PremierLeagueApp.services', []).
factory('footballdataAPIservice', function($http) {
var footballdataAPI = {};
footballdataAPI.getTeams = function() {
$http.defaults.headers.common['Auth-Token'] = 'token';
return $http.jsonp('http://www.football-data.org/alpha/soccerseasons/398/leagueTable?callback=JSON_CALLBACK');
};
return footballdataAPI;
});
Related
I am using Django with Angular JS to access the Google Drive API. I am following this document from Google. The FLOW.step1_get_authorize_url() gives me the URL similar to the sample URL mentioned on the page. But the problem is that after return HttpResponseRedirect(authorize_url) the browser does not redirect to the authorize_url and gives the error as shown in the picture below (Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access. The response had HTTP status code 405).
But if I copy pasted the URL, it works fine.
The oauth2 function looks like this.
def index(request):
FLOW = flow_from_clientsecrets(
settings.GOOGLE_OAUTH2_CLIENT_SECRETS_JSON,
scope='https://www.googleapis.com/auth/drive',
redirect_uri='http://127.0.0.1:8000/oauth2callback/'
)
FLOW.params['access_type'] = 'offline'
authorize_url = FLOW.step1_get_authorize_url()
return HttpResponseRedirect(authorize_url)
And here is the oauth2callback function.
def auth_return(request):
credential = FLOW.step2_exchange(request.GET)
return HttpResponseRedirect("/mycustomurl")
I used this to enable CORS in the Django Server Side. Here is my part of service in Angular that makes the call to oauth2.
(function () {
'use strict';
angular.module('myApp')
.service('myService', function ($http) {
this.saveToDrive = function (startYear, endYear, shape) {
var config = {
params: {
start: '1999',
end: '2002',
action: 'download-to-drive'
},
headers: {
'Access-Control-Allow-Origin': '*',
'X-Requested-With': null
}
}
var promise = $http.get('/oauth2/', config)
.then(function (response) {
return response.data;
});
return promise;
};
});
})();
Please suggest what am I missing here. Any help or suggestions are highly appreciated.
I found it be a minor design issue rather than the code issue. I separated the logic that sends the oauth2 request to the client, and after the oauth2 request, I sent request to internal API with the params options. And now it's working fine.
I'm trying to setup token auth but can't seem to figure out a good way to save the headers the server is sending me into a cookie. I then need to read that value out of the cookie and into the new request headers.
I'm using Angular 1.5
Here's some simple code I've been trying to work with:
os.config(['$httpProvider', function ($httpProvider) {
return {
'request': function(config) {
var access_token = $cookies.get('access-token');
var token_type = $cookies.get('token-type');
var client = $cookies.get('client');
var uid = $cookies.get('uid');
$httpProvider.defaults.headers.post['access-token'] = access_token;
$httpProvider.defaults.headers.post['token-type'] = token_type;
$httpProvider.defaults.headers.post['client'] = client;
$httpProvider.defaults.headers.post['uid'] = uid;
},
'response': function(response) {
$cookies.put('access-token', 'oatmeal');
$cookies.put('token-type', 'oatmeal');
$cookies.put('client', 'oatmeal');
$cookies.put('uid', 'oatmeal');
}
};
}]);
EDIT: People have been commenting trying to show me how to set headers. I can do that easily, as you can see in the example. What I need to do is save the response headers after I've made a request. These need to be saved into a cookie which is what my question pertains to.
I'm interested in a method that doesn't require me to run some function in the .then part of every single API request I do, that's not DRY and seems like madness...
I have an angular front end with a webapi back end. I have implemented OAuth v2 security using OWIN/Identity and JWT tokens (thanks to Taiseer Joudeh's blogs). My burden is that we still have legacy pages that require a specific cookie. I have augmented the Http Response from WebApi to include that cookie when the JWT token is returned from a login request. I have verified the cookie is in the response header.
My problem is that I am unable to see the cookie inside my angular response handler where I will push it to the browser. I have tried each of the following based on suggestions I found elsewhere within StackOverflow but so far visibility of the cookie within the .js code has eluded me (alternate attempts have been commented out but left in for completeness). I have also made sure I set the appropriate "allow" fields on the server by adding "Access-Control-Allow-Headers" to "set-cookie" and "Access-Control-Allow-Credentials" to "true" at the end of my ValidateClientAuthenticationContext(..) method.
What do I need to do to see the attached cookie on my webapi response? Is this a problem on the server or client? both?
in my authService.js file:
var _login = function (loginData) {
// this makes the data "form data"
var data = "grant_type=password&client_id=ngAuthApp&username=" + loginData.userName + "&password=" + loginData.password;
var deferred = $q.defer();
$http.post(serviceBase + 'oauth/token', data, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } })
.success(function (response) {
localStorageService.set('authorizationData', { token: response.access_token, userName: loginData.userName });
_authentication.isAuth = true;
_authentication.userName = loginData.userName;
console.log($cookies);
//var xxx = $http.defaults.headers;
//var headers = $http.response.headers;
var ddc = $http.response.cookies;
$cookies.DDC = ddc;
deferred.resolve(response);
})
//.success(function (data, status, headers, config) {
// // any required additional processing here
// var results = [];
// results.data = data;
// results.headers = headers();
// results.status = status;
// results.config = config;
// deferred.resolve(results);
//})
.error(function (err, status) {
_logOut();
deferred.reject(err);
});
return deferred.promise;
};
in my custom OAuthProvider .cs file
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
// skipping over lots of code here
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { allowedOrigin });
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Credentials", new[] { "true" });
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Headers", new[] { "authorization", "content-type", "set-cookie" });
context.Validated();
return Task.FromResult<object>(null);
}
According to the docs - see here
$http.post() method returns an HttpPromise future object. Your call to .post() returns a promise. Which according to the Deprecation Notice on the above referenced page :
The $http legacy promise methods success and error have been
deprecated. Use the standard then method instead. If
$httpProvider.useLegacyPromiseExtensions is set to false then these
methods will throw $http/legacy error.
So instead of .success() / error(), use this: (Copied from docs)
$http.post()
.then(function successCallback(response) {
// this callback will be called asynchronously
// when the response is available
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
Also, if you haven't already tried this (according to the .post() call it doesn't appear to) set the responseType property of your $http configuration object. This sets the datatype of the response object returned. Otherwise the default of a DOM string is returned. It may not fix it but it could be a start.
This could also need the help of withCredentials property set. Test them out and see how it goes. Idea comes from the suggestion of bastijn.
Your $http call should also set the withCredentials flag to true to explicitly allow cookie sharing.
$http.post(url, {withCredentials: true, ...})
The withCredentials flag allows javascript to access the authenticated session of the user.
//edit
Now that I read your question again this is probably not your issue. The withCredentials is to,communicate your session to the server on the next request you make that requires the authenticated session. From your question it seems you want to validate in the js code that the cookie you verified is there is also reachable by code.
It turns out the error was in my assumptions. I expected that a cookie sent via a web service directly from embedded js code would be ignored by the browser. However, the response header has the "Set-Cookie" value in the header and the browser IS already pushing it to be with the rest of the cookies. I really didn't expect that.
I must add this has been a very useful question for me because it taught me a lot about web programming and how the browser works with http header values. I appreciate everyone's time!
Marcus
I am trying to access the 8coupons api since i want to learn angularjs. But, whenever i try to hit the url it displays XMLHttpRequest cannot load http://api.8coupons.com/v1/getsubcategory. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.
javascript:
var getjson = angular.module('dataapp',[]);
getjson.controller('controller',function($scope,$http)
{
var url = "http://api.8coupons.com/v1/getsubcategory?key=62a3ce5309039c70b7e74e759d0092282a50558b7af45ae1ca8c4bb1fa6bb4fcb16a7c896175dd5414746e2d407098dc";
$http.get(url).success(function(data,status,headers,config){
$scope.jsondata = data;
console.log(data);
}).error(function(data,status,headers,config){
});
});
You have to change your $http request as follows.
var url = "http://api.8coupons.com/v1/getsubcategory?key=62a3ce5309039c70b7e74e759d0092282a50558b7af45ae1ca8c4bb1fa6bb4fcb16a7c896175dd5414746e2d407098dc&callback=JSON_CALLBACK&time"+Math.random();
$http.jsonp(url)
.success(function(data) {
console.log("Success");
console.log(data[0].category);
}).error(function(data) {
console.log("Error");
});
Appended the additional param in the above URL which is required for JSONP call. Read the doc for more info https://docs.angularjs.org/api/ng/service/$http#jsonp
callback=JSON_CALLBACK
Demo : http://plnkr.co/edit/m9GW6y1JuiimbvKibQZ4
I just added www.corsproxy.com as a prefix to the url domain
e.g., http://www.corsproxy.com/api.8coupons.com/.....
my problem got fixed
In my angular app, I have a $http request interceptor called 'authInterceptor' that I create like this:
.factory('authInterceptor', function ($q, $window, EXT_API_BASE, $injector) {
return {
request: function (config) {
if (config.url.indexOf(EXT_API_BASE) !== -1){
var Auth = $injector.get('Auth');
if(Auth.user && Auth.user.token){
config.headers.Authorization = 'Web ' + Auth.user.token;
}
}
return config;
}
}});
It gets registered in a .config():
$httpProvider.interceptors.push('authInterceptor');
As you see, my Authorization headers are bound to a Auth.user.token value. This value is available when my user is signed in.
Then the headers are sent for any calls to my api.
The problem I am facing is... when the user signs out in my angular app, the Authorization headers are still being sent even though I deleted Auth.user.token already.
On a hard refresh of the page, the Authorization headers then get removed completely.
How can I make sure 'authInterceptor' registers the change in token value when my user signs out?
Answering my own question. Made a newbie mistake of changing Auth.user object like this on sigh out:
Auth.user = {}
That created a new object and the requestInterceptor was still referencing the old object.
The correct way to do it is:
delete Auth.user.token