Secure AngularJs application with Spring Security

Most of JEE developers are aware of web applications security requirements and are familiar with security frameworks like Spring-Security.

But when we have to secure a web application based on front-end framework like AngularJs, we will have to deal with some specific features and we will need to customize the server-side configuration.

For example, some commonly used features like Spring-Security taglib can’t be used because page is rendered client-side.

Photo credit: SLO Icon Design
In this post, I will present a sample project to deal with some common security features in an AngularJs project.
You can get project source code on GitHub here and you can run the application here.


1 – Back-end security management

This parts provides instructions on how to add Spring Security to an existing application using Spring java based config.

1.1 – Back-end dependencies

In order to use Spring Security you must add the necessary dependencies. For the sample we will add the following Spring Security dependencies:

      <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
            <version>4.0.3.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>4.0.3.RELEASE</version>
        </dependency>

1.2 – Spring security config

In this step, we create a Spring Security configuration.

@EnableWebSecurity
@Configuration
@ComponentScan(basePackages = {"com.mycompany.myproject.security"})
public class SecurityConfig extends WebSecurityConfigurerAdapter {

 public static final String REMEMBER_ME_KEY = "rememberme_key";

 @Autowired
 private RestUnauthorizedEntryPoint restAuthenticationEntryPoint;

 // Autowire other required beans 

 @Autowired
 public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
  auth.userDetailsService(userDetailsService);
 }

 @Override
 public void configure(WebSecurity web) throws Exception {
  web.ignoring().antMatchers("/resources/**", "/index.html", "/login.html",
   "/partials/**", "/", "/error/**");
 }

 @Override
 protected void configure(HttpSecurity http) throws Exception {
  http
   .headers().disable()
   .csrf().disable()
   .authorizeRequests()
    .antMatchers("/v2/api-docs").hasAnyAuthority("admin")
    .antMatchers("/users/**").hasAnyAuthority("admin")
    .anyRequest().authenticated()
    .and()
   .exceptionHandling()
    .authenticationEntryPoint(restAuthenticationEntryPoint)
    .accessDeniedHandler(restAccessDeniedHandler)
    .and()
   .formLogin()
    .loginProcessingUrl("/authenticate")
    .successHandler(restAuthenticationSuccessHandler)
    .failureHandler(restAuthenticationFailureHandler)
    .usernameParameter("username")
    .passwordParameter("password")
    .permitAll()
    .and()
   .logout()
    .logoutUrl("/logout")
    .logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler())
    .deleteCookies("JSESSIONID")
    .permitAll()
    .and()
   .rememberMe()
    .rememberMeServices(rememberMeServices)
    .key(REMEMBER_ME_KEY)
    .and();
 }
}

1.2.1 – Authentication config

Authentication entry point
We need a custom authenticationEntryPoint because default Spring-Security config will redirect to login page. In our case we need just a https status 401 and a json response.

@Component
public class RestUnauthorizedEntryPoint implements AuthenticationEntryPoint {

 @Override
 public void commence(HttpServletRequest request, HttpServletResponse response,
  AuthenticationException exception) throws IOException, ServletException {
  SecurityUtils.sendError(response, exception, HttpServletResponse.SC_UNAUTHORIZED,
   "Authentication failed");
 }
}

Login success handler
The login success handler returns http status 200 with user info in json format.

@Component
public class RestAuthenticationSuccessHandler 
extends SimpleUrlAuthenticationSuccessHandler {

 @Autowired
 private UserRepo userService;

 @Override
 public void onAuthenticationSuccess(HttpServletRequest request, 
  HttpServletResponse response, Authentication authentication)
 throws ServletException, IOException {
  User user = userService.findByLogin(authentication.getName());
  SecurityUtils.sendResponse(response, HttpServletResponse.SC_OK, user);
 }
}

Login fail handler
The login fail handler returns http status 401.

public class RestAuthenticationFailureHandler
extends SimpleUrlAuthenticationFailureHandler {

 @Override
 public void onAuthenticationFailure(HttpServletRequest request,
  HttpServletResponse response, AuthenticationException exception)
 throws IOException, ServletException {
  SecurityUtils.sendError(response, exception, HttpServletResponse.SC_UNAUTHORIZED,
   "Authentication failed");
 }
}

Logout success handler
When logout succeeds, we need to return ok status instead of login page redirection.
Spring security implements logout handler that returns ok status.

org.springframework.security.web.authentication.logout.HttpStatusReturningLogoutSuccessHandler

Account Rest web service
The account Rest web service returns the authenticated user account information if he’s already authenticated.

@RestController
public class SeurityController {

 @Autowired
 private UserRepo userRepo;

 @RequestMapping(value = "/security/account", method = RequestMethod.GET)
 public @ResponseBody
 User getUserAccount() {
  User user = userRepo.findByLogin(SecurityUtils.getCurrentLogin());
  user.setPassword(null);
  return user;
 }

}

1.2.2 – Authorization config

You can manage authorization by specifying authorized roles for each secured URL.

@Configuration
// @other annotations ..
public class SecurityConfig extends WebSecurityConfigurerAdapter {

// extra config code ...

@Override
protected void configure(HttpSecurity http) throws Exception {
  http
    .authorizeRequests()
    .antMatchers("/v2/api-docs").hasAnyAuthority("admin")
    .antMatchers("/users/**").hasAnyAuthority("admin")
    .anyRequest().authenticated()
    .and()
    // others config ...
}

}

Using Spring-Security annotations is another way to manage authorization.

First, we enable method security in the config class

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
// @other annotations ..
public class SecurityConfig extends WebSecurityConfigurerAdapter {
  // config code ... 
}

Next, we add annotation for a method that must have access restriction.

@RestController
public class SeurityController {

    @PreAuthorize("hasAuthority('admin')")
    @RequestMapping(value = "/security/tokens", method = RequestMethod.GET)
    public @ResponseBody
    List<Token> getTokens () {
       // method code ...
    }
}

Access denied handler
The access denied handler returns http status 403.

@Component
public class RestAccessDeniedHandler implements AccessDeniedHandler {

 @Override
 public void handle(HttpServletRequest request, HttpServletResponse response,
  AccessDeniedException exception) throws IOException, ServletException {
  SecurityUtils.sendError(response, exception, HttpServletResponse.SC_FORBIDDEN, 
   "Not authorized resources");
 }
}

2 – Front-end security management

2.1 – Front-end dependencies

If you are using Bower, you need to add to your bower.json file the dependencies in the code bellow.

{
  "name": "example",
  "version": "0.0.1",
  "dependencies": {
    "jquery": "2.1.4",
    "angular": "~1.4",
    "angular-route": "~1.4",
    "angular-resource": "~1.4",
    "angular-sanitize": "~1.4",
    "angular-animate": "~1.4",
    "angular-spinkit": "0.3.3",
    "angular-http-auth": "1.2.2",
    // others dependencies
  }
}

2.2 – AngularJs config

The code source bellow presents the routeProvider configuration.

var myapp = angular
    .module('myApp', ['ngResource', 'ngRoute', 'http-auth-interceptor']);

myapp.config(function ($routeProvider, USER_ROLES) {

    $routeProvider.when("/home", {
        templateUrl: "partials/home.html"      
    }).when('/login', {
        templateUrl: 'partials/login.html',
        controller: 'LoginController'
    }).when("/error/:code", {
        templateUrl: "partials/error.html",
        controller: "ErrorController"
    }).
       // Other routes config ...
       // ......
    }).otherwise({
        redirectTo: '/error/404'
    });
});

2.3 – Authentication management

First, create services.


myapp.service('Session', function () {
    this.create = function (data) {
        this.id = data.id;
        this.login = data.login;
        this.firstName = data.firstName;
        this.lastName = data.familyName;
        this.email = data.email;
        this.userRoles = [];
        angular.forEach(data.authorities, function (value, key) {
            this.push(value.name);
        }, this.userRoles);
    };
    this.invalidate = function () {
        this.id = null;
        this.login = null;
        this.firstName = null;
        this.lastName = null;
        this.email = null;
        this.userRoles = null;
    };
    return this;
});

myapp.service('AuthSharedService', function($rootScope, $http, authService, Session) {
 return {
  login: function(userName, password, rememberMe) {
   var config = {
    params: {
     username: userName,
     password: password,
     rememberme: rememberMe
    },
    ignoreAuthModule: 'ignoreAuthModule'
   };
   $http.post('authenticate', '', config)
    .success(function(data, status, headers, config) {
     authService.loginConfirmed(data);
    }).error(function(data, status, headers, config) {
     $rootScope.authenticationError = true;
     Session.invalidate();
    });
  }
 };
});

Next, write a login controller.

myapp.controller('LoginController', function($rootScope, $scope, AuthSharedService) {
 $scope.rememberMe = true;
 $scope.login = function() {
  $rootScope.authenticationError = false;
  AuthSharedService.login($scope.username, $scope.password, $scope.rememberMe);
 }
});

Finally, create login.html partial page.

<form>
    <div class="form-group"
         ng-class="{'has-error is-focused' : authenticationError}">
        <input id="login" ng-model="username" type="text" class="form-control" 
               required="required" placeholder="login"/>
        <span ng-show="authenticationError" class="help-block">
            Please check your credentials and try again.
        </span>
    </div>

    <div class="form-group">
        <input id="password" ng-model="password" type="password" class="form-control" 
               required="required" placeholder="password"/>
    </div>

    <input type="checkbox" ng-model="rememberMe"/><span> Remember me</span>

    <button ng-click="login()" >Login</button>
</form>

2.4 – Authorization management

In this part, we deal with server-side authorization error and with client-side authorization managing.

2.4.1 Manage server-side authorization

If the requested resource or service isn’t authorized for the authenticated User, the request will fail with response status 403.
The client-side logic must intercept the error and redirect the user to a 403 error page.

myapp.run(function($rootScope, $location, $http, AuthSharedService, Session,
 USER_ROLES, $q, $timeout) {
// Call when the 403 response is returned by the server
 $rootScope.$on('event:auth-forbidden', function(rejection) {
  $rootScope.$evalAsync(function() {
   $location.path('/error/403').replace();
  });
 });
}

2.4.2 – Client-side authorization management

It’s better to manage authorization client-side for better performance and to avoid servers-side errors.

We added an access property which details if the route requires the user to be logged in and what permissions the user must have to access the route.


myapp.constant('USER_ROLES', {
    all: '*',
    admin: 'admin',
    user: 'user'
});

myapp.config(function ($routeProvider, USER_ROLES) {

   $routeProvider.when("/home", {
        templateUrl: "partials/home.html",
        controller: 'HomeController',
        access: {
            loginRequired: true,
            authorizedRoles: [USER_ROLES.all]
        }
    }).when('/users', {
        templateUrl: 'partials/users.html',
        controller: 'UsersController',
        access: {
            loginRequired: true,
            authorizedRoles: [USER_ROLES.admin]
        }
    })
    // other routs config ...
    // ... 
    .otherwise({
        redirectTo: '/error/404',
        access: {
            loginRequired: false,
            authorizedRoles: [USER_ROLES.all]
        }
    });
}

Next, we add a service function to check if authenticated user has required roles to access the resource.

myapp.service('AuthSharedService', function (Session) {
    return {
        // other functions ...
        isAuthorized: function (authorizedRoles) {
            if (!angular.isArray(authorizedRoles)) {
                if (authorizedRoles == '*') {
                    return true;
                }
                authorizedRoles = [authorizedRoles];
            }
            var isAuthorized = false;
            angular.forEach(authorizedRoles, function (authorizedRole) {
                var authorized = (!!Session.login &&
                Session.userRoles.indexOf(authorizedRole) !== -1);
                if (authorized || authorizedRole == '*') {
                    isAuthorized = true;
                }
            });
            return isAuthorized;
        }
    };
});

Finally, we implement a listener on the $routeChangeStart event to track the next route navigation.
– If the user is not yet authenticated the function broadcast “event:auth-loginRequired”.
– If the user is not authorized the function broadcast “event:auth-loginRequired”.

myapp.run(function($rootScope, AuthSharedService, USER_ROLES) {

 $rootScope.$on('$routeChangeStart', function(event, next) {
 if (next.originalPath === "/login" && $rootScope.authenticated) {
   event.preventDefault();
  } else if (next.access && next.access.loginRequired && !$rootScope.authenticated) {
   event.preventDefault();
   $rootScope.$broadcast("event:auth-loginRequired", {});
  }else if(next.access && !AuthSharedService.isAuthorized(next.access.authorizedRoles)) {
   event.preventDefault();
   $rootScope.$broadcast("event:auth-forbidden", {});
  }
 });

}

2.4.3 – Manage already authenticated user

If the user is already authenticated and he has a valid remember me token he should access the application to the requested page.

When the application starts running, it requests account Rest web service. If the user is already authenticated the rest API will return user details.

We have to carry about account Rest web service response time. That’s why we redirect the user to loading page until getting the response to check authorities for accessing the requested page.

First, we update the AutehtSharedService with getAccount function.

myapp.service('AuthSharedService', function ($rootScope, $http, $resource, 
    authService, Session) {
    return {
        login: function (userName, password, rememberMe) {
            // login code ...
        },
        getAccount: function () {
            $rootScope.loadingAccount = true;
            $http.get('security/account')
                .then(function (response) {
                    authService.loginConfirmed(response.data);
                });
        },
        isAuthorized: function (authorizedRoles) {
            // isAuthorized code ..
        }
    };
});

Next, we add code to handle events and call getAccount function.

myapp.run(function($rootScope, $location, $http, AuthSharedService, Session,
 USER_ROLES, $q, $timeout) {

 $rootScope.$on('$routeChangeStart', function(event, next) {
  // route change start code ...
 });

 // Call when the the client is confirmed
 $rootScope.$on('event:auth-loginConfirmed', function(event, data) {
  $rootScope.loadingAccount = false;
  var nextLocation = ($rootScope.requestedUrl ? $rootScope.requestedUrl : "/home");
  var delay = ($location.path() === "/loading" ? 1500 : 0);

  $timeout(function() {
   Session.create(data);
   $rootScope.account = Session;
   $rootScope.authenticated = true;
   $location.path(nextLocation).replace();
  }, delay);

 });

 // Call when the 401 response is returned by the server
 $rootScope.$on('event:auth-loginRequired', function(event, data) {
  if ($rootScope.loadingAccount && data.status !== 401) {
   $rootScope.requestedUrl = $location.path()
   $location.path('/loading');
  } else {
   Session.invalidate();
   $rootScope.authenticated = false;
   $rootScope.loadingAccount = false;
   $location.path('/login');
  }
 });

 $rootScope.$on('event:auth-forbidden', function(rejection) {
  // auth-forbidden code ...
 });

 // Get already authenticated user account
 AuthSharedService.getAccount();

});

2.5 – Securing UI Elements

To secure UI elements, we will create a directive that accepts as attribute a comma-separated list of authorized roles.

myapp.directive('access', [
    'AuthSharedService',
    function (AuthSharedService) {
        return {
            restrict: 'A',
            link: function (scope, element, attrs) {
                var roles = attrs.access.split(',');
                if (roles.length > 0) {
                    if (AuthSharedService.isAuthorized(roles)) {
                        element.removeClass('hide');
                    } else {
                        element.addClass('hide');
                    }
                }
            }
        };
    }]);

Next, we specify authorized roles in the access property.


      <ul class="nav navbar-nav">
            <li><a href="#/home" class="mdi-action-home"></a></li>
            <li><a href="#/users">Users</a></li>
            <li><a href="#/apiDoc">API Doc.</a></li>
            <li><a href="#/tokens" access="admin">Sessions</a></li>
        </ul>

Conclusion

Even if security is managed client-side with all security features, it’s important to manage security server-side.
Client-side security is easy to hack; user can inspect code and change CSS and display hidden elements and it can display network requests and execute them out of the application.

I hope this post helped you to get an overview on securing an Angular web application with Spring Security. For more information you can read source code in Github and run a demo here.

Thanks for your comments 🙂

References

98 thoughts on “Secure AngularJs application with Spring Security

  1. Dear Samer,
    I have cloned your project on GitHub https://github.com/samer-abdelkafi/ssng-project and I faced with lots of errors. After trying to manipulate the Maven to fix issues I ran it on Glassfish server and found the server sill can’t find bean file or any web.xml file. The question is how can I start this project successfully and does every web project need a web.xml file ? I like to work to upgrade this project to spring IDAP but I wasn’t successful unfortunately.

    1. Thank you for your comment.
      If your application container is Servlet 3.0 ready you don’t need a web.xml file.
      You have to verify if the glassfish version is Servlet 3.0 ready.
      For pom build errors, can you provide log errors as an issue in Github.
      I will try to fix it.
      Regards.

      1. I think the project ran. But I get 404 not found error in debugging with the URL path /security/account
        MY Glassfish server is 4.1 and supports Servlet3 annotations.

  2. Sorry, I found that I didn’t put the source in Java folder. However after restructing the project carefully, I found that org.springframework.orm can not be found. Did you miss something in maven file?

    1. I don’t think that I missed some dependencies. The project is built on Linux (Openshift) server, deployed on Jboss, and runs without any problem.

      I did a test with Glassfish server. There is a problem with Guava version. GlassFish loads an older version.

      You can fix it by removing Swagger Rest API documentation, if you don’t need It.

  3. Hi!

    Failed to run task (com.github.eirslett:frontend-maven-plugin:0.0.22:bower:bower install:generate-resources)

    Failed to run task (com.github.eirslett:frontend-maven-plugin:0.0.22:gulp:gulp build:generate-resources)

    Any idea what may cause this? I tried deleting those to executions

    bower install

    bower

    install

    gulp build

    gulp

    generate-resources

    and it compiled successfully but unfortunately it didnt load first page cuz there was missing folder ‘vendors’ in resources folder and also some uncaught errors ‘Cannot read property ‘controller’ of undefined’ etc.

    Any idea what may cause this? I am using tomcat 8.

      1. Hmm yes now that i downloaded it again then it also had vendor folder, before it was missing for some reason. Now it seems to be working. Thank you for fast response and great piece of code!

  4. Dear Sameer

    I was looking for good spring security+AngularJs login based application. You work is very nice.
    Actually I am converting my current spring mvc project into AngularJs based. As already lot of code/functionality exist I am dare change the whole existing setup . I am comfort with spring-context.xml and web.xml based (existing projeect setup). Do you have any sample with xml based config.? it will be very helpful for me.
    In your code how we set session invalidate on inactive

    thanks in advance

    1. Hi,

      I’m sorry, I don’t have a sample with xml based config.
      I suggest this post that may help you: http://www.baeldung.com/2011/10/31/securing-a-restful-web-service-with-spring-security-3-1-part-3/

      I don’t understand your last question. If it’s about logout it’s managed by /logout URL and the HttpStatusReturningLogoutSuccessHandler.
      If you are looking for a solution for Handling of expired sessions, in my sample the user will be redirected to login page.
      But if you would like to manage expired session, I think this article can help you http://www.waitingforcode.com/spring-security/handling-of-expired-sessions-in-spring-security/read

      Regards.

  5. How secured is this example, since you are disabling the CSRF protection and in this part of the tutorial: “Client-side authorization management” you do the authorization in the client side, is this configuration secured in production?

    1. Hi,

      If you think you have CSRF risk, you have to enable protection against it.

      In this sample Authorization is managed server side and client side.
      You can test it by login as “bill” user, then try in the browser to call rest API to provide authenticated users “/security/tokens”. You will get response status 403.
      For your test you can use this URL: http://bit.ly/ssng-project

      This configuration is secured in production.

      Regards.

      1. I tried adpting the example to my angularjs/spring mvc web app, but I when I press the login button it doesn’t do anything, I beleive that this part it’s not too clear form me:

        In the AuthSharedService service you o a http.post to a url like this
        $http.post(‘authenticate’, ”, config)
        .success(function (data, status, headers, config) {
        authService.loginConfirmed(data);
        }).error(function (data, status, headers, config) {
        $rootScope.authenticationError = true;
        Session.invalidate();
        });

        the thing is that I don’t understand what does means the ‘authenticate’ url that you put inside the post method like this $http.post(‘authenticate’, ”, config), since you only use this ‘authenticate’ value in the SecurityConfig.java class in the .loginProcessingUrl(“/authenticate”) but I don’t have that url in my project and you don’t have it also, since I downloaded your project from github and searched fro that url and it doesn’t appear in any other file besides, the SecurityConfig.java and AuthSharedService.js

        thanks in advance

  6. I have a doubt, couldn’t somebody press F12 in their web browser and then use the console to override the permission level that is set for them on the service? Is there a way to restrict the views in the serve-rside I know that you put this line in the security config in java “.antMatchers(“/users/**”).hasAnyAuthority(“admin”)”but I tried putting the partials like in my case “partials/deleteUser.html” and i put the role admin so the admin would be the only one who could wath the page but it din’t worked I always get the forbiden response even when I try with the role admin, if there a way to protect partials from the server-side? can I tried moving the partials from the resourses folder and put them in the views folders wheres the index.html page, but I get a 404 error

    1. Hi Feng,

      Here is my response for your 20 May question:
      In the sample source code, we set the login porocess URL to “authenticate”. It’s the URL that the login form is posted to. If unspecified, it defaults to /login.
      Spring Security framework intercepts that URL and gets login and password parameter, then look for the user details. In our case it will use com.mycompany.myproject.security.UserDetailsService .

      Here is my response to your 22 May question:
      In the post sample, Rest web services URL are secured. Even if user can get the html he can’t get data.
      When Angular calls the Rest service the server return back a 403 status. Then, the angular-http-auth module will broadcast ‘event:auth-forbidden’. Finally, the user is redirected to the 403 error page.
      I think you can secure static html resources. You may need to define a directory hierarchy for your partials html pages like that:
      partials/public/ for public html pages.
      Partials/private/admin for admin pages.
      Partials/private/user for users pages.
      Then, you secure URLs in your securityConfig class.

      Regards.

      1. thanks for the reply friend, I tried what you said about creating a folder structure to protect my partials but I always get error 403 like if my user doesn’t have the role to get access to that partial but I’m extremely sure that the user with I login have that role, here is my project structure

        SpringMVCProject
        –Web-Pages
        –WEB-INF
        –resources
        –angular
        –controllers
        userController.js
        –services
        userService.js
        –partials
        –userPartials
        deleteuser.html
        app.js
        permissionConstants.js
        routes.js
        –css
        –privatePartials
        protectedPartial.html
        –views
        index.html
        –Source Packages
        –controllers
        –userControllers
        UserController.java
        –secuirty
        SecuirtyConfig.java

        I put this line in my SecuirtyConfig class like you said
        .antMatchers(“/privatePartials/protectedPartial.html”).hasAnyAuthority(“roleA”)

        and also this one
        .antMatchers(“/privatePartial/protectedPartial.html”).access(“hasRole(‘roleA’)”)

        but still I get the 403 error message

        I posted this questions in StackOverFlow with more Details
        https://stackoverflow.com/questions/37504785/spring-secuirty-dont-let-me-get-access-to-my-protected-static-files

        https://stackoverflow.com/questions/37368320/how-to-protect-angularjs-partials-pages-with-spring-security

        thanks in advance

  7. sry for all the question friend, I solved the antmatcher problem it was my mistake I was adding the permission instead of the roles in the UserDetailService when you add all the authorities that is why when the antmatcher was checking my authority I was getting a 403 error, but now I notice that when I refresh the page my spring security session is lost, and when this happens I can get access to all the antmatchers private partials it doesn’t matter what role I have if I refresh the page I get access to all the private partials, here is my code in a stackoverflow question https://stackoverflow.com/questions/37504785/spring-secuirty-dont-let-me-get-access-to-my-protected-static-files , sry and thanks in advanced

    1. Hi,

      It’s strange that you lose session.
      I can’t see what the problem is.

      If your project is not confidential and doesn’t have any business code, you can share your source code on GitHub. Then I will try to look for solution.

      Regards.

      1. no is not confidential I would put it in GitHub as soon as I get a chance, but I forget to tell you that I’m not doing anything that has to do with the “remember me” I mean I don’t have the RememberMeServices class that extends AbstractRememberMeServices and nothing that have to do with the remember me function, does this have something to do with keeping the session after refreshing the page, I excluded since I thought that it was only to avoid the login after login out.

  8. Caused by: java.lang.ClassCastException: Cannot cast org.springframework.web.SpringServletContainerInitializer to javax.servlet.ServletContainerInitializer problem javax.servlet-api and spring?

    1. This error could be related to your workspace or project configuration.
      I will reply to your firs question, it may help you solve this Exception.

      – I suggest using STS (https://spring.io/tools) as Eclipse version. It has all Spring, Git, maven plugins installed and well configured.
      – To import the project, click on menu File>Import>Check out Maven Project from SCM
      Provide SCM URL https://github.com/samer-abdelkafi/ssng-project.git
      – Right click on the project and select Run as> maven install
      – Finally Right click on the project and select Run as> run on server> select your tomcat (version 7) or you can use provided TC Server.

  9. hi friend sry that I didn’t upload my project to github, but I created a stackoverflow question with all the code that I have in my project, I have the same thing that you have in the example except the remember me related code, I kinda found out the problem, if I refresh or reload the page I get redirected to logout somehow, and then redirected to the login page, does this have something to do with me don’t having any remember me code, I would apreciate if you can check my AuthSharedService javascript file and look the url that I put in the $http.post method and my login controller.java, and of course the SecurityConfig.class is all in that question that I made, thanks in advance and sry
    https://stackoverflow.com/questions/37504785/spring-secuirty-dont-let-me-get-access-to-my-protected-static-files

  10. Hey Samer Abdelkafi, Thanks for posting the tutorial. In POST call to /authenticate username and password been passed as query parameters. On omitting theses query parameter error occurs. Why ?

  11. Hi Samer, very nice tutorial! I have some similar requirements, but instead of $routeProvider, I am using $stateProvider. What changes will i need to make to your tutorial to make it work?

    – Can I add an “access” object to my state object like you to in then when() call on $routeProvider?

    – What would be the code change required in this line: $rootScope.$on(‘$routeChangeStart’, function(event, next)

    – What other changes?

    Thanks

    1. I think you can control partial page access with UI-Router the same way it’s done with the default angular router.
      You can add access to states like that:

      $stateProvider.state('contacts', {
        template: '<h1>My Contacts</h1>',
        access: {
                  loginRequired: true,
                  authorizedRoles: [USER_ROLES.admin]
              }
      })
      

      Next you control access on stateChangeStart event.

      $rootScope.$on('$stateChangeStart', 
      function(event, toState, toParams, fromState, fromParams, options){ ... })
      

      Regards.

  12. Hi Samer;
    i see your powerfull example project and i would like to my project.
    when i am trying to login, i become a failure like ” No ‘Access-Control-Allow-Origin’ header is present ”
    please can you help me?
    Best Regards

  13. Hi Samer Abdelkafi,
    thank you for you nice demo. I really like it. After downloading, it took me an hour for configurations. But i can not build this project.
    i am using nodejs 2.14.7
    JDK 1.7
    maven 3.2.1
    tomcat 7.0.67
    eclipse Juno
    i got as following log error:
    [ERROR] npm WARN prefer global marked@0.3.5 should be installed with -g
    [ERROR] npm WARN EPACKAGEJSON example@0.0.1 No repository field.
    [ERROR] npm WARN EPACKAGEJSON example@0.0.1 No license field.
    [ERROR] bower jquery#2.1.4 ENOGIT git is not installed or not in the PATH
    [ERROR] Failed to execute goal com.github.eirslett:frontend-maven-plugin:0.0.22:bower (bower install) on project ssng-project: Failed to run task: ‘bower install’ failed. (error code 1) -> [Help 1]
    [ERROR]

    do you any suggestions? highly appreciate if you have any 🙂 thank you a lot

      1. Hi Samer,

        It is impressed me, it works to me, so great. Thank you for your response and have a nice day

      2. Hi

        I did what mentioned, remove frontend-maven-plugin , maven, clean, install, and the error is gone.
        but i cannot start the page, it only shows “404 – Not Found”
        I don’t see any errors, “Clean succesfull” && “Build successful”
        I’m Using wildfly 10, this is the output of the deploy:
        ————————————————————————————————————————–
        22:37:08,328 INFO [org.jboss.as.server.deployment.scanner] (DeploymentScanner-threads – 2) WFLYDS0004: Found ssng-project-1.0-SNAPSHOT.war in deployment directory. To trigger deployment create a file called ssng-project-1.0-SNAPSHOT.war.dodeploy
        22:37:08,333 INFO [org.jboss.as.server.deployment] (MSC service thread 1-3) WFLYSRV0027: Starting deployment of “ssng-project-1.0-SNAPSHOT.war” (runtime-name: “ssng-project-1.0-SNAPSHOT.war”)
        ———————————————————————————————————————————-
        Thanks!!!

      3. Hi, great article!

        i’ve spent some time trying to get this work, i’m still stuck, it seems really hard to do.

        I’m doing

        -Eclipse STS, downloaded code from SCM Provide SCM
        -remove frontend-maven-plugin
        -mvn clean, install, run on Server (wildfly 10)

        It compiles and install OK.

        I deployed, ok I think
        But it returns “404-not found” on the browser =(

        Did this have happened to someone?

        In the wildfly log i see three warnings, i dunno if they are critical or not, since they are warnings:

        WARN [org.jboss.as.ee] (MSC service thread 1-4) WFLYEE0007: Not installing optional component org.springframework.http.server.ServletServerHttpAsyncRequestControl due to an exception (enable DEBUG log level to see the cause)
        WARN [org.jboss.as.ee] (MSC service thread 1-4) WFLYEE0007: Not installing optional component org.springframework.web.context.request.async.StandardServletAsyncWebRequest due to an exception (enable DEBUG log level to see the cause)
        WARN [org.jboss.weld.deployer] (MSC service thread 1-4) WFLYWELD0013: Deployment deployment “ssng-project-1.0-SNAPSHOT.war” contains CDI annotations but no bean archive was not found. (No beans.xml nor class with bean defining annotations)

        thanks!

      4. [SOLVED]

        Hi again !!!

        It turns out that the war name was “ssng-project-1.0-SNAPSHOT.war”

        then the “ssng-project” was not the real URL (the one wich pop ups in the browser):
        http://localhost:8080/ssng-project/#/login

        I changed to ssng-project-1.0-SNAPSHOT and worked perfectly!!
        http://localhost:8080/ssng-project-1.0-SNAPSHOT/#/login

        I think the problem i had is related to the way the war is created i’ll see what is going out with that!

        thanks!!

  14. Hello!

    I have a little doubt about your post: Secure AngularJs application with Spring Security.

    When you do a call to /authenticate: $http.post(‘authenticate’, ”, config)
    In this way angular sends the post with params as a query string. Is there a way to not do it like this? It seems insecure to me to send credentials data like that. I also tried to send the parameters in the body but spring security is not able to catch them, only works with the parameters as a query string.

    Do you know why it works like that? And do you have a solution to send those params in the post body?

    Thanks in advance, very nice article and the only one I found on the internet that’s actually clear how to combine angularjs and spring security.

    1. Hi,

      Thank you for this details and your comment.

      You are right. this is a security problem.

      You can fix it:

      login: function (userName, password, rememberMe) {
                  var config = {
                      ignoreAuthModule: 'ignoreAuthModule',
                      headers: {'Content-Type': 'application/x-www-form-urlencoded'}
                  };
                  $http.post('authenticate', $.param({
                          username: userName,
                          password: password,
                          rememberme: rememberMe
                      }), config)
                      .success(function (data, status, headers, config) {
                          authService.loginConfirmed(data);
                      }).error(function (data, status, headers, config) {
                      $rootScope.authenticationError = true;
                      Session.invalidate();
                  });
              },
      

      Best regards

  15. Hi. Thank you for your article. I have chosen your solution for my web project and tell me please. When I try make some changes in your project, it doesn’t allow to do it. For example I tried to change index.html, but after compire the index.html is reverted. Please could you help me? Thanx!

    1. Hi,

      The project uses gulp-inject for injecting css and js.

      If you made some changes to css or js imports they will be erased.

      But if you made changes outside of inject:css and inject:js they should be preserved.

      Best regards.

  16. Hi,

    thanks for your work, I really appreciated.

    I got a question: I’ve replicated this behavior in my own project. What I mean is that everything is just like you have architected but my app is a bit different. For example I use “state” instead of “route” provider. And I use mysql instead of hsql. But in the end, 90% is just like your own (cloned from your github).

    So, my question is: why is my app not “landing” on /login url? I mean: I deploy app on tomcat 7 (local eclipse) and when I insert “localhost:8080/myapp/” it will redirect to “otherwise” url (defined in app.js). Even if I’m not actually logged in.
    NOTE: if I go to localhost:8080/myapp/#/login/ I can use the login form correctly, but I get another error (see below).

    Last question: inside authSharedService.js, “login” function. Could you provide an implementation of “authenticate” method? Apparently I can’t logging in if I leave it void.

    Kind regards,
    Claudio

    1. [SOLVED] I was ant matching for “/**” instead of “/”. Now everything works fine.

      Just last question: when I successfully login, I expect to be redirect to “/myCustomUrl”. It really redirect me, but it does not replace the content inside “ui-view” (I actually see correct url in top of my browser, but it still display my login form, instead of my “myCustomUrl” content).

      It is angular or spring issue?

      1. well….solved this too! It was an improper use of “$location.path(nextLocation).replace()” since I use $state insted of $route. Indeed, the correct way:

        replace –> $location.path(nextLocation).replace()
        with –> $state.go(nextLocation);

        And do it for every $location replace() statement.

  17. Hi,

    new error here: after login, every URL coming from requestMapping (ie: “/security/account”) return a 403 forbidden –> Access denied. Before login it returns 401 (as expected).

    I don’t understand what’s wrong. Same as your application. Maybe the issue is related to spring 4? I’m using 4.3.3

    Thanks,
    Claudio

    1. solved! 😀
      I just added my .antMatchers(“/api”).hasAnyAuthority(“admin”) after the first one with “permitAll()”. In this way, everything works fine. If I add after another “hasAnyAuthority()”, it doesn’t work.
      No guide will explain this, keep in mind: the order is important

  18. Hi Samer. It is really good realization for us and thank you.

    Samer, I have some questions.

    1. I use one page site and authorization with registration only placed in one page in header.
    I saw this code AuthSharedService.getAccount(); First before show main page run function of checking user for authenticated or not. For my case it is not good, can you tell me: How can I save my users data in the site? Can I use cookie of Angular or may be you give another some advises. Is it right to use cookie?

    I have seen many cases in Google, but I don’t know How I can store user in my site. Thank you.

    1. Hi,
      The application already uses a remember me cookie to save authenticated users sessions.
      When the get account request is sent, if the cookies exists the application will get user account if it is already stored. Otherwise it will return code 401 (unauthorized user).
      I don’t think it’s a good solution, to store user data in cookies, because you can lose them. It’s better to store a remember me cookie in the client side and manage users data in the server side in a database.
      Best regards.

  19. Hi Samer,
    This article was lot of help and saved a lot of time…
    I have a question, “if i have to use a custom auth provider and remove db based lookup for users” what should I change.
    I appreciate your clear responses to the questions.

    Thanks
    Abu

    1. Hi,

      To use a custom authentication provider, you can implement it like that:

      @Component
      public class CustomAuthenticationProvider implements AuthenticationProvider {
      // override methods
      }
      

      Then, configure spring security to use your custom provider:

      @Configuration
      @EnableWebSecurity
      public class SecurityConfig extends WebSecurityConfigurerAdapter {
          @Autowired
          private CustomAuthenticationProvider authProvider;
       
          @Override
          protected void configure(AuthenticationManagerBuilder auth) throws Exception {
              auth.authenticationProvider(authProvider);
          }
       
      }
      

      This article may help you:
      http://www.baeldung.com/spring-security-authentication-provider

      Best regards.

  20. It’s possible to run font-end and back-end as two diffrent application? Eg. back-end on port 8080 and front 9000 using Grunt? This security configuration it’s able to work in this situation?

  21. First I want to thank you for your wonderful article. It saves my days.
    Currently I am facing one problem.
    I have created One page called /signup with loginRequired = false. user are requested to fill up very minimum information and submit the from. after that I am sending one backend created link (set password/activation) link to user’s email.
    http://localhost:8080/#/setpass/O1IuJUJJBFcEHghUIS1ZTFtWCh8=
    now the problem is when user clicks the link it redirect to /login page. But I want to open /setpass page.

    But if I copy the link and paste it working on 2nd try.
    Here is the route info from app.js
    .when(‘/signup’, {
    templateUrl: ‘partials/signup.html’,
    controller: ‘SignUpController’,
    access: {
    loginRequired: false,
    authorizedRoles: [USER_ROLES.all]
    }
    }).when(‘/setpass/:activationCode’, {
    templateUrl: ‘partials/setpass.html’,
    controller: ‘SetPasswordController’,
    access: {
    loginRequired: false,
    authorizedRoles: [USER_ROLES.all]
    }
    })

    Please help me out to fix this.
    There is another problem I am facing, duplicate or two time login form is coming. 1) login to the application with proper user name and password, then /home page is landing. after that if user submit /home page with few info and trying to go to second page /users, before jumping to /users page application automatically lading /login page again..
    I will wait for your help.
    Thanks,
    Sabir

    1. Hi,

      According to your problem description, I think that you forget to manage server side URLs access.
      You have to enable access throw Spring security in the SpringConfig Class.
      You need to add access to all URLs used in the signup page:
      age:

      public void configure(WebSecurity web) throws Exception {
         web.ignoring().antMatchers("/signup/**", "url1", "url2");
      }
      

      Best regards.

      1. Thanks for your quick reply… I tried by managed by server side security setting before. But did not solve that problem. Finally I found it. But adding below condition in “event:auth-loginRequired” event handle.
        else if($location.path().indexOf(‘/setpass/’) > -1)
        ———————————————————————–
        $rootScope.$on(‘event:auth-loginRequired’, function (event, data) {
        if ($rootScope.loadingAccount && data.status !== 401)
        {
        $rootScope.requestedUrl = $location.path();
        $location.path(‘/loading’);

        }
        else if($location.path().indexOf(‘/setpass/’) > -1)
        {
        // fell free to accept set password url
        }
        else
        {
        Session.invalidate();
        $rootScope.authenticated = false;
        $rootScope.loadingAccount = false;
        $location.path(‘/login’);
        }
        });

  22. Hi Samer,

    I am following your tutorial to secure my angular app with spring security. Everything is working fine till I haven’t trying to start login from my angularjs custom login page. I am sending one ajax call with username and password but the issue is that in UserDetailServiceImpl.java class is extending the UserDetailsService class for DB authentication is getting username null in the method parameter. Data is going fine from front end but spring security is not able to catch it. Can you please help me out in this.

    1. Hi,

      You may have a different names for the parameters in your ajax call.
      You can fix it by changing the login request pamaters name in the SecurityConfig class:

      .usernameParameter("username")
      .passwordParameter("password")
      

      Best regards.

  23. Thank you for this wonderful example and demo using spring and angularjs.
    Can you describe the process of deploying this project in live server?

      1. I did not see any code from where you called index.html, however it is the main file where all javascript are included. How will index.html is used in your project?

  24. When I run project only back end part runs in localhost:8080. How to run font end? I added gulp.task(‘connect’, function() {
    connect.server({
    root: ‘./’,
    livereload: true
    })
    });
    to connect to localhost, but if I tried to run back end from STS server which is tomcat and gulp from command promt, project will not run. Can you tell me how to run both back end and front end correctly?

    1. Hi,

      The index.html is the default page of the application. It’s loaded when you call your web application context.
      In this project html pages, js and css are static resources managed by the application server.
      You may need to add your web application context to your URL.

      Best regards.

  25. Hi,
    How are the service package interface such as GenericService.java and classes such as GenericServiceImpl.java are being called in the project? I did not see any autowiring of service layer in controller.
    Can you explain how service layer is being managed?

    1. Hi Bimal,

      Thank you for your comment.
      You are right; the GenericServiceImpl service isn’t used in the code.

      For simplification reason, I made the controller layer access directly to persistence layer.

      Best regards.

  26. Hi again =D

    This is a great example about spring security, i downloaded the code and i’m using it in a project.

    I’ve got some problems trying to call a stored procedure.

    I have basic entities, one-one related to my tables, then i’d like to create a more complex query, so I created a postgresql function (stored procedure) with my query

    I tried with an example i found, but i’m still not able to execute the SP via JPA

    or i need to do it in other ways?

    Example:
    native query (in the entity?)
    —————-
    @NamedNativeQueries(
    value={
    @NamedNativeQuery(
    name = “sp_name”,
    query = “select id,nombre from sp_name(?) ;”
    )
    }
    )
    —————–

    then created a entity manager here is where an error shows up “Caused by: javax.persistence.PersistenceException: No Persistence provider for EntityManager named Paciente”}}”

    ————
    private static final String PERSISTENCE_UNIT_NAME = “Paciente”;
    private static EntityManagerFactory factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
    —————–

    then the method
    —————————
    public List findActivos(long usuarioID) {
    List result = new ArrayList();
    EntityManager em = factory.createEntityManager();
    Query query = em.createNamedQuery(“sp_name”).setParameter(1, usuarioID);
    result = query.getResultList();
    return result;
    }
    —————————

    thanks =D

  27. hi sameer,
    your project has saved my lot of time ,and currently i want to use your project for android app authentication,so can you tell me how to authenticate webapp user .

    Thanks in advance.

  28. Hi Samer.Your article was very helpful saved my time a lot.But I have a problem.When I log in into system and refresh page once I deal with some problems…when I refresh the page redirect to login page.and when I type in url rest Request (for authorized user) I will see pure html of that page! But if I go to that page through angularjs routing I will redirect to login page! so after refresh I can see authorized page through rest request(but I just see pure html without any resources) and redirect to login page through angularjs routing! I can not understand what is happening

    1. and I should explain more…before adding any security config I can see pure html pages through rest request…so to clarify the problem my project is working correctly in back end(because I can see authorized pure html pages after refresh and cant see unauthorized html pure pages through rest request) but I just see login page through angular routings after refresh!
      hope you understand what do i mean!!!
      Thank you so much

  29. Hi samer,
    I have a small question. When the post method is executed in the client side:
    $http.post(‘authenticate’, $.param…………. )

    where is the corresponding java backend controller that takes the request.? or is it that spring security implicitly handles that?

  30. Samer, hi again. Could you help me please. How did you hide js file from view in source folder in chrome?
    For example If I open with right button of mouse in source menu I don’t see js files. I need it in my case. Thank you.

  31. Hi Samer,
    on calling spring security authentication via restful service post causes a 405 error. Not sure why this is happening since all the credentials are correct.

  32. Hi Samer,
    school boy error forgot to add the following .loginProcessingUrl(“/authenticate”). All works fine.

  33. Hi, thanks for your work. It helps me. But I have one question, where in application is set that /home must load as default. Spent much time but can’t found this. Help me please.

    1. Additional: when I load localhost:8080 it’s redirect me to localhost:8080/#/login even if home page has open access

      1. Deal with this issue, there is a request inside app.ys that accesses the server AuthSharedService.getAccount and since I’m not logged in the 401 get a server and redirect happens, it is elementary =)

  34. HI i am facing some problem with lib.min.js so i want to inject all js files sepratel but its not allowing..

    i am doing like this..
    1)This is my app.js
    var myApp = angular.module(‘myApp’, [‘ngResource’,’ngRoute’,’swaggerUi’,’http-auth-interceptor’,’ngAnimate’,’ngSpinkit’,’ui.bootstrap’,]);
    // here i am injecting above directives

    2)
    I am removing lib.min.js and trying to add below css and js files(i.e my index.html looks like this)

    https://code.jquery.com/jquery-2.1.4.min.js
    https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0/angular.min.js
    http://ajax.googleapis.com/ajax/libs/angularjs/1.2.9/angular-route.js
    https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0/angular-resource.js
    https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0/angular-sanitize.js

    http://angular-ui.github.io/bootstrap/ui-bootstrap-tpls-1.2.5.min.js
    http://static/js/app.js
    http://static/js/controller/user_controller.js
    http://static/js/service/user_service.js
    http://static/js/easyResponsiveTabs.js
    http://static/js/index.js
    http://static/js/directives.js

    its giving an error “Uncaught Error: [$injector:modulerr] http://errors.angularjs.org/1.3.0/$injector/modulerr?p0=myApp&p1=Error%3A%2…ogleapis.com%2Fajax%2Flibs%2Fangularjs%2F1.3.0%2Fangular.min.js%3A18%3A316)”

  35. Try this:

    var nextLocation = ($rootScope.requestedUrl ? $rootScope.requestedUrl : “/home”);
    $timeout(function () {
    session.create(data);
    $rootScope.account = session;
    $rootScope.authenticated = true;
    $state.go(nextLocation);
    }, 100);

    It actually say: get the requested URL. If it’s void, set state to ‘home’ (thisis a particular situation where your session has been terminated or someone give you the link before a login).

    1. hey Claudio,

      i am working on the same setup with $state and having trouble with the routing.
      questions:
      1. how do we get the path? (replace $location.path())
      2. what did you replace $location.path(‘/error/403’).replace(); with? ($state.go(‘/error/403’))?
      3. do you recall any other changes you made for using state?

      // Call when the 401 response is returned by the server
      $rootScope.$on(‘event:auth-loginRequired’, function (event, data) {
      if ($rootScope.loadingAccount && data.status !== 401) {
      $rootScope.requestedUrl = $location.path()
      $state.go(‘/loading’);
      } else {
      Session.invalidate();
      $rootScope.authenticated = false;
      $rootScope.loadingAccount = false;
      $state.go(‘/login’);
      }
      });

      // Call when the 403 response is returned by the server
      $rootScope.$on(‘event:auth-forbidden’, function (rejection) {
      $rootScope.$evalAsync(function () {
      $location.path(‘/error/403’).replace();
      });
      });

      I configured my state provider with the access property like:

      .state({
      name: “login”,
      url: “/login”,
      templateUrl: “partials/login.html”,
      controller: “LoginController”,
      access: {
      loginRequired: false,
      authorizedRoles: [USER_ROLES.all]
      }
      })

      1. hi,

        1- You can get current state like that $state.current.name
        If you need the path you can use $state.href(state)

        2- $location.path(‘/error/403’).replace(); ==> ($state.go(‘/error/403’)), I think it’s right

        3- I didn’t tray implementation with ui-router. What you did seams right.

  36. Hi Samer,
    I had used your project in my application , it is working fine. but when i use this application on safari i was unable to get user data from spring by hitting api “security/account” ,now i am very much clueless to what should i do .help me,

  37. Hi Samer,

    Thanks for this wonderful tutorial which I have implemented successfully. However my project requires now CSRF protection as well. I am following this tutorial https://spring.io/guides/tutorials/spring-security-and-angular-js/ and able to login successfully with csrf but after that none of my rest api url is working, getting the message “Invalid csrf token blah blah blah.” Can you please help me out or if would be so helpful if you can provide any csrf tutorial as well.

    Thanks
    Vaibhav

  38. Hey Samer Abdelkafi,
    Thanks for posting the tutorial. In POST call to /authenticate username and password i have the code http 403
    but when i use GET (“/authenticate?username=username&password=password”) i have the code http 200

  39. The above-mentioned point just scratches the surface of advantages offered by AngularJS and how the new version of AngularJS will revamp the development deeds. You are about to crave the future which will be exciting for all developers.

  40. Hi in angular service named AuthSharedService, authService is being injected. But I can’t find where it’s being defined? Please help me to understand the purpose of this injection.

  41. Thanks Samer for this article.

    It’s a good way to use Spring Security.

    I just have one problem with your solution.

    The Credentials are passed as parameter of the URL: http://xxxxxxxxx?username=yyyy&password=zzzzz

    It’s actually a bad practice as it will allow man in the middle attack as it allow to read the username password of the user. The values username and password should be pass as post.data, not post.params.

    But as it is now the loginForm() only allow params!

    If someone could find a fix for this problem I’d be happy to hear it… in the meantime I will use an “AuthenticationProvider”

    That’s a shame, as I think you solution was really neat.

  42. How would you try to integrate a file upload in this example? Also can the navigation bar be hidden based on authentication for ex: if user, hide users tab and etc…

Leave a reply to Samer Abdelkafi Cancel reply