Search code examples
javaspringspring-securitycorsspring-social

AngularJS, Spring Social and CORS


I have an app that I have built using Spring with Spring Social.

I was able to connect to Social Networks, it worked well. Then I had the great idea to use angular on the front end instead of jsp and set about replacing my html forms that I used to connect to social networks with http posts using angular.

Now I am getting the error

XMLHttpRequest cannot load https://accounts.google.com/o/oauth2/auth?client_id=233119510011-epdnrh651t…%2Fconnect%2Fgoogle&scope=email&state=e29561c9-a538-47dd-8b92-ca0aaa8b413b. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access. 

Form posts work, but angularjs posts do not. What gives? I looked at the failing angular post using fidler, compared it to the working html form post and found this.

Working POST using html forms

 POST http://localhost:8080/connect/google HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Content-Length: 54
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Origin: http://localhost:8080
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.76 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Referer: http://localhost:8080/myscene/account-settings
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8
Cookie: _ga=GA1.1.679586999.1424266167; JSESSIONID=74A29A5F0B04B937281A7FAC4DD7B102
X-Forwarded-For: 12.13.14.15

_csrf=c71a3881-d272-42de-b8b1-c7647f7e7609&scope=email

Here's the code that makes that post

<form action='<c:url value="/connect/google" />' method="POST">
                        <input name="${_csrf.parameterName}"
                            value="${_csrf.token}" /> <input name="scope"
                            value="email" />
                        <button type="submit" class="common_button">Connect with
                            Google</button>
                    </form>

POST that doesn't work using angularjs

POST http://localhost:8080/connect/google HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Content-Length: 54
Origin: http://localhost:8080
X-XSRF-TOKEN: c71a3881-d272-42de-b8b1-c7647f7e7609
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.76 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Cache-Control: max-age=0
Referer: http://localhost:8080/myscene/account-settings
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8
Cookie: _ga=GA1.1.679586999.1424266167; JSESSIONID=74A29A5F0B04B937281A7FAC4DD7B102
X-Forwarded-For: 12.13.14.15

_csrf=c71a3881-d272-42de-b8b1-c7647f7e7609&scope=email

Here's the code that makes that post

$http({
                  method  : 'POST',
                  url     : '/connect/google',
                  data    : $.param(oauth2Scope),  // pass in data as strings
                  headers : { 
                                'Content-Type': 'application/x-www-form-urlencoded',
                                'X-XSRF-TOKEN'   : token,
                                'Cache-Control'  : 'max-age=0',
                                'Accept'         : 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8'
                            }  
                 })

Am I on the right track? I've found this quite tricky so any help is more than welcome! Hopefully someone can point me in the right direction.

EDIT 1:

I've created a filter server side but things are not working so there must be something else I need to do.

EDIT 2:

Also, it is worth noting the request that generates the error is a GET to google's servers by the Spring Social Framework. My angular POST that causes the issue is to localhost:8080 and is processed by Spring Social.

EDIT 3: So I have noticed this is a problem only when spring social sends that GET to google / facebook and not for my own site. For my own site, I can submit ajax posts using angular fine.

Also, I have noticed the non working GET to google has Origin included where as the working GET to google does not. Could this be the problem?

Filter

@Component
public class SimpleCORSFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // TODO Auto-generated method stub

    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp,
            FilterChain chain) throws IOException, ServletException {

        HttpServletResponse response = (HttpServletResponse) resp;

        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "x-requested-with");

        chain.doFilter(req, resp);
    }

    @Override
    public void destroy() {
    }

}

Solution

  • Your servlets/rest services must have the CORS header set and I noticed that $http checks the http OPTIONS prior to a call.

    The best way to add this features is a filter, that adds the header entries.

    See Tomcat CORS filter