CSRF Tokens and Angular.js

Posted: 2014-10-15 18:35:54

This is key to preventing Cross-site request forgery. Basically you log in and do some work on one site, then go to a malicious site and now they can send POST requests to the sites you have authentication to. But by passing a token we can prevent that issue.

The steps

  • Make a token path
  • Make a token service to use again and again in Angular.js
  • Add it as a resolve to the route in Angular.js
  • Add it to your forms

Make a token path

In this case it is Laravel and I just add this route (in a Controller or route.php same idea)

    /**
     * @Get("auth/token")
     */
    public function getToken()
    {
        return csrf_token();
    }

Make your Angular Service and inject it into the Controller

Service in this case is

(function(){
    'use strict';

    function TokenService($http)
    {
        return {
            get: get
        };

        ////
        function get() {
            return $http.get('auth/token').then(
                success,
                fail
            );
        }

        function success(response) {
            return response;
        }

        function fail(response) {
            return response;
        }
    }

    angular
        .module('app')
        .factory('TokenService', TokenService);
})();

The ui router passes it in on this POST related route

            .state('projects_create', {
                url: '/projects/create',
                views: {
                    '': {
                        templateUrl: 'assets/js/projects/templates/projects.edit.html',
                        resolve: {
                            project: ['ProjectsService', function(ProjectsService){
                                return ProjectsService.create();
                            }],
                            token: ['TokenService', function(TokenService) {
                                return TokenService.get();
                            }]
                        },
                        controller: 'ProjectsCreateCtrl',
                        controllerAs: 'vm'
                    }
                }
            })

Since it is a promise and in the resolve we get the benefits of not loading the page till this is done loading. A nice addition here could be getting is current_user info etc.

Add it to your Angular Controller

    function ProjectsCreateCtrl(project, token, ProjectHelpers, $window, Noty)
    {
        var vm                  = this;
        vm.token                = token.data;

Later, using Restangular, during the post I add it to the payload. So when the user clicks Create Project they trigger this.

function saveProject()
        {
            vm.rest.route = 'api/v1/projects';
            vm.rest._token  = vm.token;
            vm.rest.post()
                .then(function(response) {
                    vm.success(response);
                }, function(response){
                    vm.fail(response);
                });
        }

That is it. You can see it in the form

form

And you can remove it to show the form fail.

You can also see it in the payload we are posting.

post