1

We have a fully-working back-end login POST service, implemented using Spring Security, along with Spring Boot and Spring Session. A user needs to be logged-in in order to access other services. The login operation works, and so does the mechanism to restrict/allow access to the other services. This has been tested with Postman, which is "smart enough" to keep the session cookie on successive requests.

Now, we are trying to build the client on React. When using the browser's debug we can see the session cookie is sent in the response header without problems. We were trying to get the session cookie from the header and store it for successive requests, but it doesn't work. When investigating we learnt we are not meant to read the response header from the code, as explained here and here.

Our login operation should redirect to /customer/home, which works in Postman but not on our application. The behaviour we get with this is a 403 Forbidden, and the way we assess it is because the cookie is not set when redirecting, and hence the second operation (GET /customer/home) fails and returns 403. Is our understanding correct? However, the browser does not seem to keep the session cookie automatically. How are we supposed to maintain the session for subsequent requests if the cookie is not set automatically, and we are not supposed to read it manually? Are we supposed to NOT use cookies for this purpose, and issue authentication tokens instead?

We are obviously misunderstanding or missing something. Any pointers please?

Our WebSecurityConfigurerAdapter:

@EnableWebSecurity
@Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private AuthenticationProviderService authenticationProviderService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                    .antMatchers("/customer/register").permitAll()
                    .anyRequest().fullyAuthenticated()
                    .and()
                .formLogin()
                    .permitAll()
                    .defaultSuccessUrl("/customer/home", false)
                    .and()
                .logout()
                    .permitAll()
                    .and()
                .httpBasic();
        http.csrf().disable();
    }
//[ . . . ]
}

Our client trying to do a POST:

const mw = store => next => action => {

  if(action.type == 'SUBMIT_LOGIN_USER') {

    var payload = {
      username: action.user.username,
      password: action.user.password
    };

      // Build formData object.
    let formData = new FormData();
    formData.append('username', action.user.username);
    formData.append('password', action.user.password);


    return fetch('http://192.168.0.34:8080/login', {
      method: 'POST',
      body: formData
    }).then(
      r => (r)
    )
    .then(function(response) {
      console.log(document.cookie) //empty
      console.log(response.headers.get('Set-Cookie')) //null
      next(action)
    })
    .catch(function(err) {
      console.info(err);
    });
  } else {
    next(action)
  }
}
bohemian
  • 149
  • 2
  • 17

1 Answers1

0

Using JWT (JSON Web Tokens) is a great way to implement security on single page applications like React.

If you're going with the JWT approach it would be efficient to use a package like axios to for http requests from the client side. Axios allows you to easily add an authorization token to all requests without hassle.

Even if you're not using JWT try using axios to send authorization tokens efficiently.

Corey Potts
  • 3
  • 1
  • 2
Muljayan
  • 3,588
  • 10
  • 30
  • 54
  • Thanks for your answer. The question is more about what conceptual mistake we are making. Could you expand on how JWT and Axios can help us with our particular problem? – bohemian Jan 19 '19 at 09:14
  • 1
    With axios you can set authorization tokens into the header once and easily make sure all requests are authenticated . As for JWTs, most single page application frameworks use it as the frontend and backend are decoupled. You can check the comparison between server and cookies here. https://dzone.com/articles/cookies-vs-tokens-the-definitive-guide – Muljayan Jan 20 '19 at 08:27
  • Thanks for he recommendation, we will have a look. Up-vote for effort, but you are not really answering the question, which is: what is the theoretical procedure for cookie-based authentication? We are using Spring Security and don't want to re-invent the wheel. – bohemian Jan 20 '19 at 09:39
  • So the issue is the cookie is not being stored on subsequent requests right ? have you tried to store the cookie on the redux store ? There is a possibility for the cookie to be destroyed when the page reloads. Is such a situation happening ? – Muljayan Jan 20 '19 at 09:53
  • Yes, the problem seems to be the cookie not being stored. As explained above, we are not meant to read the cookie from the response header (bad and unsafe practice), so how are we supposed to store it? – bohemian Jan 20 '19 at 10:45
  • 1
    Oh alright. Ill check on it and let you know if i come across a working answer. Also to your comment about spring security, you can do some configurations to spring security to implement jwt auth. I know this because our team uses spring security and react with jwt auth for one of our projects. – Muljayan Jan 20 '19 at 11:08