babbaggeii
babbaggeii

Reputation: 7747

CSRF mismatch when POSTing to sails backend from Angular JS

In angular, I obtain a CSRF token like this:

// Get CSRF token and set as header
var csrfRequest = Auth.getCSRF().then(function(data){
    console.log(data.data._csrf);
    $rootScope.csrf = data.data._csrf;
});

Which logs the new token to the console (this works fine).

Then, I try to login to a sails.js api. Here's the request:

POST /auth/login HTTP/1.1
Host: localhost:1337
Connection: keep-alive
Content-Length: 108
Pragma: no-cache
Cache-Control: no-cache
Accept: application/json, text/plain, */*
Origin: http://localhost
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36
Content-Type: application/json;charset=UTF-8
Referer: http://localhost/sails-front/src/login/
Accept-Encoding: gzip, deflate
Accept-Language: en-GB,en-US;q=0.8,en;q=0.6

Request Payloadview parsed
    {"email":"[email protected]","password":"mypass","_csrf":"PIlVO7S362OroPGBSG0X1vW2FydkP9VhK8cMk="}

The _csrf field is the same as that which was received in the getCSRF call.

Yet I get the response 'CSRF mismatch'. However, when I try the exact same thing with Postman, it works fine (so I don't think it's a problem with the sails server).

Here's the login code in angular. In the controller:

$scope.login = function() {
    Auth.login({
            email: $scope.email,
            password: $scope.password,
            _csrf: $rootScope.csrf
        },
        function(res) {
            $state.go('app.home');
        },
        function(err) {
            $rootScope.error = "Failed to login";
        });
};

And the Auth service:

/*********************************
* login
******************************** */
function login(user, success, error) {
    $http.post(API_BASE_URL + 'auth/login', user).success(function(user){
        changeUser(user);
        success(user);
    }).error(error);
}

Upvotes: 1

Views: 2004

Answers (1)

sgress454
sgress454

Reputation: 24958

You posted your full request, and the answer is hidden there in plain sight--not by looking at what is being sent, but what is being omitted: namely, the cookie. The CSRF token is valid for a single Sails session, but you are neglecting to send the cookie with your AJAX request, so Sails has no idea which session the CSRF token you're sending is for.

To tell Angular to send cookies with your request, use the withCredentials setting:

$http.post(API_BASE_URL + 'auth/login', user, {withCredentials: true})

Upvotes: 2

Related Questions