I'm working with angular.js and ngstore. I'm using a token based authentication with a node.js REST service, from the angular app I send my credentials to rest server and I receive the token, I then store this token in $localStorage to use throughout all the angular app($localStorage.token). But it turns that sometimes $localStorage.token is undefined, even when I assigned the token to it, so when I call another rest endpoint sending the token in the headers, I'm actually sending an undefined value. Also when I try to logout I do
delete $localStorage.token
but when I check if the user has been loggedout actually the token still there.
What is strange is that if I set breakpoints right after deleting the token or assigning the token and wait for a while, everything works, that's making me think that those operations may be asynchronous?
Is this a common problem? How could I fix this?
Any help would appreciated, Thanks.
EDIT: actually I found that the problem is when using window.location, if I use $location.path it's working, but for certain reasons I need to use window.location, and it should work as far as I know
I had the same problem today, and using the following commit worked for me.
https://github.com/raynode/ngStorage
There is a helpful discussion about this problem here:
https://github.com/gsklee/ngStorage/issues/39
In this version of ngStorage, the author has thoughtfully provided a way to "save" before proceeding and performing a $window.location.reload();
During login:
$localStorage.value = 100;
$localStorage.$save();
(and then)
$window.location.reload();
During logout:
delete $localStorage.value;
$localStorage.$save();
$window.location.reload();
This worked for me to ensure that the $localStorage variables were deleted before page reload.
No, local storage is not asynchronous.
JavaScript is a single thread environment and read/write operations to local storage occurs immediately.
Both session and local storage containers are the same. Except that session storage is a key/value pair with an expire timestamp specified.
Storage in HTML5 is not a reliable resource. As there are a number of browser states that will restrict or remove storage.
You are referring to ngStore which is a module I've never heard of. There is no local storage module that is included with AngularJS by default, and there are multiple open source modules that handle this.
What is most likely happening is that you are handling a session token as a state variable instead of a state promise. When you use a variable to hold the state of a resource on the server, then that state has 3 possible values. 1 not assigned, 2 pending assignment and 3 value assigned.
Instead of reading the token from storage directly. You should have a service that returns a promise that will resolve to provide that token. This promise will only resolve after the REST operation has completed.
Related
I'm running into some problems when I attempt to refresh my session tokens, (Access, Id, Refresh). I have already read this question and the answer has helped me understand what is going on some. But I feel what I am trying to do isn't quite what getSession is for.
I am attempting to implement a session expiration message (done) that allows the user to extend their session (refreshes the tokens). From what I gather about getSession(), it returns either the old tokens, if they are still valid, or new tokens if they are not valid. Please correct me if I am wrong there.
I am attempting to give the user new/refreshed tokens every time they click on extend session. For dev purposes, I have a button which then displays the message with the extend session button. The tokens I receive when I call getSession() are the old ones, but I want them to be new ones.
So basically, nullifying the old session and giving them a new one.
My questions are:
Am I missing some understanding about getSession(), as previously mentioned?
Can I give the user new session tokens (Access, Id, Refresh)?
Can I do #2 without having the user sign in again?
Thank you.
EDIT 1:
It may help to know that I am not using any Federated Identities.
You can call cognitoUser.refreshSession. I've found a reasonable example for you over here:
Sample code: how to refresh session of Cognito User Pools with Node.js and Express
Look for the method called checkTokenExpiration, it explains perfectly well what you have to do to refresh the session.
I'd like to store a token on the client but am worried about malicious attacks on the clients browser.
What's the best way to store this variable during the session?
Here is my implication so far:
Create an isolated scope in the 'HeadersInterceptor' function so only that function can access it.
What's the best way to store this variable on client storage?
Here is my implication so far:
Localstorage...
I do feel like I'm going in the right direction here, but I'm stumped on storing this variable for the client. Any insights would greatly be appreciated!
You can't.
Anything that's accessible from your JS app is accessible from the developer console too, that's just the nature of client-side scripting.
Hiding it in a private variable or a service, as other answers suggest, are nothing more than obfuscation - it'll make it more of a nuisance to get, but it's there and available nonetheless.
Even if you find a method which makes it directly inaccessible from the developer console, per se, a malicious user will still be able to just modify the JS files themselves - it's a losing battle.
My thoughts on this:
What's the best way to store this variable during the session?
sessionStorage
What's the best way to store this variable on client storage?
sessionStorage
But if you don't want it accessible at all, even from the console (sessionStorage and localStorage are accessible from the console), I would think you should forgo storing it in LS and simply hold a reference in memory. Keep the token wrapped in privately in a closure and access it via a service. Like so:
app.factory('tokenSvc', function(){
var token;
return {
setToken: function(_token) {
token = _token;
},
getToken: function() {
return token;
}
};
});
Because Angular is a SPA framework, that token reference will persist as long as your application is active. So maybe you would set the token in your $http interceptor function, and then access it as need via getToken.
In my local route http://localhost:9000/#/deviceDetail/ I have a controller that manage that view. Before going to that view I set some variables to the $rootScope (for example $rootScope.dashboards).
Once on that view I have acces to dashboards property, but when I refresh the page with F5 key for example the property dashboards is lost.
I tried to save the $rootScope on the localStorage variable but I got circular reference problems with the JSON.stringify method.
Any tip to manage that?
AngularJS is a JavaScript framework, everything is stored in memory heap and the heap is starts when you open a page and it's destroyed after you close it. In this context, browser refresh is like closing and re-opening the page.
To keep the value after refresh, you should store it in a cookie, for this you use for example $cookies or sessionStorage / localStorage as recommended by M K.
I tried to store auth token using cookies following the article at Getting started with AngularJS and ASP.NET MVC - The long awaited Part Three. But the cookies is destroyed whenever I hit F5 or refresh the Chrome browser.
That article says ngCookies helps to deal with page refresh to maintain token for page refresh. And I had thought it did and I did not know ngCookies killed me. It was destroyed if page is refresh! after hours to research online I see this article helps me.
According to M K, I used localStorage (or sessionStorage) helped me to get rid of the headache of cookies. Using cookies to store authentication token or something else is a bad idea. I ran into that problem and I got lost (did not know the bug coming from "using cookies") as the above article mentioned/confirmed. So, it was a bug in that article.
Thank you million times, M K.
Use localStorage and $stateChangerStart check if you using ui.route
something like this
$rootScope.$on('$stateChangeStart', function(event, toState) {
// Grab the user from local storage and parse it to an object
var user = JSON.parse(localStorage.getItem('user'));
if(user) {
$rootScope.currentUser = user;
}
});
I have a very simple node.js app built on express which has been handling authentication using a session memory store. Basically a user logs in by:
app.post('/sessions', function(req, res) {
// check username/password and if valid set authenticated to true
if (authenticated){
req.session.user = req.body.username;
} ...
});
Then in each call from the browser a requiresLogin middleware function is called which checks to see if that user property on the session has been set.
I'm now transitioning the app to basically just provide a service that may or may not be consumed in the browser, so instead of using cookies/sessions, I'm considering changing the system so that one would post to /getToken (instead of /sessions) which would return a temporary random token associated with a user's account that could then be used for a period of time to access the service. Using the service would then require a valid token to be included in each call. (I assume this would be better than passing the username/password each time so that the password would not have to be stored in memory on the client's computer after the call to get token?)
Would such a system basically be just as secure as the above current system or Is there a much more standard/safe way to handle this? What's the standard way to handle something like this?
Thanks in advance for you help!
What you are looking for is called an HMAC and there is a great article here to get ideas on how to implement for your service.
As to whether session based security is more secure than public/private keypairs is widely debated and really depends on the implementation/application. In your case, since you want per request authentication on a public facing API, the HMAC is the way to go.
I've been reading about CSRF and XSS vulnerabilities for a few days now, and trying to come up with a solution that's 1) easy to implement and use, 2) uses Javascript to do a lot of heavy lifting, and 3) makes it virtually impossible to perform a CSRF attack against.
I haven't seen a solution like the one I'm about to describe. I'm hoping this doesn't mean that it's leaky.
I've come up with the following solution, based on my knowledge of AJAX and JS. This code assumes the user has passed through a login screen, and a session variable has been set on the server and in a cookie, with the same values.
It's easier to paste the code in and document it, rather than explain what it's doing. This code would be run in the page the user sees immediately after logging in:
<script>
// this is the constructor:
function Controller(){
//the following 2 variables are private, and inaccessible via JS calls
var secretToken; //this holds the session token, but cannot be read by the browser
//returns the session token from the server
var x = new ajaxObject('AJAX/retrieve_session_cookie.lasso');
x.callback = function(responseText, responseStatus){
secretToken = responseText;
}
//this is a private function, again inaccessible via JS calls
function getCookie(){
x.update();
}
//the following 2 functions are publicly accessible
//just a test function to ensure that secretToken is invisible
this.tell = function(){
alert(secretToken);
}
//privileged function that calls a private function, to load the token into a private variable
this.initialize = function(){
getCookie();
}
}
E = new Controller();
E.initialize();
</script>
The variable secretToken can't be read by the user, as it's a private member variable of the controller object.
In retrieve_session_cookie.lasso, I'm checking for a valid session, and matching the session variable with the browser's cookie. If both these conditions are met, the session variable is returned in plain text, where it's set as secretToken in the object E. By double-checking to see if the cookie matches the session token, I would hope that it would be impossible obtain the session token via CSRF, as it can't forge a cookie. Typing in 'AJAX/retrieve_session_cookie.lasso' would return nothing, unless it was typed in by the user while in a valid session, and from the user's computer only.
Also, now that my controller has local access to the session token, I could 'burn in' the session token with every AJAX request, so I don't even have to think about it passing a token anymore, each time an AJAX file is requested. All the AJAX objects and requests would be initialized as private members in the controller object's constructor, so nobody could access / modify the callback functions to disclose the session token.
Passing the session token with every AJAX call would protect every other AJAX file, as they would all perform the same check for the cookie matching the session token before returning any data. And, in my programming, there would be one less variable to worry about.
If I were to move ahead with a controller implemented this way, would there be ANY way for the token to be accessed / exploited, either by the user or a malicious coder via CSRF?
First of all it is trivial for a user to obtain your token and for CSRF this doesn't matter at all. Anything you transfer to the user can be intercepted, anything being sent from javascript can be tampered with. Cookies are always easy to replay (Who cares about forging them? Its just a random number.), and this doesn't matter as long as you use HTTPS. To be honest I don't think that this security system addresses CSRF at all, in fact I'm not sure what you are trying to protect against. It doesn't matter where your .lasso files are or what they contain.
What matters is the GET and POST requests can be forged. The whole point of having a CSRF token is that a 3rd party can't create an exact GET/POST request without knowing somthing about the site(and a simple token written as a hidden value works because of Same-Origin Policy). Don't roll your own security system, pick a solution off of the Cross-Site Request Forgery Cheat Sheet.