I'm currently developing a Web Application with AngularJS and I have the following question with the login system: is secure to store the information like username you used to login into the cookies?
I mean, when i login I want to store the username or the id, would be the same, into a cookie, so I can load more information from the database each time the user navigates between the different links. The thing is that I don't know if Angular has any protection about cookie edition or, in other words, should I trust this cookie's value will be the correct one?
For example, having this piece of code, is it secure?
var request = {
url: 'backend/getCharacters.php?user=' + $cookies.get('username'),
method: 'GET'
};
$http(request).then(function(response) {
if(response.status == 200)
// Get character list
else
alert('Something went wrong.');
});
You should declare ngCookies in your function. You can see following example to understand more about use cookies in angularjs. I hope you would like these resources.
Use this code. I hope it will be work for you.
angular.module('myApp', ['ngCookies']);
function CookieCtrl($scope, $cookieStore) {
var tabname = [{'KaluSingh'}]; // tabname contains username
$cookieStore.put('username', tabName);
};
var request = {
url: 'backend/getCharacters.php?user=' + $cookies.get('username'),
method: 'GET'
};
$http(request).then(function(response) {
if(response.status == 200)
// Get character list
else
alert('Something went wrong.');
});
stackoverflow.com/questions/10961963/how-to-access-cookies-in-angularjs
https://docs.angularjs.org/api/ngCookies/service/$cookies
https://docs.angularjs.org/api/ngCookies
Related
I want to refresh a URL upon successful login without a page refresh.
I am using the following code
$scope.Login = function (teacher, chkRememberMe) {
alert(chkRememberMe);
$http.post("/Teacher/Login", { teacher: teacher, chkRememberMe: chkRememberMe })
.success(function (result) {
if (result == "True") {
toastr.success("You are Login successfully!!!");
$timeout(function () { }, 5000);
$timeout(function () { }, 5000);
$location.path('Teacher/Index');
}
else {
toastr.error("The email and password you entered don't match.")
window.location = "/Teacher/Login";
}
})
.error(function (error) {
error.message
alert(error);
toastr.error("The email and password you entered don't match11")
})
}
The URL is not updating successfully.
You can use history.replaceState(data,title,url) to accomplish this. There's a bit of documentation at MDN. The history.js library may be of interest as well.
If you're trying to handle single-page authentication with angular, it can be a hassle. You may want to take a look at AngularJS: Basic example to use authentication in Single Page Application for more on this.
An aside: you may also want to consider taking steps to ensure that password managers function as you'd expect. There are a few stackoverflow questions which address these concerns (e.g., How to make Chrome remember password for an AJAX form?).
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
}
}]);
I have been fumbling around with different implementations and ideas to get this to work, but I feel like I am not doing this as DRY or smart as I could be. I've been following this "tutorial" Angular Auth
So, I have a fully functional laravel (4.2) back end set up with some resource routes protected by the oauth filter. I am using the password grant and everything is working just fine there. I've got log in/out routes also set up and am able to sign in to my Ionic app and obtain and access_token and refresh_token from laravel just fine. Obtaining new access_tokens using the refesh_token works just fine as well. BUT, I am having some issues trying to figure out how to correctly handle the following things in Ionic:
Make sure the access_token hasn't expired before the user hits an Ionic state which will consume a resource from my back end.
Handle the case where the user's access_token & refresh token have both expired requiring them to log back in to the laravel back end in order to obtain a new pair of access & refresh tokens. I only have the user "log in" when they need to obtain a new access_token & refresh token (or they are first registering) as this route, oauth/access_token, requires the params {username, password}.
What I Tried
In the article I mentioned earlier, he sets up a rootScope watcher in the run module which watches for the statechangestart event like so.
$rootScope.$on('$stateChangeStart', function (event, next) {
var authorizedRoles = next.data.authorizedRoles;
if (!AuthService.isAuthorized(authorizedRoles)) {
event.preventDefault();
if (AuthService.isAuthenticated()) {
// user is not allowed
$rootScope.$broadcast(AUTH_EVENTS.notAuthorized);
} else {
// user is not logged in
$rootScope.$broadcast(AUTH_EVENTS.notAuthenticated);
}
}
});
I am not using roles so when I implemented this I just had something like this
$rootScope.$on('$stateChangeStart', function(event, next) {
if (next.url != "/login") {
AuthService.isAuthenticated().then(function() {
console.log('you are already authed an logged in and trying to access: ' + next.url);
}, function() {
event.preventDefault();
console.log('YOU DO NOT HAVE A VALID ACCESS TOKEN');
$location.path('/app/login');
});
}
});
isAuthenticated() just hits a route inside my oauth filter so if it throws back an error (401 for example), I know that the access_token is bad. I then have a private method also inside my AuthService service that tries to get a new access_token using the users stored refresh_token
function useRefreshToken() {
console.log('Using refresh token to get new token:');
var deferred = $q.defer();
$http({
method: 'POST',
url: base_url.dev.url + 'oauth/access_token',
data: $.param({
grant_type: 'refresh_token',
client_id: API.client_id,
client_secret: API.client_secret,
refresh_token: $localStorage.session.refresh_token
}),
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}).success(function(data) {
console.log('refresh token worked!');
$localStorage.session.access_token = data.access_token;
$localStorage.session.refresh_token = data.refresh_token;
deferred.resolve();
}).error(function(error) {
console.log('refresh token failed');
CurrentUserService.setLogged(false);
console.log(JSON.stringify(error));
deferred.reject(error);
});
return deferred.promise;
};
If the above method returns back a rejected promise I just assume (which may be a good idea or not??) that the refresh token has expired and thus the user needs to log back in and retrieve a new access & refresh token pair from my laravel oauth/access_token route.
So the above methods have been working fine on their own, in that I am able to check if the users access_token is valid and if not retrieve a new access_token just fine using the users refresh_token.
Here's my isAuthenticated method in case you wanted to see that as well. It's a public method inside of my AuthService service.
isAuthenticated: function() {
console.log('Checking if token is still valid.');
var deferred = $q.defer();
$http.get(base_url.dev.url + 'valid-token', {
params: {
access_token: $localStorage.session.access_token
}
}).success(function(data) {
console.log('Token is still valid.');
CurrentUserService.setLogged(true);
deferred.resolve();
}).error(function(error) {
console.log(JSON.stringify(error));
useRefreshToken().then(function() {
deferred.resolve();
}, function(error) {
deferred.reject(error);
});
});
return deferred.promise;
}
The big problem I was running into is that because the AuthService.isAuthenticated() method runs async, the state the app was changing to, say PHOTOS, would be hit before isAuthenticated returns and if we have Case: 1 mentioned at the beginning of my post, the PHOTOS state will try to use an invalid access_token to try and consume a resource on my back end BEFORE the isAuthenticated method is able to get a new access_token using the refresh_token.
Now I was able to avoid the above issue by using a resolve on EVERY state which handled using the isAuthenticated method to check the access_token and get a new one if need be BEFORE consuming a resource. BUT that felt horribly unDRY. I apologize for the length of this post but I wanted to make sure you guys knew everything that was going on and what I was trying to accomplish.
I appreciate any feedback, criticism and instruction! Thanks guys.
I'm doing a simple SPA where I am using Sails.JS for a REST API and AngularJS for my frontend.
I'm currently having some struggles with figuring out how I should handle the sessions when combining these two.
Feel free to give me some pointers if I'm going about this the wrong way.
--
Here is part of my login function. When a successfull login happens I return the user object along with a session to my client.
User.js
if(user) {
bcrypt.compare(userObj.password, user.encryptedPassword, function(err, match) {
if(err) {
res.json({rspMessage: 'Server error'}, 500);
}
if(match) {
req.session.user = user;
res.json(req.session.user); // return user data and session.
/* This returns something like this
{ cookie:
{ path: '/',
_expires: null,
originalMaxAge: null,
httpOnly: true },
user: {
username: 'admin',
id: '549f2ad213c64d3b2f3b9777'}
}
*/
}
});
}
loginService
Here is my loginService which doesn't really do much right now. I figured this is the place to keep track of the session. I'm just not sure how to go about this... There aren't many tutorials about combining Sails + AngularJS.
MyApp.factory('loginService', ['$cookieStore', '$http', '$rootScope', function($cookieStore, $http, $rootScope){
var _user = {};
return {
login: function(credentials) {
return $http.post('/user/login', credentials)
.then(function(result) {
return result.data;
});
}
}
}])
I want to check the session against my backend somehow and see if its valid or if it has expired. If the session is still valid, the user will be kept logged in even if the user closes his browser/refresh.
Suggestions, links.. anything helpful is appreciated.
Here's some tips I can give you :
Since Sails v0.10, you can use custom responses (doc page) which is a better practice than using
res.status(...);
res.json(...);
The session cookie you are creating with Sails is saved server-side. Maybe you can create a url (e.g. GET /me) to know if this session is still valid. Your Angular app would make a request to this url each time the page is loaded (in a run block I would suggest) to know if the user is still logged in server-side.
Do not hesitate if you need more precision.
I follow this tutorial to create login using StrongLoop:
http://docs.strongloop.com/display/DOC/AngularJS+JavaScript+SDK
Somehow I get this kind of error message on console browser:
TypeError: Object function Resource(value){
shallowClearAndCopy(value || {}, this);
} has no method 'login'
Is login method for user model? Or by another model like customer/agent? So, if you want to use login method on customer/agent model you must use model extend user. http://docs.strongloop.com/display/LB/Model+definition+reference#Modeldefinitionreference-Extendingamodel
Can you confirm you have generated a lb-services.js file that contains a User factory with the login method?
You should see something like the following:
"login": {
url: urlBase + "/users/login",
method: "POST",
interceptor: {
response: function(response) {
var accessToken = response.data;
LoopBackAuth.currentUserId = accessToken.userId;
LoopBackAuth.accessTokenId = accessToken.id;
LoopBackAuth.rememberMe = response.config.params.rememberMe !== false;
LoopBackAuth.save();
return response.resource;
}
}
},
Can you confirm that? If you see this code is in the lb-services file then you should check and confirm you are includinging it in your app correctly.
The problem might be, that you have no User model.
Also, can you provide 2 pieces of code? the code, which calls login() and the code from lb-services.js, which describes it