title: Getting RestAssured test to work with Spring Security CSRF for AngularJS
body: <p>I've found "<a href="https://spring.io/blog/2015/01/12/the-login-page-angular-js-and-spring-security-part-ii" rel="nofollow">The Login Page: Angular JS and Spring Security</a>" of great help, to add CSRF protection into a web application that uses Spring (Security, among others) implementing a REST API that's used by an AngularJS application. The AngularJS application uses form-based login (<code>JSESSIONID</code>) for authentication. Here's the essence of that work:</p>
  
  <ul>
  <li>Hidden input field <code>_csrf</code> on the login page</li>
  <li><code>CsrfHeaderFilter</code> adds <code>XSRF-TOKEN</code> cookie to response</li>
  <li><code>HttpSessionCsrfTokenRepository</code> with <code>setHeaderName("X-XSRF-TOKEN")</code></li>
  </ul>
  
  <p>This <strong>all does work fine</strong> (as far as I can observe).</p>
  
  <p>I believe this leads to the following flow:</p>
  
  <ol>
  <li>Redirect to login page</li>
  <li>Login page contains <code>_csrf</code></li>
  <li>Login response includes <code>XSRF-TOKEN</code> cookie</li>
  <li>Angular uses cookie value as <code>X-XSRF-TOKEN</code> header on REST requests</li>
  <li>Happiness!</li>
  </ol>
  
  <p>Number 2. seems vanilla Spring Security CSRF. 3. and 4. seem <a href="https://spring.io/blog/2015/01/12/the-login-page-angular-js-and-spring-security-part-ii" rel="nofollow">an attempt</a> to adapt to <a href="https://docs.angularjs.org/api/ng/service/$http" rel="nofollow">AngularJS CSRF support</a>.</p>
  
  <p>Again, this <strong>all does work fine</strong>, from testing a staging instance. However, some <strong>integration tests are broken</strong>, specifically tests that are using RestAssured. I have not found good examples for RestAssured, of this set-up. <a href="https://github.com/rest-assured/rest-assured/wiki/Usage#csrf" rel="nofollow">This</a> is all the documentation I can find.</p>
  
  <p>It suggests using <code>formAuthConfig().withAutoDetectionOfCsrf()</code> or <code>withCsrfFieldName("_csrf")</code>, and doing an explicit <code>get</code> of the login page. Using this seems to be dealing <strong>fine</strong> with the login. But I don't understand how I then tell RestAssured to pivot to using the <code>X-XSRF-TOKEN</code> header.</p>
  
  <p>I've unsuccessfully gone through a lot of variations of this code, but I'm currently having this:</p>
  
  <pre><code>    FormAuthConfig baseConfig = new FormAuthConfig(loginPage, "username", "password");
      FormAuthConfig config = baseConfig.sendCsrfTokenAsHeader();
      config = config.withCsrfFieldName("X-XSRF-TOKEN");
      RestAssured.authentication = RestAssured.form(userName, password, config);
  
      given().auth().form("admin", "admin", baseConfig.withCsrfFieldName("_csrf"))
          .when().get(loginPage)
          .then().statusCode(200);
  
      expect().statusCode(200)
          .when().get(...); // line 246
  </code></pre>
  
  <p>This is awarded with the following output:</p>
  
  <pre><code>&lt;html&gt;
    &lt;head&gt;
      &lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/&gt;
      &lt;title&gt;Error 401 Unauthorized&lt;/title&gt;
    &lt;/head&gt;
    &lt;body&gt;
      &lt;h2&gt;HTTP ERROR 401&lt;/h2&gt;
      &lt;p&gt;Problem accessing /application_name/rest/something. Reason:
  &lt;/p&gt;
      &lt;pre&gt;    Unauthorized&lt;/pre&gt;
      &lt;hr/&gt;
      &lt;i&gt;
        &lt;small&gt;Powered by Jetty://&lt;/small&gt;
      &lt;/i&gt;
      &lt;hr/&gt;
    &lt;/body&gt;
  &lt;/html&gt;
  
  java.lang.IllegalArgumentException: Couldn't find the CSRF input field with name X-XSRF-TOKEN in response. Response was:
  &lt;html&gt;
    &lt;head&gt;
      &lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/&gt;
      &lt;title&gt;Error 401 Unauthorized&lt;/title&gt;
    &lt;/head&gt;
    &lt;body&gt;
      &lt;h2&gt;HTTP ERROR 401&lt;/h2&gt;
      &lt;p&gt;Problem accessing /application_name/rest/something. Reason:
  &lt;/p&gt;
      &lt;pre&gt;    Unauthorized&lt;/pre&gt;
      &lt;hr/&gt;
      &lt;i&gt;
        &lt;small&gt;Powered by Jetty://&lt;/small&gt;
      &lt;/i&gt;
      &lt;hr/&gt;
    &lt;/body&gt;
  &lt;/html&gt;
  
      at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
      at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
      at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
      at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
      at org.codehaus.groovy.reflection.CachedConstructor.invoke(CachedConstructor.java:80)
      at org.codehaus.groovy.reflection.CachedConstructor.doConstructorInvoke(CachedConstructor.java:74)
      at org.codehaus.groovy.runtime.callsite.ConstructorSite$ConstructorSiteNoUnwrap.callConstructor(ConstructorSite.java:84)
      at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallConstructor(CallSiteArray.java:60)
      at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:235)
      at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:247)
      at com.jayway.restassured.internal.filter.FormAuthFilter.filter(FormAuthFilter.groovy:85)
      at com.jayway.restassured.filter.Filter$filter.call(Unknown Source)
      at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
      at com.jayway.restassured.filter.Filter$filter.call(Unknown Source)
      at com.jayway.restassured.internal.filter.FilterContextImpl.next(FilterContextImpl.groovy:49)
      at com.jayway.restassured.filter.FilterContext$next.call(Unknown Source)
      at com.jayway.restassured.internal.RequestSpecificationImpl.invokeFilterChain(RequestSpecificationImpl.groovy:994)
  &lt;snip&gt;
      at com.jayway.restassured.internal.ResponseSpecificationImpl.get(ResponseSpecificationImpl.groovy)
      at com.company.application_name.AbstractJettyJsonRestTest.getCollection(AbstractJettyJsonRestTest.java:246)
      at com.company.application_name.JsonRestIntegrationTest.testSomething(JsonRestIntegrationTest.java:74)
  &lt;snip&gt;
      at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)
  </code></pre>
  
  <p>Your help much appreciated!</p>