authorisation and login control in an Angular app - angularjs

So for the past few months I have been developing the 'login functionality' of my Angular apps like this. The user logs in and if the credentials are correct, the REST API returns a token. I take that token and store it as a cookie:
$cookies.put('authorisation', data['token']);
Whenever I call the $http service, I submit the authorisation cookie as a header and it authorises the http request. Then on the controller of each view I add:
if (!$cookies.get('authorisation')) {
$location.path('/login');
}
So if the cookie doesn't exist, the user is automatically kicked to the login screen.
This has worked for me just fine up until now but I can't help but feel that it is not the 'correct' way of doing things. Could anyone shed a little light on what the best practice method for this could be? And perhaps why what I'm doing is 'wrong'?

Are you familiar with Angular $http Interceptors:
https://docs.angularjs.org/api/ng/service/$http#interceptors
You could use the request interceptor to have your authorization checked before each $http request.
If you do this you also have to integrate a custom Flag on each $http config object (e.g. skipAuthorization) in order to allow the user to perform Requests without being logged in (useful for actually logging in ;-))
#AzzyDude to your comment:
I'm using ui-router to do the navigation inside of my Angular 1.6.X Application.
You can either integrate own config-properties on the states (isGuestState) or if its a closed application such as mine, hard-coded in a $stateChange event, like this:

Related

Angular API authentication by sessions

I have a API server that have a POST method to login user and it stores the logged in status in session. Then after success login I have available method to get the current user information. It works well in Postman but in Angular application the second method returns that I'm not logged in. I tried with $http withCredentials flag and with angular service $cookieStore but it's still not working.
I don't know exactly how to deal with it. I don't know what should be set or stored to properly handle APIs session. Can you give me some examples?

Laravel 5 Middleware with angular routes

I'm using Laravel 5 with AngularJS for a project, in a way so that Laravel is used as an API and the API routes are in Laravel, while the client side routes are in AngularJS (app.js).
Is it possible to use Laravel Middleware to protect AngularJS routes, so for example, I want it to use the RedirectIfAuthenticated Middleware on the angular login form page route so people can't go to that page if they are logged in, except normally as far as I know, the middleware is specified in the Laravel controller, which doesn't have logic for angular side routes - hence, the problem.
So the question is, can I use Middleware or do I have to make angular send a get request asking laravel if the user is logged in on every page? Wouldn't that be less secure?
What I ended up doing was making a client-side cookie on login in angular to keep track of whether the user is logged in or not for user experience purposes (hiding information, redirecting before the view is rendered), and using Laravel Middleware to protect API calls to make sure the user can't interact or get information from the API on the server and to keep it secure in case the user changes their cookie to lie about their login status.
Alternatively, you could also send a request to the server before each page loads instead of the cookie check, but that adds quite a bit more overhead, and isn't any more secure - as far as I know, since that API call to check if the user is logged in is just for UX purposes too and the javascript for that can be removed by a malicious user.

PayPal express checkout from Angular app?

I am trying to complete a PayPal payment from an Angular app, using PayPal's classic express checkout API. In this checkout flow, I obtain a URL to send the buyer to in order to authorize their payment on PayPal's site. When I request that URL, PayPal returns a 302 response and attempts to redirect the buyer. However, when the browser attempts to redirect, I understandably get this error:
XMLHttpRequest cannot load 'PAYPAL_SITE'. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'MY_HOST' is therefore not allowed access.
What is the best way to deal with this? I have seen that PayPal also has a newer, RESTful API. If this API supports CORS, would switching to that solve the problem? Is there something I should change in my Angular configuration? From what I have read it seems like the PayPal server need certain headers to allow my host access, but I'm not too sure...
The way I solved this was to send the user away from the angular app to a "dummy" page, which just immediately made an (non-XML) HTTP request to the PayPal site. I passed the data I needed as params in the URL.
In your js:
window.location.href = "dummypage.html" + build_params();
Assuming you are using some sort of MVC framework, in your controller:
index() {
paypalUrl = getParams(paypalUrl);
redirect_to(paypalUrl);
}
When the user is confirming the payment they are redirected back to the angular app to complete the transaction. I don't believe this is an optimal solution, and it feels pretty messy to use, but I haven't come up with anything better yet!

Adding http headers to window.location.href in Angular app

I have a angular app that I needed to redirect outside to a non angular html page, so I thought I could just use the $window.location.hrefto redirect the angular app to my external site. This actually works fine, however, I have a nodejs/express backend that checks for auth token before serving up any content(even static content).
This requires a auth token to be sent in the header of the http request. Now the question:
Can/How do you add an auth token to the request that is made by changing the $window.location.href before it is sent off?
When you use $window.location.href the browser is making the HTTP request and not your JavaScript code. Therefore, you cannot add a custom header like Authorization with your token value.
You could add a cookie via JavaScript and put your auth token there. The cookies will automatically be sent from the browser. However, you will want to review the security implications of using a cookie vs. a header. Since both are accessible via JavaScript, there is no additional attack vector there. Unless you remove the cookie after the new page loads, there may be a CSRF exploit available.
This answer is NOT a safe way, as the token is exposed in the URL, which is logged in browser history, access logs, etc. Use a domain cookie instead. I'll leave the answer as it can be an easy way to debug in your local setup.
I am using JWT as authentication on a Laravel PHP backend, and it works by putting ?token=... in the URL. For example, when using AngularJS with satellizer plug-in, I add ?token=' + $auth.getToken() to the URL.

When is angularjs cookieStore updated with new cookie?

I am currently implementing login functionality in my app. I use AngularJS and $cookieStore. I get a cookie from the server when I make an ajax request to authenticate the user. I want to use this cookie in success() to set up the user in my Auth services. I use chrome developer tools to pause right after I ask for the cookie like this:
var cookieUser = $cookieStore.get('user');
but it turns out to be undefined, but a chrome watch on unescape(document.cookie) shows a cookie "user" is set.
If I run the request twice: $cookieStore.get('user') returns the previous cookie.
Why is $cookieStore not updated with the cookie I just received?
AngularJS' uses an asynchronous $watch callback to write cookies. So you either need to wrap your cookie reading inside a $timeout, or access the data without $cookieStore.get.
I had a similar problem.
After the login was successful in my appplication I had ,of course, to transition to a state 'main.index' and in its resolve object I wasn't able to get the authentication cookie with $cookies object(angular), but I was able to see it in document.cookie.
I think $cookies are refreshed a tiny bit latter than the $.cookie that #swenedo mentioned.
Using $.cookie from jquery worked for me.

Resources