Methods of saving user info in AngularJS - angularjs

I want to know about the ways of saving user info.
Many seniors have recommended using $cookieStore, or Authentication or etc.
But how about using $rootScope?
My idea is when user has logged in, saving his/her id and password into $rootScope.
(Naming like $rootScope.user_id = 'stupid';)
Is this dangerous way?
I don't know whether this question is duplicated or not, but I couldn't find one talking about using $rootScope.
.
.
UPDATE
My config is like below.
'root controller' can see every scopes, so even if I refreshed pages,
$rootScope value does not disappear.
$stateProvider
.state('root.login',{
url: '/login',
controller: 'LoginCtrl',
templateUrl: 'views/login.html'
})
.state('root.signup',{
url: '/signup',
controller: 'LoginCtrl',
templateUrl: 'views/signup.html'
})
.state('root.main',{
url: '/main',
controller: 'MainCtrl',
templateUrl: 'views/main.html',
})

Its very bad way to store raw user credential in rootScope or cookies. However you can archive this by using userToken or session given by server side.
Example for userToken
send user login req to backend server
server return response userToken
angularjs store userToken in cookies
everytime angularjs req to backend, must append with this userToken(usually put in header)
Example for session
send user login req to backend server
server return result (as backend server will create session on http in server itself)
angularjs can send req to backend normally ( backend will validate whether session is valid or not to accept the req)
so if user refresh the page or switch the page you can call backend server to validate the userToken or session.

$rootScope will be vulnerable if you are storing sensitive data,instead use localstorage for storing user credential with encryption using some encryption algorithm and key and as mentioned above , create service to get and set values.

Related

Adal Infinite redirection + Edge + Trusted sites

Background:
I have a single page app (built using Angular) which uses adal and adal-angular to authenticate against Azure Active Directory.
Have been using version 1.0.7 of adal and adal-angular (tried using 1.0.14 as well but still no luck) and ui-router for routing.
Issue:
Few of our users are getting continuous authentication loop while trying to access the web application on Edge browser specifically.
Note that it works fine with IE, Chrome and Firefox. Surprisingly it also works fine when Edge is opened in InPrivate window.
This issue is device specific, user specific and only occurs in Edge.
Workaround:
When my site is added to the trusted sites (via Control Panel -> Internet Options), the authentication loop issue is resolved and everything works seamlessly.
Any idea why this is happening?
From what I’m assuming as of now is that it’s a cookie issue when adal writes to the auth cookie to the site and Edge can’t seem to read it?
Also any suggestions for a better fix/workaround for this? As I can’t tell all my users to go and add my website to their trusted sites collection.
Code snippet of app.js:
function authenticationInit(adalAuthenticationServiceProvider, $httpProvider, $locationProvider) {
$locationProvider.html5Mode(false);
var endpoints = {
// Map the location of a request to an API to a the identifier of the associated resource
"EndPointKey": window.config.aadEndPointUrl,
"EndPointValue": window.config.aadResouceIdUrl
};
adalAuthenticationServiceProvider.init(
{
instance: window.config.AADAuthenticationInstance,
tenant: window.config.tenant,
clientId: window.config.clientId,
extraQueryParameter: 'nux=1',
endpoints: endpoints
}, $httpProvider);
}
function registerRoutes($stateProvider) {
$stateProvider
.state('home', {
templateUrl: getViewUrl('widgets'),
controller: 'WidgetsController',
controllerAs: 'widget',
url: '/dashboard'
})
.state('terms',
{
templateUrl: getViewUrl('terms'),
controller: 'TermsController',
controllerAs: 'terms',
url: '/terms'
})
}
$rootScope.$on('$locationChangeStart', function (e) {
if (adalAuthenticationService.userInfo.isAuthenticated == false) { // Will be executed during first time login and token expiration
adalAuthenticationService.login();
}
});
$rootScope.$on("adal:loginSuccess", function (e) { // Will be executed after AAD authentication is successful
NavigationFactory.navigateTo('home');
});
Have raised the same query here- https://github.com/AzureAD/azure-activedirectory-library-for-js/issues/537
adal uses localStorage to save the tokens and reads data from it later on (you also have the option to change it to session storage). The point is that if adal is not able to write into local storage, you will not get the tokens. There is a setting in Microsoft Edge that lets the websites store data. To enable this, go to: Settings>Advanced Settings and enable: 'Let sites save protected media license on my device'. I hope this fixes your issue.

Implementing authentication with AngularJS and ui-router

I am trying to deal with authentication with ui-router and angularJS, i would like to achieve this normal scenario where:
if (user is not authenticated && state requires authentication) then
go to 'login' state
else if (user is authenticated && state does not require authentication) then
go to 'main' state
else go to state requested by the user.
i have implemented it in a way i am not sure is correct and i need some validation here from you guys.
I have a resolve function that retrieving the information whether user is authenticated from the server, if it rejected, then I send the user to 'login' state in $stateChangeError. if it resolved I handle the other logic in $stateChangeSuccess.
But as I understand that the information would only be available in $stateChangeSuccess and not in $stateChangeStart , therefore if I implement the logic i wrote above in $stateChangeSucceess then some of the pages will flicker before the transition ends.
Please advise. Is there another way or a way to improve this solution ?. I thought of making a resolve function for each state , check if the user is authenticated and make the routing there.
Thanks.
This is a problem with single page apps. One of the solutions that I use in my angular pages is to cache the userid and the fact that the user is authenticated in local storage. You can add an expiry to this as well. Here's a link to the local storage module: https://github.com/grevory/angular-local-storage (there are others too).
Then in each state you can check to see if the user has already been authenticated rather than going back to the server each time. Also, this will help the back/fwd buttons work better. Typically in your controller you'd have code to check if the user is authenticated (which would probably go and check local storage for a flag and get the userinfo which was initially retrieved from the server).
I can see some security issues with this though if the browser is being shared by multiple users.
This article seems to list a better/newer way to do this: https://auth0.com/blog/2014/01/07/angularjs-authentication-with-cookies-vs-token/
using runfunction in your module combining with a service that knows if the user it's authenticated:
angular
.module('myApp')
.run(runFn);
runFn.$inject = ['$rootScope', 'MyAuthService', '$state'];
function runFn($rootScope, MyAuthService, $state){
$rootScope.$on('$stateChangeSuccess', function(e, toState, toParams, fromState, fromParams) {
var userAuthenticated = MyAuthService.isLogged();
//* check if the user it's present on cookies
//if(!userAuthenticated && $cookieStore.get('user_token'))
// If the token is in the cookies i get the user from server
//else
// $state.go('login')
//your logic here
/*if (user is not authenticated && state requires authentication) then $state.go('login')*/
});
}
This function will be executed always that a state change.

How to stop Angular App on 401 response

Hey im building login system using angularjs. I have one thing which annoys me. For example i have page A with 2 rest request. The first request send some public data - you dont need auth for this, and some private - for current user.
My api check the token - for public data, becouse user always can delete cookies - error response send 401 and angular catch it, and check authience for api/me- similarly send 401. What's the problem? Or what annoying me?
In one page we have two request for api/me to see some private data (private buttons for example) and public data in one page, but when we have got unauth user (probably deleted a cookies) http interceptor catch 2x 401 response error, from api/me and api/public data. How can I solve this problem? Becouse it's doesn't matter how much 401 response we've got. The one 401 response is enough to state that we should logout user.
By the way I was interesting how fb check cookies, they doing it asynchronous becouse when we remove cookie names 'xs' server send request to ajax api then our fb is totally blocked. Where I can learn more about this technique ?
basically the states within ui.router (which is used by professional developers instead of angulars default routing) , can be given a property to determine whether auth is required ...
.state('login', {
url: '/login',
templateUrl: 'routes/login/login.html',
controller: 'LoginController',
controllerAs: 'loginCtrl',
authenticate: false
})
.state('home', {
url: '/home',
templateUrl: 'routes/home/home.html',
controller: 'HomeController',
controllerAs: 'homeCtrl',
authenticate: true
})
then you can use the authenticate property to determine if the state requires auth. on every state change you can make an http call to your isauthenticated api if the state requires auth. if that call returns 401 then call your logout function.
your logout function might clear auth cookies and send the user to the login state.
you can also watch for 401s in your http interceptor and deal with them how you think best.

UI Router and Satellizer force login

I know this question isn't very specific, but I have no idea how to solve this issue or where I should begin..
I'm using Satellizer for authentication with UI-Router. the problem is I have 2 routes /sign_in and /profile the /sign_in issue a request to the server returning the user info (when successful login)... this currentUser info is used all over the application...
the problem is when a user try to go to /profile before login, it renders the empty view... how do I enforce user to login first before accessing these "restricted" views ?!
again I know this isn't a specific question but I really don't know where to start
Have a look into handling the routechangestart event on UI router, I did something similar.
I think this will give you some clues http://arthur.gonigberg.com/2013/06/29/angularjs-role-based-auth/
The key is that you need to create some form of authentication service where you can store the logged in state of the user, and since a service is invoked once (singleton) it is shared across your app (controllers, other services, etc). Then in the routechangestart event handling you can prevent routing to the target page and redirect to login if user is not authenticated.
I found the answer in this Github Repo
the idea is to have role based authentication as discussed in the Repo readme.
so the code for forbidding the unauthorised access to /profile would be something like the following
$stateProvider.state("profile", {
url: "/profile",
templateUrl: "app/profile/profile.html",
controller: "ProfileCtrl",
controllerAs: "user",
data: {
permissions: {
except: ['guest'],
redirectTo: 'sign_in'
}
}
});
given that you defined the guest role
definePermissions = function(Permission, Identity) {
Permission.defineRole('guest', function(stateParams) {
return !Identity.currentUser;
});
};

Angular ui-router using resolve validate authentication

I'm trying to see what's the best way to validate if a user is authenticated into the application.
Right now I'm using the following:
The user log in into the application
On Server Side a Token is created and send it back to the browser
On Log In Success, AngularJS stores the Token: $http.defaults.headers.common['RequestVerificationToken'] = token || $cookies.token;
On every http call to the server the Token is sent and is verified server side, in case the token doesn't exist then a 401 response status is sent to client.
This is working pretty well, now Im using UI-Router to control application states (pages - real scenario):
I have the following state:
$stateProvider
.state('personinfo', {
url: "/personinfo",
controller: 'PersonController',
templateUrl: "app/partials/personinfo.html"
})
Inside my PersonContoller:
app.controller('PersonController', function ($scope,$sce, $location, PersonService) {
$scope.title = 'Person Page';
PersonService.getPersons().success(function (response) {
$scope.persons = response.success;
}).error(function () {
// If token doesn't exist, a 401 reponse status is sent by server
$location.url('/login');
});
});
I don't really like how it works because AngularJS will load the state and download the partial HTML file and then it will go into the controller and execute the get method and if the token is not valid then it will redirect to login state.
I would like to validate the token before the state is being loaded, so if the token is not valid then the partial HTML won't be downloaded or whatever.
I have read that UI-Router has a resolve property that can be used to get data before the view is loaded... can I use the resolve to validate the Token?
Hope someone can give me a guide or advice.
Thanks a lot.
Your build stack should compile production JS with template embedded, so there
is no round trip to worry about.
If you really want to intercept the initial page load, experiment with
$locationChangeSuccess, which is fired before the first $routeChangeStart.
If you want to hook into resolve, just attach a promise to it.

Resources