How to pass JsonWebToken x-access-token through angular js - angularjs

I created a node express RESTful API with jsonwebtoken as authentication method. But unable to pass the x-access-token as headers using angular js.
my JWT token authentication script is,
apps.post('/authenticate', function(req, res) {
// find the item
Item.findOne({
name: req.body.name
}, function(err, item) {
if (err) throw err;
if (!item)
{
res.json({ success: false, message: 'Authentication failed. item not found.' });
}
else if (item)
{
// check if password matches
if (item.password != req.body.password)
{
res.json({ success: false, message: 'Authentication failed. Wrong password.' });
}
else
{
// if item is found and password is right
// create a token
var token = jwt.sign(item, app.get('superSecret'), {
expiresIn: 86400 // expires in 24 hours
});
res.json({
success: true,
message: 'Enjoy your token!',
token: token
});
}
}
});
});
Middleware which checks the token is correct is,
apps.use(function(req, res, next) {
// check header or url parameters or post parameters for token
var token = req.body.token || req.params.token || req.headers['x-access-token'];
// decode token
if (token)
{
// verifies secret and checks exp
jwt.verify(token, app.get('superSecret'), function(err, decoded) {
if (err)
{
return res.json({ success: false, message: 'Failed to authenticate token.' });
}
else
{
// if everything is good, save to request for use in other routes
req.decoded = decoded;
next();
}
});
}
else
{
// if there is no token
// return an error
return res.status(403).send({
success: false,
message: 'No token provided.'
});
}
});
Finally the GET method script is,
app.get('/display', function(req, res) {
Item.find({}, function(err, items) {
$http.defaults.headers.common['X-Access-Token']=token;
res.json(items);
});
});
But it always failed to authenticate. Please any one help me to solve this issue. I am really stucked here.
It always shows only the following authentication failed message.
{"success":false,"message":"No token provided."}

If you use $http as the dependency in your angular controller then this would help you I guess -
var token = this.AuthToken.getToken();
$http.get('/api/me', { headers: {'x-access-token': token} });
I will change this according to your code once you upload your angular code.

The client should be sending the token in the Authorization header, using the Bearer scheme, as 'X-' headers have been deprecated since 2012:
Your node would now be along the lines of:
apps.post('/authenticate', function(req, res) {
.....
var token = 'Bearer' + ' ' + jwt.sign(item, app.get('superSecret'), {
expiresIn: 86400 // expires in 24 hours
});
.....
}
apps.use(function(req, res, next) {
// Trim out the bearer text using substring
var token = req.get('Authorization').substring(7);
....
}
Then your angular code would become:
var token = this.AuthToken.getToken();
$http.get('/api/me', { headers: {'Authorization': token} });

You could create a interceptor that catches all ajax calls and injects the token into the header. That way you would not have inject it every time you make an ajax call.
This is a good place to start if you wanted to go that route:
http://www.webdeveasy.com/interceptors-in-angularjs-and-useful-examples/

Related

MEAN: Loggin in by JWT

[Q1] What advantage does an HTTP Interceptor provide on modifying the config.headers["Authorization"] (frontend AngularJS) to contain the value of token when I can verify the requests by checking the req.cookies object? (at the backend NodeJS)
I am trying to understand how JSON web tokens function. The demo application I have setup has a login functionality.
On GET '/login' I am able to produce a token, set a cookie with it.
On the frontend, I can access a JSON object containing the token.
I can view the cookie in the developer console.
Nodejs:
index.js - login route
router.post('/login', function(req, res, next) {
Authenticator.find(req.cookies.token, req.body, Heartbeat.common, function(err, warning, data){
if(err) {
res.status(404).send({token:false, warning: null, error:err});
} else if(warning){
res.status(200).send({token:true, warning: warning, error:null});
} else {
res.cookie('token', data, {maxAge: 3600000, httpOnly:true});
res.status(200).json({token:true, error: null});
}
});
});
Authenticator.ctrl.js - Authenticator.find()
find: function(token, user, heartbeat, callback) {
if(!token) {
Auth.findOne({email:user.email}, function(err, data){
if(err) {
console.log(err);
} else {
if(data) {
if(data.checkHash(user.password)) {
callback(null, null,TokenMaker.createToken(user.email, heartbeat));
} else {
callback(Errors.login.strict.MISMATCH, null, null);
}
} else {
callback(Errors.login.strict.NOT_REGISTERED, null, null);
}
}
});
} else {
callback(null, Errors.login.warning.ACTIVE_REFRESH, null);
}
},
Angular Controller
app.controller('userAccessCtrl', ['$scope', '$http', function ($scope, $http){
$scope.user = {
email: "someone#some.com",
password: "12345679"
};
$scope.error = {};
$scope.loginAccess = function(user) {
var submitReady = true;
var emailStatus = EmailValidator.email(user.email);
var passwordStatus = EmailValidator.password(user.password);
if(typeof emailStatus === "string") {
$scope.error.email = emailStatus;
submitReady = false;
}
if(typeof passwordStatus === "string") {
$scope.error.password = passwordStatus;
submitReady = false;
}
if(submitReady) {
$scope.error = {}
var data = $scope.user;
$scope.user = {};
$http.post('/login', data)
.then(function(success){
console.log(success);
},function(error){
console.log(error);
});
}
}
}]);
Console response:
{
"data": {
"token":true,
"error":null
},
"status":200,
"config":{
"method":"POST",
"transformRequest":[null],
"transformResponse":[null],
"url":"/login",
"data":{
"email":"someone#some.com",
"password":"12345679"
},
"headers":{
"Accept":"application/json, text/plain, */*",
"Content-Type":"application/json;charset=utf-8"
}
},
"statusText":"OK"
}
Actually it's a wrong to use cookies and JWT tokens.
JWT token is much better for authentication than cookies.
When you use token, your server doesn't need to store session in database of memory and this is a big advantage for your application - you can scale you application, add new servers without thinking about how to sync sessions between servers.
In short words, when you use JWT token your flow is next:
frontend (in you case it's an angular) sends login and password to /login route
backend checks credentials and sends back token (in request body, not in cookies)
frontend app saves token in local storage or session storage of browser
and you can write HTTP Interceptor which will intercepts all requests to backend and it will attach "Authorization" header to all requests, it looks like next:
Authorization: Bearer here-is-your-jwt-token
backend can check this authorization header and if it is correct (look at http://jwt.io to read how verification works) backend can serve you request.

Angular Node - send token to server upon opening new browser window

The question is pretty self-explanatory: I have a token stored on my browser. When I log in, the server-side authentication middleware uses Passport to authenticate me. However, when I close and re-open my browser window the token is still there but Passport doesn't know who I am.
How can I retrieve the token from the client side to the server side?
Below is my code.
app.get('/main', ensureAuthenticated, function(req, res, next) {
// thingToSend gets sent the first time, I will modify it
// later so it doesn't resend token if token exists
var thingToSend = {
token: createSendToken(req.user, config.secret),
id: req.user._id,
username: req.user.username,
authorization: req.user.authorization
};
res.render('main.ejs', thingToSend);
});
function ensureAuthenticated(req, res, next) {
if (req.isAuthenticated()) {
return next();
} else {
res.redirect('/login_page');
}
}
You should add an request interceptor to your angular app and attach your auth token along with every request you send to the server.
Read more about request interceptors here: https://docs.angularjs.org/api/ng/service/$http
So the answer to my problem was to make a request interceptor which I injected in app.config. The request interceptor collects the token, and anytime after my initial session the request interceptor attaches the token to the request header:
app.factory('httpInterceptor', function($q, $store, $window) {
return {
request: function (config){
config.headers = config.headers || {};
if($store.get('token')){
var token = config.headers.Authorization = 'Bearer ' + $store.get('token');
}
return config;
},
responseError: function(response){
if(response.status === 401 || response.status === 403) {
$window.location.href = "http://localhost:3000/login";
}
return $q.reject(response);
}
};
});
It then uses function ensureAuthentication() to check either a) Passport.authentication upon initial login, or b) checks token authentication anytime after that in a custom function checkAuthentication().
function ensureAuthenticated(req, res, next) {
if (req.isAuthenticated()) {
return next();
} else {
var x = checkAuthentication(req, res, next);
if (x === true) {
return next();
} else {
res.redirect('/login_Page');
}
}
}
Anyone interested in seeing checkAuthentication() or my progress in troubleshooting a related issue regarding JSON web tokens: JWT not decoding "JWT malformed" - Node Angular

CORS issue when combining AngularJS with PassportJS

I'm trying to combine ExpressJS + PassportJS with Angular SPA application. The problem probably is in CORS headers.
Here is what I'm trying to accomplish:
Client View:
<a class="btn btn-block btn-social btn-twitter" ng-click="twitter()">
<i class="fa fa-twitter"></i> Sign in with Twitter
</a>
Client Controller:
Is the following approach correct?
$scope.twitter = function() {
$http.get('oauth/twitter').then(function(res) {
// Fetch the user from response and store it somewhere on the client side
});
};
The server side responsible for handling authentication looks as follows:
Server routes:
app.get('/oauth/twitter', passport.authenticate('twitter', {
failureRedirect: '/signin'
}));
app.get('/oauth/twitter/callback', passport.authenticate('twitter', {
failureRedirect: '/signin',
successRedirect: '/'
}));
Twitter strategy:
passport.use(new TwitterStrategy({
consumerKey: config.twitter.clientID,
consumerSecret: config.twitter.clientSecret,
callbackURL: config.twitter.callbackURL,
passReqToCallback: true
}, function (req, token, tokenSecret, profile, done) {
var providerData = profile._json;
providerData.token = token;
providerData.tokenSecret = tokenSecret;
var providerUserProfile = {
fullName: profile.displayName,
username: profile.username,
provider: 'twitter',
providerId: profile.id,
providerData: providerData
};
users.saveOAuthUserProfile(req, providerUserProfile, done);
}));
Users Server Controller:
exports.saveOAuthUserProfile = function (req, profile, done) {
User.findOne({
provider: profile.provider,
providerId: profile.providerId
}, function (err, user) {
if (err) {
return done(err);
} else {
if (!user) {
var possibleUsername = profile.username || ((profile.email) ? profile.email.split('#')[0] : '');
User.findUniqueUsername(possibleUsername, null, function (availableUsername) {
profile.username = availableUsername;
user = new User(profile);
user.fullName = profile.fullName;
user.save(function (err) {
if (err) {
var message = getErrorMessage(err);
req.flash('error', message);
return done(err);
}
return done(err, user);
});
});
} else {
return done(err, user);
}
}
});
};
When I click Sign in with Twitter in a browser (Chrome/Firefox) I see the following requests being made:
GET http://localhost:3000/oauth/twitter (302 Moved Temporarily)
GET https://api.twitter.com/oauth/authenticate?oauth_token=Zz014AAAAAAAg5HgAA******** (307 Internal Redirect)
The browser complains about missing "Access-Control-Allow-Origin" headers.
To fix this I have tried using cors package like this
var cors = require('cors');
api.use(cors());
and also manually setting headers of all responses, with no effect.
Could you please show me the way?
Regards
Instead of using cors module,try to set header in nodejs
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
I faced with a similar problem and couldn't fix it within the code. So I found this Chrome extension: Allow-Control-Allow-Origin: *
You can set URL patterns and enable Cross-Origin Resource Sharing.
Don't forget to disable it when you finish your work!

Trouble with getting data from nodejs/express because of CORS

Solution here: Trouble with getting data from nodejs/express because of CORS
So i have a problem with getting data from nodejs/express because of CORS.
I'm getting error something like this (sorry, error i translated with google):
Query from an external source is blocked: one source of policy prohibits reading remote resource on http://localhost:8080/api/login. (Cause: Failed to query CORS).
I'm trying to send query with angular $http.post
$http.post($rootScope.api + 'login', {
email: form.email.$viewValue,
password: form.password.$viewValue
}).then(function(data) {
console.log(data.data);
});
Here is my server code (i cut some code, because i think it not important):
/* some nodejs requires */
var cors = require('express-cors');
mongoose.connect('mongodb://localhost:27017/batarindashboard');
require('./config/passport')(passport);
/* some express settings */
app.use(cors({
allowedOrigins: [
'localhost:*', '127.0.0.1:*'
]
}));
var port = process.env.PORT || 8080;
var router = express.Router();
router.use(function(req, res, next) {
console.log('Something is happening');
next();
});
/* sign up api */
router.post('/login', passport.authenticate('local-login', {
failureRedirect : '/api/passport_message',
failureFlash : true
}), function(req, res) {
res.json({
'message': 'You successfully signed in!'
});
});
/* passport_message api */
/* is_logged_in api */
/* logout api */
app.use('/api', router);
app.listen(port);
console.log('Magic happens on port ' + port);
And passport file (maybe problem is here. Why not?)
var LocalStrategy = require('passport-local').Strategy;
var User = require('./../app/models/user');
module.exports = function(passport) {
/* some serialize deserialize code */
/* sign up strategy */
passport.use('local-login', new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true
}, function(req, email, password, done) {
User.findOne({
'local.email':email
}, function(err, user) {
if(err) return done(err);
if(!user) {
return done(null, false, req.flash('message', 'No user found.'));
}
if(!user.validPassword(password)) {
return done(null, false, req.flash('message', 'Oops! Wrong password.'));
}
return done(null, user);
})
}))
};

Sign in Twitter OAuth without Sessions aka token_secret (AngularJS Fail)

This is an express route from angularjs satellizer example, implementing 3 legged OAuth with Twitter:
/*
|--------------------------------------------------------------------------
| Login with Twitter
|--------------------------------------------------------------------------
*/
app.get('/auth/twitter', function(req, res) {
var requestTokenUrl = 'https://api.twitter.com/oauth/request_token';
var accessTokenUrl = 'https://api.twitter.com/oauth/access_token';
var authenticateUrl = 'https://api.twitter.com/oauth/authenticate';
if (!req.query.oauth_token || !req.query.oauth_verifier) {
var requestTokenOauth = {
consumer_key: config.TWITTER_KEY,
consumer_secret: config.TWITTER_SECRET,
callback: config.TWITTER_CALLBACK
};
// Step 1. Obtain request token for the authorization popup.
request.post({ url: requestTokenUrl, oauth: requestTokenOauth }, function(err, response, body) {
var oauthToken = qs.parse(body);
var params = qs.stringify({ oauth_token: oauthToken.oauth_token });
// Step 2. Redirect to the authorization screen.
res.redirect(authenticateUrl + '?' + params);
});
} else {
var accessTokenOauth = {
consumer_key: config.TWITTER_KEY,
consumer_secret: config.TWITTER_SECRET,
token: req.query.oauth_token,
verifier: req.query.oauth_verifier
};
// Step 3. Exchange oauth token and oauth verifier for access token.
request.post({ url: accessTokenUrl, oauth: accessTokenOauth }, function(err, response, profile) {
profile = qs.parse(profile);
// Step 4a. Link user accounts.
if (req.headers.authorization) {
User.findOne({ twitter: profile.user_id }, function(err, existingUser) {
if (existingUser) {
return res.status(409).send({ message: 'There is already a Twitter account that belongs to you' });
}
var token = req.headers.authorization.split(' ')[1];
var payload = jwt.decode(token, config.TOKEN_SECRET);
User.findById(payload.sub, function(err, user) {
if (!user) {
return res.status(400).send({ message: 'User not found' });
}
user.twitter = profile.user_id;
user.displayName = user.displayName || profile.screen_name;
user.save(function(err) {
res.send({ token: createToken(user) });
});
});
});
} else {
// Step 4b. Create a new user account or return an existing one.
User.findOne({ twitter: profile.user_id }, function(err, existingUser) {
if (existingUser) {
var token = createToken(existingUser);
return res.send({ token: token });
}
var user = new User();
user.twitter = profile.user_id;
user.displayName = profile.screen_name;
user.save(function() {
var token = createToken(user);
res.send({ token: token });
});
});
}
});
}
});
The problem is Step 3:
var accessTokenOauth = {
consumer_key: config.TWITTER_KEY,
consumer_secret: config.TWITTER_SECRET,
token: req.query.oauth_token,
verifier: req.query.oauth_verifier
};
// Step 3. Exchange oauth token and oauth verifier for access token.
request.post({ url: accessTokenUrl, oauth: accessTokenOauth });
Because the node-request documentation describes Step 3 as:
// step 3
// after the user is redirected back to your server
var auth_data = qs.parse(body)
, oauth =
{ consumer_key: CONSUMER_KEY
, consumer_secret: CONSUMER_SECRET
, token: auth_data.oauth_token
, token_secret: req_data.oauth_token_secret
, verifier: auth_data.oauth_verifier
}
, url = 'https://api.twitter.com/oauth/access_token'
;
request.post({url:url, oauth:oauth}
The difference is, in the satellizer example, it doesn't pass token_secret to sign-in, but it should. So is this a mistake or what am I missing?
The real problem for me was, 3 legged twitter sign-in flow actually requires session on server side, but the satellizer example doesn't use any sessions, so I was wondering how this possible without sessions, but either it is not possible and satellizer example is wrong, or I don't understand something.

Resources