I’m trying to implement an API with a JWT based authentication in Spring. In order to do that, I’m trying to set /login and /signup routes available without a JWT, but I keep having 403 errors when I try them.
Here’s my code for that ensures requests are authenticated :
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import static com.toto.api.Constants.BCRYPT_VERSION;
import static com.toto.api.Constants.BCRYPT_STRENGTH;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
private final UserDetailsService userDetailsService;
private final AuthenticationProvider authenticationProvider;
public SecurityConfig(UserDetailsService userDetailsService, AuthenticationProvider authenticationProvider) {
this.userDetailsService = userDetailsService;
this.authenticationProvider = authenticationProvider;
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http, AuthenticationManager authenticationManager) throws Exception {
return http
.cors(AbstractHttpConfigurer::disable)
.csrf(AbstractHttpConfigurer::disable)
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
.requestMatchers(HttpMethod.PUT, "/auth/**").permitAll()
.requestMatchers(HttpMethod.POST, "/auth/**").permitAll()
.anyRequest().authenticated())
.authenticationManager(authenticationManager)
.build();
}
@Bean
public AuthenticationManager authenticationManager(HttpSecurity http) throws Exception {
AuthenticationManagerBuilder authenticationManagerBuilder = http.getSharedObject(AuthenticationManagerBuilder.class);
authenticationManagerBuilder.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
return authenticationManagerBuilder.build();
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(BCRYPT_VERSION, BCRYPT_STRENGTH);
}
}
and here’s the auth controller :
import com.toto.api.security.JwtHelper;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;
import com.toto.api.core.records.LoginRequest;
import com.toto.api.core.records.LoginResponse;
@RestController
@RequestMapping(path="/auth", produces="application/json")
public class AuthController {
private final AuthenticationManager authenticationManager;
public AuthController(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
@PostMapping(path="/login", consumes="application/json")
public ResponseEntity<LoginResponse> login(@RequestParam LoginRequest request) {
try {
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(request.email(), request.password()));
} catch(BadCredentialsException e) {
return new ResponseEntity<>(null, HttpStatus.UNAUTHORIZED);
}
String token = JwtHelper.generateToken(request.email());
return new ResponseEntity<>(new LoginResponse(request.email(), token), HttpStatus.OK);
}
}
Here’s the result when I try it on Postman :
I can’t find what’s wrong or missing.