jwt authorization token missing from response header - angularjs

I'm trying to setup a simple Angularjs app with Hapi, using JWT authentication.
I send an email to newly registered user with a jwt token link to verify if the email exists. The link looks like this:
http://127.0.0.1:3000/verifyEmail/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyTmFtZSI6InJpY2tAaWNvZGU0dS5ubCIsInNjb3BlIjpbIkN1c3RvbWVyIl0sImZpcnN0TmFtZSI6IlJpY2siLCJsYXN0TmFtZSI6IkdvbW1lcnMiLCJpYXQiOjE0NDkxNDc5MzR9.6lWxcsSIC7DgAiGC0hcp7bdAhyl40Nbcqid3VgVtM6c
This is how I generate the token:
handler: function(request, reply) {
request.payload.password = Common.encrypt(request.payload.password);
request.payload.scope = "Customer";
User.saveUser(request.payload, function(err, user) {
if (!err) {
var tokenData = {
userName: user.userName, //email address
scope: [user.scope],
firstName: user.firstName,
lastName: user.lastName
};
Common.sentMailVerificationLink(user,Jwt.sign(tokenData, privateKey));
reply("Please confirm your email id by clicking on link in email");
} else {
if (11000 === err.code || 11001 === err.code) {
reply(Boom.forbidden("please provide another user email"));
} else {
console.log(Boom.forbidden(err));
reply(Boom.forbidden(err)); // HTTP 403
}
}
});
}
Now when I click the verification link, the response header looks like this:
{ host: '127.0.0.1:3000',
connection: 'keep-alive',
accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;
q=0.8',
'upgrade-insecure-requests': '1',
'user-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KH
TML, like Gecko) Chrome/46.0.2490.86 Safari/537.36',
dnt: '1',
'accept-encoding': 'gzip, deflate, sdch',
'accept-language': 'nl-NL,nl;q=0.8,en-US;q=0.6,en;q=0.4,fr;q=0.2,es;q=0.2',
'x-cookiesok': 'I explicitly accept all cookies' }
The Question:
I am missing the Authorization token from the response header. How can I send the Authorization token in the header?

You send the token in the url so it can't return in the headers. You have to get it back from the url.

Related

How to push request a CSRF Token in k6 performance testing tool - ReferenceError

I am quite new to k6 and load testing and I could not figure out why I am not able to push a token from one request to another, to test the login process in a Laravel-built web app. I hope somebody can help me out with this issue.
So my script looks like the following:
First request from where I want the token:
import { parseHTML } from 'k6/html';
import { sleep, group, check } from "k6";
import http from 'k6/http'
export const options = {}
export default function main() {
let response
group('page_1 - http://localhost:81/login', function () {
response = http.get('http://localhost:81/login', {
headers: {
host: 'localhost:81',
'user-agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:104.0) Gecko/20100101 Firefox/104.0',
accept:
'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
'accept-language': 'en-US,en;q=0.5',
'accept-encoding': 'gzip, deflate, br',
connection: 'keep-alive',
cookie:
'XSRF-TOKEN=eyJpdiI6InY5ckZiaGdFTkI4Q0YyRi8rdmtyNUE9PSIsInZhbHVlIjoiT0NjZXlWWVBubTE5Zjh6cXBmNmZFWTdZKzBjVXlEOGhheGR0aVUybURSSGRZbEFmQ0N2RW5BQ3pOYzBQUXgweXhUaGNpRDhrcTV5SHBJUkEvU0FYTmN3eCswYTFsVnhQdk8wL1dkeHMvOTNXRTU4dnk2WjJ0QWFCSWdyQzEwQkwiLCJtYWMiOiIyODI1YmFkMDI1MzlkOGY4ODEyMDg4YWU5M2I5MWE3NmI3Yjg2ODczYTBkMzhhNmZiZTU5ODNlZDBjOGViNWIzIn0%3D; dev_session=eyJpdiI6ImNGalhPQW9GTWlYLzdsaEg1Qk0zdnc9PSIsInZhbHVlIjoiVU5jQ21OZmkyUDVnUmd2WUxUc3Z5dWhRbzBJTm1HWFhmQ1RuNzdFaEpRb1IzdVlIa1VhUkNXYTBlc2IxMHRMajl6UTAzYmFVTHZheEdTV2RrYU84d3pmdEUxYUlkaVFFT3J5YUVWSE1wVklRektqemVmbjhmK3hLWHo2ZmlMYlgiLCJtYWMiOiI3MTQ2ODg0Yjk4YjhhNjg2Yzg1YjllZjdmMWMyNzVkY2ZmNGM1NjAzYWUyN2NlMmE0ZjAwOTAyNWMwNGI2YmM2In0%3D',
'upgrade-insecure-requests': '1',
'sec-fetch-dest': 'document',
'sec-fetch-mode': 'navigate',
'sec-fetch-site': 'none',
'sec-fetch-user': '?1',
'sec-gpc': '1',
},
})
// Query the HTML for an input field named "_token".
const elem = response.html().find('input[name=_token]');
// Get the value of the attribute "value" and save it to a variable
const token = Elem.attr('value');
// Now you can concatenate this extracted value in subsequent requests that require it.
// console.log() works when executing k6 scripts locally and is handy for debugging purposes
console.log('The value of the hidden field is: ' + token);
check(response, {
list_OK: (r) => r.status === 200,
});
})
Second request - I want to use the token from the previous request to log in:
group('page_2 - http://localhost:81/customlogin', function () {
const url = 'http://localhost:81/customlogin';
const payload = JSON.stringify({
_token: `${token}`,
email: 'user',
password: '1234',
});
const params = {
headers: {
'Content-Type': 'application/json',
host: 'localhost:81',
'user-agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:104.0) Gecko/20100101 Firefox/104.0',
accept:
'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
'accept-language': 'en-US,en;q=0.5',
'accept-encoding': 'gzip, deflate, br',
'content-type': 'application/x-www-form-urlencoded',
origin: 'http://localhost:81',
connection: 'keep-alive',
referer: 'http://localhost:81/login',
cookie:
'XSRF-TOKEN=eyJpdiI6ImlnZFZCUGF1b1FYUlJOdTJHNDd2Vnc9PSIsInZhbHVlIjoiTXhhdnZyQzlPamRFQ21rajdQVEZXcThzWittZndqU2d1L0hyN1BmRTA2a2RBbEpYZUhIUlRpWjh1RWJoQ1Y5dWJoTWVnaXEzZ1NVTjBndG1tenUyN2phY1lMdkIxSzBGek5aYndlSmRxaEhVTGY4WkNCcE1UY3N6YmowUnkrTkciLCJtYWMiOiJlNDIxNjhkYTc1NjYxNTVkNWZhOWViZDYwMGU1ODRkNmQ2ZGU0NjgyMjU5NjIxMzQ0MjYyYzRjMmJkYTVmNjUwIn0%3D; dev_session=eyJpdiI6IndxWXpobW9BUm1GSHNVZkorN0N0OGc9PSIsInZhbHVlIjoiSE82by9aRnBXQjFkNG5JMHFkVzUzc3kraUZOYUdIdjNlUGN6a3c2SjBSZy9TaVNxNmRsWnQzMTltMGt0MGQvWUoxQndyQXFvd2theWViNU94Z2FXaXlGTkc4ZVdERGY2KzRpUUZDZDIxNG85UFhhanRiajBCWElmcmthMWE0R3IiLCJtYWMiOiJjMDllMmRmNGJjNDRlMjM2MmZmZTViOWEwZmUzNWQ3MzNjZDI1NWQwYmU3MjE4OTZiMTRhN2U0NWNkMTcxMDAzIn0%3D',
'upgrade-insecure-requests': '1',
'sec-fetch-dest': 'document',
'sec-fetch-mode': 'navigate',
'sec-fetch-site': 'same-origin',
'sec-fetch-user': '?1',
'sec-gpc': '1',
},
};
response = http.post(url, payload, params);
console.log(response)
check(response, {
list_OK: (r) => r.status === 200,
});
})
After running the script I get an error message saying:
> ReferenceError: token is not defined
Thank you for your passionate help!
In this case you are defining a variable in the first call to group (const token ....` and then try to use it in the second call.
This has nothing to do with CSRF or k6, but with javascript ... and arguably scoping in most other languages.
But in order for both functions to see the same variable you will need to define it earlier - so for example next to your let response in the start of the default function.
Also remove const from the current definition as otherwise it won't work ;)

Ajax request with chrome's cors plugin

I'm trying to make a cors ajax request to users/login to authenticate the user and send back a JWT token. The options request returns 200, whereas the post request returns 403 forbidden with 'Missing CSRF token cookie' error. I'm using chrome's cors plugin. On my UsersController.php inside its initialize function i have $this->Auth->allow(['login']);
cakephp server on localhost:8765 with 'cake server', and extjs server started on http://localhost:1841/ with 'sencha app watch'
LoginController.js
onLoginClick: function() {
this.getView().mask('Effettuando il login..');
var data = this.getView().down('form').getValues();
App.security.Firewall.login(data.username, data.password).then(function() {
this.getView().destroy();
Ext.create({
xtype: 'app-main'
});
this.getView().unmask();
}.bind(this), function(data) {
Ext.Msg.alert('Errore', data.message || 'Impossibile eseguire il login in questo momento.');
});
}
Firewall.js
login: function(username, password) {
var deferred = new Ext.Deferred();
Ext.Ajax.request({
url: 'http://localhost:8765/users/login',
method: 'POST',
params: {
'username': username,
'password': password
},
success: function (response) {
var data = Ext.decode(response.responseText);
if (data.token) {
App.security.TokenStorage.save(data.token);
deferred.resolve(data, response);
} else {
deferred.reject(data, response);
}
},
failure: function (response) {
var data = Ext.decode(response.responseText);
App.security.TokenStorage.clear();
deferred.reject(data, response);
}
});
return deferred.promise;
},
This is how i loaded the JWT Auth plugin
$this->loadComponent('Auth', [
'storage' => 'Memory',
'authenticate' => [
'ADmad/JwtAuth.Jwt' => [
'userModel' => 'Users',
'fields' => [
'username' => 'id'
],
'parameter' => 'token',
// Boolean indicating whether the "sub" claim of JWT payload
// should be used to query the Users model and get user info.
// If set to `false` JWT's payload is directly returned.
'queryDatasource' => true,
]
],
'unauthorizedRedirect' => false,
'checkAuthIn' => 'Controller.initialize',
// If you don't have a login action in your application set
// 'loginAction' to false to prevent getting a MissingRouteException.
'loginAction' => [
'controller' => 'Users',
'action' => 'login',
],
]);
and finally this is the user route
Router::scope('/users', function ($routes) {
$routes->setExtensions(['json']);
$routes->resources('Users');
});
'options' network tab:
GENERAL
Request URL: http://localhost:8765/users/login
Request Method: OPTIONS
Status Code: 200 OK
Remote Address: [::1]:8765
Referrer Policy: no-referrer-when-downgrade
RESPONSE HEADERS
Access-Control-Allow-Headers: x-requested-with
Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE
Access-Control-Allow-Origin: *
Allow: POST, GET, OPTIONS, PUT, DELETE
Connection: close
Content-type: text/html; charset=UTF-8
Date: Wed, 03 Jul 2019 14:44:03 +0000
Host: localhost:8765
X-Powered-By: PHP/7.1.26
REQUEST HEADERS
Provisional headers are shown
Access-Control-Request-Headers: x-requested-with
Access-Control-Request-Method: POST
Origin: http://localhost:1841
Referer: http://localhost:1841/
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36
'post' network tab:
GENERAL
Request URL: http://localhost:8765/users/login
Request Method: POST
Status Code: 403 Forbidden
Remote Address: [::1]:8765
Referrer Policy: no-referrer-when-downgrade
RESPONSE HEADERS
Access-Control-Allow-Headers: x-requested-with
Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE
Access-Control-Allow-Origin: *
Allow: POST, GET, OPTIONS, PUT, DELETE
Connection: close
Content-Type: text/html; charset=UTF-8
Date: Wed, 03 Jul 2019 14:44:08 +0000
Host: localhost:8765
X-DEBUGKIT-ID: 6d9d2319-d3a6-4022-a877-fb404d639081
X-Powered-By: PHP/7.1.26
REQUEST HEADERS
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Origin: http://localhost:1841
Referer: http://localhost:1841/
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36
X-Requested-With: XMLHttpRequest
I just want to authenticate the user which is trying to login and send back to the client its JWT token. At the moment the request doesn't even 'reach' the login function. It's the first time that I try to make a login system

HTTP headers are not being sent in CORS GET from AngularJS application

My problem is that HTTP headers are not being sent from my AngularJS HTTP GET requests. However, for a HTTP POST, I do see the headers being set. These HTTP requests are over CORS.
Although there are a lot of SO posts on this problem, I have tried them and none of them worked. One of the solutions suggests that HTTP headers are not sent if the data field is empty, and I've tried the suggestion to add an empty data value (which doesn't really sense for a HTTP GET request, by the way), but still, the HTTP headers do not make it.
On a side note, I might defend that this post/question may merit itself as "not a duplicate" (from the other SO posts) as it deals with HTTP GET (as opposed to HTTP POST) and CORS (as opposed to not-CORS).
Here is my technology stack.
NodeJS v4.2.2
Express v4.13.3
AngularJS v1.4.0
To enable CORS, I followed the example here http://enable-cors.org/server_expressjs.html. My NodeJS server application looks like the following.
var express = require('express');
var bodyParser = require('body-parser');
var morgan = require('morgan');
var jwt = require('jsonwebtoken');
var port = process.env.PORT || 8080;
var router = express.Router();
var app = express();
app.set('secret', 'mySecret');
app.use(express.static('public'));
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(morgan('dev'));
app.use('/api', router);
router.use(function(req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, x-access-token');
res.header('Access-Control-Allow-Methods', 'POST, PUT, GET, OPTIONS, DELETE');
next();
});
router.post('/authenticate', function(req, res) {
var username = req.body.username;
var pw = req.body.password;
if(username !== 'root') {
res.json({
success: false,
message: 'User not found'
});
} else if(pw !== 'root') {
res.json({
success: false,
message: 'Password wrong'
});
} else {
var user = {
username: username,
pw: pw
};
var token = jwt.sign(user, app.get('secret'), {
expiresIn: 60 * 60 * 24 * 365
});
res.json({
success: true,
message: 'Enjoy your token!',
token: token
});
}
});
router.use(function(req, res, next) {
/* according to comments, have to ignore OPTIONS request from protection */
if('OPTIONS' === req.method) { next(); return; } //original post modified here to show, after adding this line, the OPTIONS is accessible, then the GET does actually send the required HTTP header
if('/api/authenticate' === req.originalUrl) {
next();
return;
}
var token = req.body.token || req.params['token'] || req.headers['x-access-token'];
if(token) {
jwt.verify(token, app.get('secret'), function(err, decoded) {
if(err) {
return res.json({
success: false,
message: 'Failed to authenticate token'
});
} else {
req.decoded = decoded;
next();
}
})
} else {
return res.status(403).send({
success: false,
message: 'No token provided'
});
}
});
router.get('/users', function(req, res) {
res.json([
{ fname: 'john', lname: 'doe' },
{ fname: 'jane', lname: 'smith' }
]);
})
var server = app.listen(port, function() {
var host = server.address().address;
var port = server.address().port;
console.log('Example app listening at http://%s:%s', host, port);
});
My AngularJS service looks like the following.
myServices.factory('HomeService', ['$resource', '$http', '$location', '$cookies', 'conf', function($resource, $http, $location, $cookies, conf) {
var svc = {};
svc.getRestUrl = function() {
return 'http://localhost:8080';
};
svc.sendData = function(url, data, method) {
var restUrl = svc.getRestUrl() + url;
var options = {
method: method,
url: restUrl,
withCredentials: false
};
var token = $cookies.get('token');
if(_.isEmpty(token)) {
options.headers = {
'X-Requested-With': 'XMLHttpRequest'
};
} else {
options.headers = {
'X-Requested-With': 'XMLHttpRequest',
'x-access-token': token
};
}
if(data) {
options.data = data;
} else {
options.data = '';
}
return $http(options);
}
svc.getData = function(url) {
return svc.sendData(url, null, 'GET');
};
svc.postData = function(url, data) {
return svc.sendData(url, data, 'POST');
};
svc.authenticate = function(username, password) {
var data = JSON.stringify({
username: username,
password: password
});
return svc.postData('/api/authenticate', data);
};
svc.getUsers = function() {
return svc.getData('/api/users');
};
return svc;
}]);
Note
for the service's authenticate method, this is a HTTP POST
for the service's getUsers, this a HTTP GET
when there is no data to send (HTTP GET), the data is set to empty data: ''
Using Fiddler, for authenticate I see the following HTTP request.
POST http://localhost:8080/api/authenticate HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Content-Length: 37
Accept: application/json, text/plain, */*
Origin: http://localhost
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36
Content-Type: application/json;charset=UTF-8
Referer: http://localhost/
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8
{"username":"root","password":"root"}
For getUsers, I see the following HTTP request.
OPTIONS http://localhost:8080/api/users HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Access-Control-Request-Method: GET
Origin: http://localhost
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36
Access-Control-Request-Headers: accept, x-access-token, x-requested-with
Accept: */*
Referer: http://localhost/
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8
Am I missing something here with regards to HTTP GET over CORS that the HTTP headers are not being sent?
According to your HTTP request, an OPTIONS request is fired to your CORS API icase of your getUsers method.
When it comes to CORS, there are 2 kinds of requests
Simple Requests
Preflighted Requests
Simple requests
A simple cross-site request is one that meets all the following conditions:
The only allowed methods are:
GET
HEAD
POST
Apart from the headers set automatically by the user agent, the only headers which are allowed to be manually set are:
Accept
Accept-Language
Content-Language
Content-Type
The only allowed values for the Content-Type header are:
application/x-www-form-urlencoded
multipart/form-data
text/plain
Preflighted requests
In case you make any request which violates the conditions of a simple request, then a "preflighted" OPTIONS request is sent in order to determine whether the actual request is safe to send.In particular, a request is preflighted if:
It uses methods other than GET, HEAD or POST. Also, if POST is used
to send request data with a Content-Type other than
application/x-www-form-urlencoded, multipart/form-data, or
text/plain, e.g. if the POST request sends an XML payload to the
server using application/xml or text/xml, then the request is
preflighted.
It sets custom headers in the request (e.g. the request uses a header
such as X-PINGOTHER)
For more details about Preflighted Requests, you can refer to this MDN link.
I believe this is what is happening in your case. Even though you're making a simple GET request, you're adding 2 custom headers X-Requested-With & x-access-token which makes it necessary to validate the safety of your API, so a preflighted OPTIONS request is sent by the browser. The browser will continue with your GET request only if it receives valid response.
In your NodeJS server code, you're handling only POST requests to /authenticate and GET requests to /users, so in case of an OPTIONS request, it's going to the default handler where you're checking for token and if it's not available, you respond with a 403. So I suggest you change your code to handle OPTIONS request as well.

AngularJS Satellizer jwt CORS issue when authenticated

i'v got weird behaviour of my code. I'm using Satellizer to authenticate user and when user is not authenticated when i execute this code:
$http.get('http://eune.api.pvp.net/api/lol/eune/v1.4/summoner/by-name/somename?api_key=XXXXXXXXXXXXXXXXX')
.success(function (data) {
console.log(data);
});
my request is ok and i get data
headers:
Accept:application/json, text/plain, */*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:pl-PL,pl;q=0.8,en-US;q=0.6,en;q=0.4
Connection:keep-alive
Host:eune.api.pvp.net
Origin:http://localhost:9000
Referer:http://localhost:9000/
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.93 Safari/537.36
but when i authenticate user and try to do same request i get:
XMLHttpRequest cannot load http://eune.api.pvp.net/api/lol/eune/v1.4/summoner/by-name/somename?api_key=XXXXXXXXXXXX. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:9000' is therefore not allowed access. The response had HTTP status code 401.
and headers of this request looks like:
Accept:*/*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:pl-PL,pl;q=0.8,en-US;q=0.6,en;q=0.4
Access-Control-Request-Headers:accept, authorization
Access-Control-Request-Method:GET
Connection:keep-alive
Host:eune.api.pvp.net
Origin:http://localhost:9000
Referer:http://localhost:9000/
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.93 Safari/537.36
my app.config
.config(function ($urlRouterProvider, $stateProvider, $httpProvider, $authProvider, API_URL) {
$urlRouterProvider.otherwise('/');
... some routes ...
$authProvider.loginUrl = API_URL + 'login';
$authProvider.signupUrl = API_URL + 'register';
$authProvider.google({
clientId: 'secret',
url: API_URL + 'auth/google'
});
$authProvider.facebook({
clientId: 'secret',
url: API_URL + 'auth/facebook'
});
// $httpProvider.interceptors.push('authInterceptor');
})
So how should i fix it? I suppose that those headers with Access-Control are the reason, but how should i handle it?
You could try putting the following in the satellizer config:
$authProvider.httpInterceptor = false;
Adding skipAuthorization property in config block might be helpful:
$http.get('http://eune.api.pvp.net/api/lol/eune/v1.4/summoner/by-name/somename?api_key=XXXXXXXXXXXXXXXXX', {
skipAuthorization: true
})
.success(function (data) {
console.log(data);
});
I usually work with the config block by preference. This is how it would look.
//configuration block method:
$http({
method: 'GET',
url: 'http://eune.api.pvp.net/api/lol/eune/v1.4/summoner/by-name/somename?api_key=XXXXXXXXXXXXXXXXX',
skipAuthorization: true
});
Good Luck.
Ok i figured it out. As i supposed Satellizer registers new interceptor, which adds some headers and that's why it doesn`t work. This is satellizer code :
.config(['$httpProvider', 'satellizer.config', function($httpProvider, config) {
$httpProvider.interceptors.push(['$q', function($q) {
var tokenName = config.tokenPrefix ? config.tokenPrefix + '_' + config.tokenName : config.tokenName;
return {
request: function(httpConfig) {
var token = localStorage.getItem(tokenName);
if (token && config.httpInterceptor) {
token = config.authHeader === 'Authorization' ? 'Bearer ' + token : token;
httpConfig.headers[config.authHeader] = token;
}
return httpConfig;
},
responseError: function(response) {
return $q.reject(response);
}
};
}]);
}]);
i handled it by changing one lane to this:
if (token && config.httpInterceptor && httpConfig.rawReq !== true) {
and i pass in my httpConfig option rawReq: true
but this is not nice. Is there posibility to disable specific interceptor ?

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":"myemail#email.com","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);
}
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})

Resources