1

I am using the Django REST token authentication for my API.

I posted my credentials to obtain token endpoint. However when I try to set the header in a correct way it keeps responding with a http 401 error. I tried it using curl -X GET http://127.0.0.1:8000/events/ -H 'Authorization: Token 4d92d36768ca5d555b59cf68899eceab39c23704 ' and that does work! This is my code:

app.controller('HomeController', ['$scope','$http', function($scope,$http) {
    $scope.username = '';
    $scope.password = '';
    $scope.submitLogin = function () {
        var credentials = {
            username : $scope.username,
            password : $scope.password,
        };

        var req = $http.post('http://127.0.0.1:8000/api-token-auth/', credentials);
        req.success(function(data, status, headers, config) {
            $scope.token = data.token;
            var str1 = 'Token ';
            $scope.tokenheader = str1.concat($scope.token);
            $http.defaults.headers.common.Authorization = $scope.tokenheader;
        });
        req.error(function(data, status, headers, config) {
            alert( "failure message: " + JSON.stringify({data: data}));
        });
    };
    $scope.getEvents = function () {
        var req = {
            method: 'GET',
            url: 'http://127.0.0.1:8000/events/',
        }
        $http(req).then( 
           function() {
                       console.log('succes')
           }, 
           function(){
                       console.log('fail') 
        });
    };
}]);

And the error message in chrome dev tools:

XMLHttpRequest cannot load http://127.0.0.1:8000/events/. 
Response for preflight has invalid HTTP status code 401

How do I get rid of this 401 error?

Edit: I just found out the fault lies in the fact that I did not have CORS installed on my API. I was using a CORS plugin in chrome that worked for the authentication part of my api but not for my events url!

icam0
  • 157
  • 2
  • 14

2 Answers2

1

You need to add Token to the headers:

get($http, "/some_url", {headers: {"Authorization": "Token " + $your_token}}
    ....
    ....
);

Response code 401 means Unauthorized. If you are using Token based authentication then in case of fail it would be 403, Forbidden. So my guess would be that it's username/password who is messing with it. In your curl example you are not using them.

DevilPinky
  • 558
  • 3
  • 13
  • I already did that: `var str1 = 'Token '; $scope.tokenheader = str1.concat($scope.token);` – icam0 Nov 10 '15 at 12:58
  • @icam0, But why are you using username and password then? I updated my answer. – DevilPinky Nov 10 '15 at 13:58
  • That's because in my html I have 2 buttons. One that I connected to the submitlogin() function and the other one that I connected to the getEvent() function. I first requested the token with another curl command: `curl -X POST http://127.0.0.1:8000/auth/login/ --data ‘username=icam0&password=password123’` – icam0 Nov 11 '15 at 00:24
1

Did you check that the token is actually added to your request?

You can do this for example using the Chrome developers tools.

Personally I prefer to use the $httpprovider.interceptor as described in:

angularjs $httpProvider interceptor documentation

This ensures that the tokens are always present on any call.

If you are accessing more than one API, you should consider adding something like:

           $httpProvider.interceptors.push(['$q', '$location', '$log', 'loginService', 'restHelperService',
            function ($q, $location, $log, loginService, restHelperService) {
                return {
                    request: function (config) {
                        // check if the request comes with an url
                        if (config.url) {
                            // check that the call is to the REST api, if yes add token
                            if (restHelperService.isRestCall(config.url)) {
                                // add auth header or revert to login
                                if (loginService.userIsLoggedIn()) {
                                    config.headers = config.headers || {};
                                    config.headers.Authorization = 'Token ' + loginService.getToken().token;
                                } else {
                                    $location.path('/login');
                                }
                            }
                        }
                        return config;
                    },
                    responseError: function (response) {
                        if (response.status === 401 || response.status === 403) {
                            // clear auth token if the REST call failed with the current token
                            if (response.config && response.config.url && restHelperService.isRestCall(response.config.url)) {
                                $log.debug(" restCall failed due to bad credentials, resetting credentials");
                                loginService.resetCredentials();
                                $location.path('/login');
                            }
                        }
                        return $q.reject(response);
                    }
                };
            }]);
    }])

This avoid issues that will arise when you start adding the token to API calls that don't expect them. Also the code ensures that a user will be automatically redirected to the login page if the credentials are not valid.

The example, I'm using two additional services. A loginService that manages the tokens and a restHelperService that manages the urls of the REST framework.

I would recommend doing the same as else it will be hard to access the credentials from outside your controller.

Community
  • 1
  • 1
Niels van Eldik
  • 211
  • 2
  • 7