Search code examples
javaspringspring-bootspring-securityrailway

SpringBoot application on Railway: GET requests work but POST requests fail


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


Solution

  • 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.