I have a SpringBoot application running on Java 17 with Maven, using SpringBoot 3.2.4 and Spring Security 6. I've deployed it on Railway along with a MySQL database. The deployment is successful, but I'm facing an issue where POST requests are not working while GET requests are functioning properly. In my local everythings works perfect but in Railway POST requests are not working. Below is my code of my SecurityConfig with SecurityFilterChain:
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig {
private final JwtUtils jwtUtils;
public SecurityConfig(final JwtUtils jwtUtils) {
this.jwtUtils = jwtUtils;
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
return httpSecurity
.csrf(AbstractHttpConfigurer::disable)
.cors(AbstractHttpConfigurer::disable)
.httpBasic(Customizer.withDefaults())
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(http -> {
// public endpoints
http.requestMatchers(HttpMethod.POST, "/api/v1/auth/sign-up").permitAll();
http.requestMatchers(HttpMethod.POST, "/api/v1/auth/log-in").permitAll();
http.requestMatchers(HttpMethod.POST, "/api/v1/auth/new-password").permitAll();
http.requestMatchers(HttpMethod.POST, "/api/v1/auth/test").permitAll();
http.requestMatchers(HttpMethod.POST, "/api/v1/auth/test-body").permitAll();
http.requestMatchers(HttpMethod.GET, "/api/v1/auth/test").permitAll();
// private endpoints
http.requestMatchers(HttpMethod.POST, "/api/v1/auth/unlock").hasRole("GERENTE");
})
.addFilterBefore(new JwtTokenValidator(jwtUtils), BasicAuthenticationFilter.class)
.build();
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
@Bean
public AuthenticationProvider authenticationProvider(UserDetailsServiceImpl userDetailsService) {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setPasswordEncoder(passwordEncoder());
provider.setUserDetailsService(userDetailsService);
return provider;
}
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
}
This is my production enviroment in Railway: Architecture
Logs when I try POST request and from Postman I get a 401 code: Observability
I have tried enabling and disabling CORS and CSRF, but it's not working for me. I want to understand why I'm encountering this error and what I need to add, enable, or disable to make my POST requests work.
UPDATE
Adding the request matcher: http.requestMatchers(HttpMethod.OPTIONS, "/**").permitAll(); And using https:// insted of http:// solve the problem
To resolve the issue with POST requests not working in your Railway deployment, you can try the following solutions in your code:
Explicitly Allow OPTIONS Requests: Sometimes, issues with CORS (Cross-Origin Resource Sharing) can cause problems with POST requests. Ensure that your application allows OPTIONS requests, which are often pre-flight requests sent by browsers to check if the server allows the actual request. Add .requestMatchers(HttpMethod.OPTIONS, "/**").permitAll() to your authorizeHttpRequests method.
Update CSRF Configuration: Although you have already disabled CSRF protection in your SecurityConfig, it's worth double-checking that it's disabled in all parts of your application. Ensure that CSRF protection is disabled globally by adding .csrf().disable() to your httpSecurity configuration.
Check for Redirects: Sometimes, redirects can cause issues with POST requests, especially when they change the request method. Ensure that your application is not redirecting POST requests to another endpoint that requires authentication. You can configure Spring Security to ignore certain URLs for redirection by using .permitAll() for those URLs.
Inspect Authentication and Authorization: Double-check your authentication and authorization logic to ensure that users are correctly authenticated and authorized to access the POST endpoints. Verify that the JWT tokens are being generated and parsed correctly, and that the roles/permissions are properly assigned to users.
Logging and Debugging: Add more logging statements to your application to track the flow of requests and identify any errors or unexpected behavior. Use debug mode in your IDE or logging frameworks like Logback or Log4j to get detailed information about what's happening inside your application.
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final JwtUtils jwtUtils;
public SecurityConfig(final JwtUtils jwtUtils) {
this.jwtUtils = jwtUtils;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.cors().disable()
.httpBasic(Customizer.withDefaults())
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeRequests(authorize -> authorize
.antMatchers(HttpMethod.POST, "/api/v1/auth/sign-up").permitAll()
.antMatchers(HttpMethod.POST, "/api/v1/auth/log-in").permitAll()
.antMatchers(HttpMethod.POST, "/api/v1/auth/new-password").permitAll()
.antMatchers(HttpMethod.POST, "/api/v1/auth/test").permitAll()
.antMatchers(HttpMethod.POST, "/api/v1/auth/test-body").permitAll()
.antMatchers(HttpMethod.GET, "/api/v1/auth/test").permitAll()
.antMatchers(HttpMethod.POST, "/api/v1/auth/unlock").hasRole("GERENTE")
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll() // Allow OPTIONS requests
.anyRequest().authenticated()
)
.addFilterBefore(new JwtTokenValidator(jwtUtils), BasicAuthenticationFilter.class);
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
@Bean
public AuthenticationProvider authenticationProvider(UserDetailsServiceImpl userDetailsService) {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setPasswordEncoder(passwordEncoder());
provider.setUserDetailsService(userDetailsService);
return provider;
}
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
}
These changes should help ensure that your POST requests work correctly in your Railway deployment. Make sure to test thoroughly after making these modifications. If the issue persists, continue debugging and investigating other potential causes.