3

I wish to use Spring Security (version 5.1.2) to generate a CSRF token for my Angular 7 application. I have the following in my SecurityConfig file:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.cors().and()
            .csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
}

with the following RequestMapping in my controller:

@RestController
@RequestMapping("/authentication")
public class AuthenticationController {

    @GetMapping("/csrf")
    public void getCsrfToken(){...}

    @PostMapping("/register")
    public RegisterOutputDTO register(@RequestBody UserDTO input){...}
}

I gathered from various sources that the csrfTokenRepository would automatically generate a cookie with header XSRF-token on my first GET call (which is what /authentication/csrf is for), but I am not getting a cookie back from the server. Hence on my next POST call I am getting a 403 response. What could I possibly be missing?

This is my output

3
  • It will only create cookie XSRF-TOKEN if it is missing. Look at the Request Headers to see if it is already present. Commented Feb 26, 2019 at 23:21
  • @Andreas I've thought of this as well, but I don't send any such token in the headers. I can see in the application tab of Chrome that the cookie does not exist. Commented Feb 27, 2019 at 16:24
  • 1
    I believe I may have found the answer. It appears that it is not possible to send a cookie cross-domain. My angular application is hosted on localhost:3000 and my Java backend is hosted on localhost:9080. It seems my options are to either deploy them on the same domain somehow or use a proxy. Source: stackoverflow.com/questions/48002670/… Commented Feb 27, 2019 at 17:21

1 Answer 1

1

As indicated on the comments to my question, I found the answer to my problem. A cookie can not be sent cross-domain.

My frontend was deployed on localhost:3000 and my backend on localhost:9080, which are considered different domains apparently. If I go to localhost:9080 (I get a white page, but that doesn't matter) and I then go to the application tab in Chrome, I find that the XSRF cookie I was looking for is stored like I was expecting all along. The cookie was available from the GET call I executed from my front-end. The problem is that the cookie needs to be available for localhost:3000 so that Angular can make use of the cookie.

There are multiple ways you can solve this issue in your local environment.

Use a proxy

You can use a proxy to map certain url paths to your backend. This is the solution I went with.

I run my Angular application with a webpack dev server. Webpack provides an easy way to proxy certain urls to your backend. For example:

devServer: {
    contentBase: path.join(__dirname, 'dist'),
    compress: true,
    port: 3000,
    proxy: {
        '/api': 'http://localhost:9080'
    }
}

The Angular application runs on localhost:3000. Any calls to localhost:3000/api/*. will be forwarded to localhost:9080/api/*. So in my case I no longer perform a GET call on localhost:9080/api/authentication/csrf, but I call localhost:3000/api/authentication/csrf which will then get forwarded to my backend. (I added /api to the path in my rest controller, for those wondering.)

Deploy both applications on the same port

Using the frontend-maven-plugin you can build the frontend to its dist folder and then let maven package the dist folder along with the backend for deploy. I haven't tried this, but there are various resources that show this should be easy to do with Spring boot. So both frontend and backend would be available through localhost:9080 for example.

Use Spring Profile to disable csrf locally

You can make use of Spring @Profile annotations to create a different configuration for local environment and the rest (test, acceptance, production). Csrf can simply be disabled for development. I do not prefer this option since I like to keep DEV and other environments the same as much as possible. It's also not a real answer to the problem statement.

Special thanks to the answer of user @dspies which helped me find the problem.

Sign up to request clarification or add additional context in comments.

1 Comment

I have a very similar setup in my local too, but Spring is sending the XSRF token, and Angular is sending it back to Spring just fine. I am very confused with this answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.