Question: Spring Security AJAX login with CORS and CSRF


Spring Security AJAX login with CORS and CSRF

Answers 0
Added at 2017-01-05 19:01

I have problem with AJAX login on another server with Spring Security and CSRF tokens.

I have very little time before production, app is working very slow with bigger number of users, and have a few not so great server instances. I've been planing on solving this problem with spliting server work on AJAX and non-AJAX server calls. If there is other way around please help me, also every advice is very welcome. My solution is below.

I need to have one Main Server and multiple API servers. They are basically same applications, but created like that so that all AJAX calls go to different API servers, and Main server should work with JSP pages. And now I have problem with logging in on API server.

I have created next responsibility chain.

  1. AJAX GET Request to /api/csrf - Returns CSRF in header
  2. AJAX POST Request to /ajax/login - Should login to API server

CORS is working properly it always returns 200 OPTIONS response before POST login request witch returns 405 Method not allowed, I assume problem is in CSRF tokens.

AJAX looks like this

function loginUser(){

// retrieves CSRF tokens and then calls for login
    url: "http://localhost:8081/gabe-is-cool-guy/api/csrf",
    type: "GET", 
    crossDomain: true,
    success: function(data, status, request){

        // CSRF parameters
        var header = request.getResponseHeader("X-CSRF-HEADER");
        var param = request.getResponseHeader("X-CSRF-PARAM");
        var token = request.getResponseHeader("X-CSRF-TOKEN");

        // User credentials
        var username = $("#username").val();
        var password = $("#passwrod").val();
        var data = {
            "j_username" : username,
            "j_password" : password

        // login user
            url: "http://localhost:8081/gabe-is-cool-guy/ajax/login",
            type: "POST", 
            crossDomain: true,
            data: JSON.stringify(data),
            beforeSend : function(xhr) {
                xhr.setRequestHeader(header, token);
                xhr.setRequestHeader("Accept", "application/json");
                xhr.setRequestHeader("Content-Type", "application/json");
            success : function(data) {

                    console.log("Login successful");
                    console.log("Bad credentialas")

public class CSRFController {

    public String getToken(HttpServletRequest request, HttpServletResponse response){

        CsrfToken token = (CsrfToken) request.getAttribute("_csrf");

        // Spring Security will allow the Token to be included in this header name
        response.setHeader("X-CSRF-HEADER", token.getHeaderName());

        // Spring Security will allow the token to be included in this parameter name
        response.setHeader("X-CSRF-PARAM", token.getParameterName());

        // this is the value of the token to be included as either a header or an HTTP parameter
        response.setHeader("X-CSRF-TOKEN", token.getToken());

        return "Status OK";
} (Works on same server)

public class LoginController {

    AuthenticationManager authenticationManager;

    SecurityContextRepository repository;

    RememberMeServices rememberMeServices;

    @RequestMapping(method = RequestMethod.POST,produces = MediaType.APPLICATION_JSON_VALUE,consumes = MediaType.APPLICATION_JSON_VALUE)
    public String performLogin(@RequestBody JUserWrapper user, HttpServletRequest request, HttpServletResponse response) {

        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user.getJ_username(), user.getJ_password());

        try {
            Authentication auth = authenticationManager.authenticate(token);

            repository.saveContext(SecurityContextHolder.getContext(), request, response);
            rememberMeServices.loginSuccess(request, response, auth);

            return "{\"status\": true}";

        } catch (BadCredentialsException ex) {
            return "{\"status\": false, \"error\": \"Bad Credentials\"}";

public class APICorsFilter extends CorsFilter {

    public APICorsFilter() {

    private static UrlBasedCorsConfigurationSource configurationSource() {
        CorsConfiguration config = new CorsConfiguration();
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);
        return source;
Source Show
◀ Wstecz