Angular ui-router using resolve validate authentication - angularjs

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.

Related

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.

Authentication Logic - Server vs Client

I'm trying to get my head around where authentication logic should live in my application, the approach I am trying to take is to have any auth responsibility handled by the server, redirecting to a login page that's separate from the main client side app - which I think is sensible?
I have an angularjs application which uses ui-router and makes api requests which are routed via the server.
I am using an Express server which is configured to use a couple of directories like so:
app.use(express.static('./dist/client'));
app.use(express.static('public'));
I then have middleware that performs an auth check (Im using express-session as well) and redirecting to login when required.
//A request to '/login' will serve the login page
app.use('/login', function(req, res){
res.sendFile(path.join(__dirname+'/public/login.html'))
});
//This will listen for all requests
app.use(function(req, res, next) {
if (req.url!== '/auth/login' && !req.session.accessToken) {
res.redirect('/login');
return;
}
next();
});
On initial page load, when no session cookie exists, express immediately redirects to the login view as expected.
After logon, and the main application loads, if I then manually delete the cookie in the browser and perform a state change that requires an api request (in a state resolve), the server returns the login view but this gets rendered inside the ui-view component being used by ui-router, rather than a full redirect to /login by the server.
Also, if I navigate to a page (after deleting cookie) that does not perform an api request, that page is served back, I guess as its not covered by my app.use middleware that does the redirect.
I feel I'm missing something obvious here, can someone help me please?
One way to handle this, there are others:
Make the API server return a 401 (unauthorized) error if the user is not authenticated, rather than redirecting them to the login page.
Then, in a run block, add a $stateChangeError event handler to the $rootScope. This way, if an API request is made from an unauthenticated user, it will trigger the event handler. From there you can redirect the user to your login page:
angular.module('myApp').run(function($rootScope, $window) {
$rootScope.$on('$stateChangeError', function() {
$window.location.href = '/login';
});
});
I'm not sure if it makes sense to worry about the other scenario where you delete the cookie and navigate to a page that does not make any API requests. What is such a user going to gain? In this hypothetical scenario, they are already looking at a page in your app (that might have sensitive data or not). How did they get there to begin with?
You could use a similar event handler for the $stateChangeStart event that checks for the presence of the cookie and redirect if it's missing. But, you don't want to put code in your client that validates the cookie, b/c then any curious visitor could read that code and learn how to create a cookie to fool your server.

Getting external Token into my Angular application

My http server framework is serving a static (Angular) SPA.
To authenticate users, they will need to enter their email adress and submit it. They receive a link per email in the form of https://www.somedomain.com/?token=123456789 (inspired by passwordless.net). For later accesses, the token will be stored with localStorage.
My problem is: I have no solid idea how the SPA can learn about that token. Of course, the user may copy&paste that token. Or I can embed that token within the served HTML, but I don't see that being very elegant or even fast, and possible not very secure either.
Is there a simple way to do this I'm missing?
If you are using '$location', then you can simply parse the '$location.url()' and get the token.
If you are using the '$routeProvider', then you can define the routeProvider configuration like this:
$routeProvider.when('/reset_password/:token', { /*controller and template conf here*/ })
And in your controller:
var theToken = $routeParams.token;

Angular basic authentication and token

I'm getting crazy to understand how to handle a basic authentication with an API.
Basically what I need to do is to request a token from an API sending a module-username and module-password (not a user login). The server should return a token that I will need to use for all other request I will make to the server.
Looking on internet I've found solution that involves user logins and angular routing.
I'm not using any routing, the routing is managed server side and I need to consume the API on few pages, before consuming I need to attach the token to every request.
I don't understand exactly how to start properly.
I should need to create an ajax request for the first authentication, save the token somewhere and use it for all other requestes. Keeping in mind that if the token is not valid I should request it again.
I'm quite confused on how to do it, I can not find any good tutorial.
Any help?
I'm still learning Angular myself, but hopefully this basic example helps you. You can use $cookies to save and retrieve a token that is sent back from your server. Then, assuming you are using $http or $resource, you can use an $httpProvider interceptors to add the current token value (retrieved from $cookies) to the header of every outgoing request your app makes.
Here's a simple example of how you might create an $httpProvider interceptor:
authServices.factory('sendTokenInHeader', ['$cookies', function($cookies) {
return {
request: function(config) {
var token = $cookies.getObject('x-my-token');
if(token) {
var updateHeaders = config.headers || {};
updateHeaders['x-my-token'] = token;
config.headers = updateHeaders;
}
return config;
}
};
}]);
Then in your app.config you need to just push this interceptor and now any outgoing $http/$resource request will include the current token!
myApp.config(['$httpProvider', function($httpProvider) {
// do other stuff...
$httpProvider.interceptors.push('sendTokenInHeaders');
}]);

HTTP post with angular on a "before auth" laravel route

I authenticate my user only through laravel, so angular does not know about it. But I need to do a $http.post on a "before auth" route with angular in order to get some profil info:
laravel route.php
Route::post('profile', array('before' => 'auth', function()
{
// Only authenticated users may enter...
}));
angular app.js
$http.post("/profile").success(function (data) {
$scope.profile = data;
});
For now I get an internal server error (500) with a "Illuminate\Session\TokenMismatchException" because laravel think I'm not logged in.
Could someone help me out with this?
Thanks in advance :)
My mistake, it was a csrf filter that was causing this error, not the auth filter...
For reference to my question:
AJAX Requests are identical with regular requests in regards to session data. Anything that depends on Session or Auth will work with an AJAX call.
link to thread

Resources