0

I'm building an API with Springboot and Springboot Security, alongside a frontend to interact with this API. I've tested all the endpoints which work fine in Postman, but when sending POST requests with Axios to the API (in my case, for the login request to generate the JWT), I'm receiving a 401 error, which is odd since there shouldn't be any authorization required for this request.

When trying to troubleshoot this, most posts were just issues from incorrectly passing the Auth token into the request, but that isn't the case here since the endpoint requires no auth token (see the successful postman request). I found other similar posts pointing out that it may be a cors related issue, but after tweaking the Controller to include the relevant @CrossOrigin annotation, and testing the results when exluding .cors() from filterChain, the issue persisted with little for me to utilize for troubleshooting.

SecurityFilterChain

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig {
    @Autowired
    private AuthEntryPointJwt authorizationHandler;
    @Autowired
    UserDetailsServiceImpl userDetailsService;

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.cors().and().csrf().disable().exceptionHandling().authenticationEntryPoint(authorizationHandler).and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests()
                .antMatchers("/api/v1/auth/**").permitAll()
                .antMatchers("/api/v1/reviews/**").permitAll()
                .antMatchers("/api/v1/test/**").permitAll().anyRequest().authenticated();

        http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);

        return http.build();
    }

    @Bean
    public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); }

    @Bean
    public AuthTokenFilter authenticationJwtTokenFilter() { return new AuthTokenFilter(); }

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }
}

Controller

@CrossOrigin(origins = "http://localhost:5173", maxAge = 3600)
@RestController
@RequestMapping("/api/v1/auth")
public class AuthController {
    @Autowired
    AuthenticationManager authenticationManager;
    @Autowired
    UserRepository userRepository;
    @Autowired
    PasswordEncoder encoder;
    @Autowired
    JwtUtils jwtUtils;

    @PostMapping("/signin")
    public ResponseEntity<?> authenticateUser(@RequestBody LoginRequest loginRequest) {

        Authentication authentication = authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword())
        );

        SecurityContextHolder.getContext().setAuthentication(authentication);
        String jwt = jwtUtils.generateJwtToken(authentication);
        UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();

        return ResponseEntity.ok(new JwtResponse(jwt, userDetails.getId(), userDetails.getUsername(), userDetails.getEmail()));
    }

auth.service.js

import axios from "axios";

const API_URL = "http://localhost:8080/api/v1/auth/";

export default class AuthService {
  login(username, password) {
    console.log(API_URL + "signin");
    console.log(username, password);
    return axios
      .post(API_URL + "signin", { username, password })
      .then((response) => {
        if (response.data.accessToken) {
          localStorage.setItem("user", JSON.stringify(response.data));
        }

        return response.data;
      });
  }

  logout() {
    localStorage.removeItem("user");
  }

  register(username, email, password) {
    return axios.post(API_URL + "signup", {
      username,
      email,
      password,
    });
  }
}

Successful Postman Request

Successful Postman Request

Unsuccessful Axios Request

Unsuccessful Axios Request

Request Headers (From Network Tab)

// GENERAL
Request URL: http://localhost:8080/api/v1/auth/signin
Request Method: POST
Status Code: 401
Remote Address: [::1]:8080
Referrer Policy: strict-origin-when-cross-origin

// RESPONSE HEADERS
HTTP/1.1 401
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Access-Control-Allow-Origin: http://localhost:5173
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Length: 0
Date: Tue, 27 Jun 2023 20:38:38 GMT
Keep-Alive: timeout=60
Connection: keep-alive

// REQUEST HEADERS
POST /api/v1/auth/signin HTTP/1.1
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8
Connection: keep-alive
Content-Length: 49
Content-Type: application/json
Host: localhost:8080
Origin: http://localhost:5173
Referer: http://localhost:5173/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36
sec-ch-ua: "Not.A/Brand";v="8", "Chromium";v="114", "Google Chrome";v="114"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"

I've tried to include as much information as I can but if there's anything else I can provide that I've missed out that'd help troubleshoot the issue, let me know.

hirw
  • 1
  • 1

1 Answers1

0

You should pass JSON-object in the body of POST-request:

return axios
  .post(API_URL + "signin", {"username":username,"password":password })
  .then((response) => {
    if (response.data.accessToken) {
      localStorage.setItem("user", JSON.stringify(response.data));
    }

    return response.data;
  });
yuri777
  • 377
  • 3
  • 7
  • This is probably better practice (and I should definitely have been formatting it like this), but it doesn't solve the issue, a 401 error is still returned. – hirw Jun 27 '23 at 21:49