Creating an AngularJS application with user authentication

Creating an authentication system within a Single Page App (SAP) can be a bit tricky; hopefully this post will help alleviate some of the challenges. Before you begin, it's a good idea to set up your environment so as to decouple the front and backends. There's a good post explaining the process over at StackOverflow. (The StackOverflow answer deals with a Laravel backend, but the code is easily modified for any other backend service.)

Our application will be structured as follows:

[code]auth_demo/ - application root auth_demo/backend/ - backend (PHP app) root auth_demo/frontend/ - frontend (AngularJS app) root auth_demo/frontend/index.html - AngularJS index auth_demo/frontend/js/ - JavaScript libraries auth_demo/frontend/js/app/app.js - core AngularJS application auth_demo/frontend/js/app/controllers/ - AngularJS controllers auth_demo/frontend/js/app/directives/ - AngularJS directives auth_demo/frontend/js/app/partials/ - AngularJS partials auth_demo/frontend/js/app/services - AngularJS services [/code]

Let's start with our basic index.html setup:

Auth Demo
?>

There are a few things going on here... First, we declare this DOM as an AngularJS app named "auth_demo." Second, we create a [code]user-info[/code] DIV (which will only be shown when the [code]ng-show[/code] directive's expression evaluates to [code]true[/code]), bind the [code]user_email[/code] variable, and provide a logout link which will trigger the [code]logout()[/code] function on click. Finally, we use the [code]ng-view[/code] directive to display the content for our menu route, and then load the various JavaScript files required by our app.

Now we can create our basic App (in app.js), routing a few paths to appropriate controllers and partials:

Note that we declare [code]ngRoute[/code] as a dependency for our App, and use the [code]resolve[/code] object property to map dependencies that will be injected into the controller. Our [code]isAnon[/code] and [code]isAuth[/code] dependencies will be promises, and Angular's router will wait for them to be resolved or rejected before instantiating the controller. This means we can use them as a sort of "filter" to control access to our routes.

Now we will create the [code]isAuth[/code] and [code]isAnon[/code] promises:

Both of the promises perform a [code]GET[/code] request against [code]/ws/api/v1/auth[/code] and work with the returned JSON. Our example backend will return a JSON object which will contain a string [code]status[/code] property (set to either [code]ok[/code] or [code]error[/code]), a boolean [code]auth[/code] property (current authentication state), and a string [code]user_email[/code] property. Depending on the values in returned JSON, the promises will either resolve or reject.

Now that the promises are set up (and the backend is returning the appropriate JSON response) we can create the login form in partials/login.html:

Login

?>

This form creates two textfields, binds their values to a [code]form_data[/code] object, and calls the [code]process()[/code] function upon form submission.

Next up is the the [code]loginController[/code] we refenced in our route provider. Declare it in controllers/loginController.js, and don't forget to load the file in your [code]index.html[/code]:

[code][/code]

You'll note that the controller uses a (so far undefined) service called authService. Let's create it in services/authService.js: