OAuth Token Response to Angular View (cookie) - angularjs

I've been struggling with this for a couple hours now and need some help. I've created a simple app that presents the user with a "Login Using Google" button in an angular view that redirects the user to the Google Oauth page. Here's the controller code that calls the login() function when the button is pressed:
angular.module('dashApp').controller('SigninCtrl', function ($scope) {
$scope.login=function() {
var client_id="191641883719-5eu80vgnbci49dg3fk47grs85e0iaf9d.apps.googleusercontent.com";
var scope="email";
var redirect_uri="http://local.host:9000/api/auth/google";
var response_type="code";
var url="https://accounts.google.com/o/oauth2/auth?scope="+scope+"&client_id="+client_id+"&redirect_uri="+redirect_uri+
"&response_type="+response_type;
window.location.replace(url);
};
});
The redirect URI set in my google project redirects to a server page to this server page:
'use strict';
var _ = require('lodash');
var request = require('request');
var qs = require('querystring');
var fs = require('fs');
// Get list of auths
exports.google_get = function (req,res){
var code = req.query.code,
error = req.query.error;
if(code){
//make https post request to google for auth token
var token_request = qs.stringify({
grant_type: "authorization_code",
code: code,
client_id: "191641883719-5eu80vgnbci49dg3fk47grs85e0iaf9d.apps.googleusercontent.com",
client_secret: process.env.GOOGLE_SECRET,
redirect_uri: "http://local.host:9000/api/auth/google"
});
var request_length = token_request.length;
var headers = {
'Content-length': request_length,
'Content-type':'application/x-www-form-urlencoded'
};
var options = {
url:'https://www.googleapis.com/oauth2/v3/token',
method: 'POST',
headers: headers,
body:token_request
};
request.post(options,function(error, response, body){
if(error){
console.error(error);
}else{
//WHAT GOES HERE?
}
});
}
if(error){
res.status(403);
}
}
I'm able to exchange the code returned by google for an auth token object successfully and log it to the terminal. I've been told that I should set a cookie using:
res.setHeader('Content-Type', 'text/plain');
res.setCookie('SID','yes',{
domain:'local.host',
expires:0,
path:'/dashboard',
httpOnly:false
});
res.status(200);
res.end();
Followed by a controller on the page I'm directing the user to that validates the session.
What am I doing wrong?

Since you have already done the hard work so there is no point talking about passport.js which is actually written to simplify these kind of social login authentication.
So let's come directly to session implementaion logic.
You need to set the following header in your app.js/server.js :
app.use(function(req, res, next) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST');
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type, Authorization');
next();
});
Let's say you are returning this token after successful login :
{
name : "some name",
role : "some role",
info : "some info"
}
You can have a client side function in your angular service or controller :
function(user,callback){
var loginResource = new LoginResource(); //Angular Resource
loginResource.email = user.email;
loginResource.password = user.password;
loginResource.$save(function(result){
if(typeof result !== 'undefined'){
if(result.type){
$localStorage.token = result.token;
$cookieStore.put('user',result.data);
$rootScope.currentUser = result.data;
}
}
callback(result);
});
}
LoginResource calls your REST endpoint which returns auth token.
You can store your auth token in localStorage and cookieStore.
localStorage makes sure that we are having the token saved even when user has closed the browser session.
If he clears the localStorage and cookieStorage both then log him out as you don't have any valid token to authorize user.
This is the same logic which i am using here. If you need more help then let me know.

Related

Read cookie in AngularJs, REST API

So, I created my client application using angular to interact with my WCF REST API. I basically use cookies to store the login session and retrieve the information by sessions. This works perfectly from Postman and also with a console client application (there I created cookie container).
Now I have a problem to read the cookies from AngularJs. My HTTP response header shows the cookies but the angular response header is undefined.
AngularService.js:
this.login = function (credential) {
var request = $http({
method: "POST",
url: "someUrlLogin",
data: angular.toJson(credental),
config: { withCredentials: true },
});
return request;
}
AngularContoller.js :
var promisePost = AngularService.login(credential);
promisePost.then(function (response) {
$scope.loginResult = angular.fromJson(response);
$timeout(function () {
console.log(response.headers("Set-Cookie"); //null
console.log($cookies["ASP.NET_SessionId"]); //undefined
console.log($cookies.getAll); //undefined
},
function error (err) {
$scope.loginResult = err;
});
WCF REST session:
_context.Session["USERLOGGEDIN"] = "SomeValue"
I have set the HTTPOnly flag to false
I have also tried "console.log(response.headers("setcookie") which also doesn't work
"Access-Control-Allow-Credentials = true"
"Access-Control-Expose-Headers" value="content-type, Set-Cookie"
What else am I missing? Is it even possible to read the cookies from the http response headers?

Angularjs $http service passing facebook access token

I'm implementing fb authentication in my SPA built using MEAN stack. While I've successfully implemented the fb authentication using facebook token passport strategy, I'm facing issues in securing API endpoints. Because for that I need to pass both the authenticated user object and access token in the $http service and I've tried passing access_token as a property of the user object and also as a header property, but I still 401 (Unauthorized error). Below is my code snippet.
Passport documentation says "Authorization: Bearer base64_access_token_string". Should the token be encoded in a base64 format? Pls help.
server code
app.get('/api/getbikes*',
passport.authenticate('facebook-token',{session: false}),
function(req,res){
if(req.user){
console.log('In getbikes api');
// console.log('req.query :',req.query);
var msg="";
ubBike
.find({cust:req.query._id})
.populate('cust','email')
.exec(function(err,bikes){
res.send(bikes);
if(err) throw err;
});
}
else
{
res.send(401);
}
});
angular code
service
this.getbikes = function(user){
var deferred = $q.defer();
$http({
method:"GET",
url:"http://localhost:3000/api/getbikes",
params: user,
headers:{
Authorization:auth.getAccesstoken()
}
}).then(function successCallback(srresponse){
deferred.resolve(srresponse.data);
},
function failureCallback(srresponse){
$log.error("get bikes http call failed ",srresponse.data);
deferred.reject(srresponse.data);
});//$http
return deferred.promise;
};//getbikes
controller
$scope.fblogin= function(){
auth.fblogin().then(
function(response){
$scope.isAuth = auth.isAuth;
$scope.usr =auth.getResponseobj();
$scope.usr.access_token=auth.getAccesstoken();
$scope.profpic=auth.profpic;
bike.getbikes($scope.usr).then(function(response){
if (response.length ==0)
{
$location.path('/addbike');//redirect to addbike screen
}
else{
$location.path('/appoint');//else redirect to view appointment screen
}
},function(reason){
$scope.msg1 = reason;
});//getbikes
},function(reason){
$log.log("fblogin() - failure :Need to login to the application :"+reason);
})
};//fblogin
Surprisingly, when I send the header as "Authorization: Bearer access_token_string" ie the fb token as is without base64 encoding the API authentication works perfectly fine. This is contrary to the passport facebook token documentation https://github.com/drudge/passport-facebook-token

Custom AngularJS $http interceptor case

recently i am working hard on my website with angularjs on the Front End and Symfony 3 on the backend. I put a security layer on my backend so every request from my FE must need a valid token (using grant_type=client_credentials). I have read a looooot about the best practices about call my API Backend with angular... I normally send the token on every request that i make to the Backend, but i read that i can use the $http interceptor to send always on the header my bearer token.
So, i am a little confused that how start... because for one part:
i want to do calls to my backend to load certain data to be used on my pages to show info (using the grant_type=client_credentials) and,
i will have an user management system too. So this users must to login with user and password (again another call to my backend) but with grant_type=password...
The really big question is:
can i do the same things with one interceptor? (one for show page elements data with grant_type=client_credentials and other for the normal users?)
Tha another question is... can i make a token with this interceptor if the token has not been created yet (only for the pages info, for the users i want to refresh the token if is going to expire)?
Sorry if is a little confused... i am confused, i really read many posts, documentation and help... but i don't know where to start... I hope that you can help me...
Thanks for all.
The beauty of JWT is that they are essentially just javascript objects. You could for instance provide the user a token containing their role in the system (user, admin, support etc...) and show/hide elements accordingly.
So basically not only you grant the user access to the API, you also provide them with their type of access. Of course you should NEVER rely on client side authentication to allow restricted API's directly (verify the token on each request, check for the provided role on the server).
Here's an example in NodeJS and Angular:
//In NodeJS...
app.get('/path/to/secured/api', verifyTokenOr401, function(req, res) {
//Do stuff...
res.json({msg: 'Success');
});
function verifyTokenOr401(req, res, next) {
var authHeader = req.headers.authorization;
try {
var token = authHeader.split(' ')[1];
if(jwt.verify(token, 'myAppSecret'))
next();
} catch(e) {
res.status(401).send('Not authorized');
}
}
//Assuming you use node-jsonwebtoken package
app.post('/path/to/authentication', function (req, res) {
//Verify authentication...
User.findOne({username: req.body.username}).then(function(user) {
//VerifyPassword
if(!user)
return res.status(401).send('No such user ' + req.body.username);
if(!user.verifyPassword(req.body.password))
return res.status(401).send('Wrong password for user ' + user.username);
//Provide the user with the access token
var token = jwt.sign({ subject: user.id, role: user.role }, 'myAppSecret');
res.setHeader('Authorization', 'Bearer ' + token.toString());
res.json(user);
})
.catch(function (e) { res.status(500).json(e); });
});
//In angular...
.factory('jwtInterceptor', function() {
return {
request: function(config){
var authHeader = config.headers('authorization');
//Attach header if not present
if(!authHeader)
config.headers.authorization = 'Bearer ' + localStorage.get('myAppToken');
return config;
},
response: function(response){
//Look for token in the header if you get a response and save it
var authHeader = response.headers('authorization');
if(authHeader){
try { localStorage.myAppToken = authHeader.split(' ')[1]; } catch(e) {}
}
return response;
}
}
});
Notable mention: check out auth0's repos for NodeJS and Angular. Both are awesome.
You can create a service which when loaded by angular make a get call for authorization token and set in header. Through this you do not need to set token at every Ajax call. You can do it like this:
app.service("MyService", ["$http", function($http) {
initialize();
function initialize() {
getAuthorizationToken().then(function(response) {
$http.defaults.headers.common.Authorization = 'Bearer some_auth_code_here';
});
}
function getAuthorizationToken() {
// Get call for token
}
}]);

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

Resources