5

all. I'm new to Spring Boot and Websocket. This is my first integrated React and Spring Boot project and I'm currently building a chat app with a backend using WebSocket.

As mentioned, my front end is built in React (localhost:3000), but when trying to call the backend/chat app, I get an error:

Access to XMLHttpRequest at 'http://localhost:9090/ws/info?t=1652731448126' from origin 'http://localhost:3000' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

I've tried looking up a few possible solutions, such as using @CrossOrigin(origins = "https://localhost:3000") and @CrossOrigin(origins = "http://localhost:3000") but that didn't change anything. I also tried (@CrossOrigin(origins = "*") with no luck. Both efforts resulted in the same error message.

Chat Controller:

package com.project2.chatapi.controller;

import com.project2.chatapi.models.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;

@CrossOrigin(origins = "https://localhost:3000")
@Controller
public class ChatController {

    @Autowired
    private SimpMessagingTemplate simpMessagingTemplate;

    /**
     * Handles messages coming into the public chatroom
     * @param message
     * @return message
     */
    @MessageMapping("/message")  // /app/message
    @SendTo("/chatroom/public")
    public Message receivePublicMessage(@Payload Message message) {
        return message;
    }

    /**
     * Handles messages being sent to a private chat
     * Receives the message from a user and sends to another user
     * @param message
     * @return message
     */
    @MessageMapping("/private-message")
    public Message receivePrivateMessage(@Payload Message message) {
        simpMessagingTemplate.convertAndSendToUser(message.getReceiverName(), "/private", message); // listens to /user/name/private
        return message;
    }
}

WebsocketConfig class:

package com.project2.chatapi.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;

@Configuration
@EnableWebSocketMessageBroker
public class WebsocketConfig implements WebSocketMessageBrokerConfigurer {

    /**
     * Adding endpoint to the chat
     * @param registry
     */
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/ws")
                .setAllowedOriginPatterns("http://localhost:3000")
                .withSockJS();
    }

    /**
     * Configuring application destination prefixes
     * Adding topic prefixes - chatroom, and user
     * @param registry
     */
    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.setApplicationDestinationPrefixes("/chat");
        registry.enableSimpleBroker("/chatroom","/user");
        registry.setUserDestinationPrefix("/user");
    }

    @Bean
    public WebMvcConfigurer corsConfig() {
        return new WebMvcConfigurer() {

            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**")
                        .allowedMethods("GET", "POST", "PUT", "DELETE")
                        .allowedHeaders("*")
                        .allowedOrigins("http://localhost:3000");
            }
        };
    }
}

React Method that calls the backend:

    const connect = (e) => {
        e.preventDefault();
        setUserData({...userData, "username": username});
        let Sock = new SockJS('http://localhost:9090/ws');
        stompClient = over(Sock);
        stompClient.connect({},onConnected, onError);
    }

I've also tried implementing different possible solutions regarding setAllowedOrigins. I've tried a handful of combinations including ("http://localhost:3000") and ("*")-- but again, it doesn't seem to change my error message.

I've been stuck on this for days now. Any help would be greatly appreciated. Thank you!

UPDATE: These are the additional things I've tried since posting this question originally. Unfortunately, I'm still getting the same errors with these attempts.

  1. I tried adding a filter
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class SimpleCORSFilter implements Filter {

    final Logger logger = LoggerFactory.getLogger(SimpleCORSFilter.class);

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
        logger.info("Initializing Middleware");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest requestToUse = (HttpServletRequest)servletRequest;
        HttpServletResponse responseToUse = (HttpServletResponse)servletResponse;

        responseToUse.setHeader("Access-Control-Allow-Origin",requestToUse.getHeader("Origin"));
        filterChain.doFilter(requestToUse,responseToUse);
    }

    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}
  1. I tried adding cors mapping in my config file
  2. Also tried adding a CorsConfirgurationSource to my config file
@Configuration
@EnableWebSocketMessageBroker
public class WebsocketConfig implements WebSocketMessageBrokerConfigurer {

    // can possibly delete
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("http://localhost:3000")
                .allowCredentials(false)
                .maxAge(3600)
                .allowedHeaders("Accept", "Content-Type", "Origin",
                        "Authorization", "X-Auth-Token")
                .exposedHeaders("X-Auth-Token", "Authorization")
                .allowedMethods("POST", "GET", "DELETE", "PUT", "OPTIONS");
    }

    /**
     * Adding endpoint to the chat
     * @param registry
     */
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/ws/*")
                .setAllowedOrigins("http://localhost:3000")
                .withSockJS();
    }

    /**
     * Configuring application destination prefixes
     * Adding topic prefixes - chatroom, and user
     * @param registry
     */
    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.setApplicationDestinationPrefixes("/chat");
        registry.enableSimpleBroker("/chatroom","/user");
        registry.setUserDestinationPrefix("/user");
    }
//
    @Bean
    public WebMvcConfigurer corsConfig() {
        return new WebMvcConfigurer() {

            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/ws/**")
                        .allowedMethods("GET", "POST", "PUT", "DELETE")
                        .allowedHeaders("*")
                        .allowedOrigins("http://localhost:3000");
            }
        };
    }

    @Bean
    CorsConfigurationSource corsConfigurationSource() {

        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        final CorsConfiguration configuration = new CorsConfiguration();
        configuration.setExposedHeaders(Arrays.asList("Authorization"));
        configuration.addAllowedOrigin("http://localhost:3000");
        configuration.addAllowedMethod("*");
        configuration.addAllowedHeader("*");
        configuration.applyPermitDefaultValues();
        return source;
    }
}
  1. adding the cors mapping and WebMvcConfigurer to my main app
    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/*").allowedOrigins("http://localhost:3000");
            }
        };
    }

enter image description here I've checked the network logs in my google chrome browser and it is still showing Access-Control-Allow-Origin: * despite all the configuration.

4
  • maybe change .allowCredentials(false) to .allowCredentials(true) since you already have the Authorization header set?
    – Normal
    May 18, 2022 at 18:30
  • or maybe this could help? stackoverflow.com/questions/32393519/…
    – Normal
    May 18, 2022 at 18:33
  • I'm currently not using JWT or a web token for this chat. So not fully applicable either. May 18, 2022 at 18:44
  • did you find a solution ? I am facing the same issue
    – thahgr
    Sep 29, 2022 at 8:38

2 Answers 2

3

this solved my problem

 @Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
    registry
    .setAllowedOrigins("http://localhost:3000") // not setAllowedOriginPatterns  
    .withSockJS();
}
0

In my case I solved it like this. As I am testing it locally for that reason it is the localhost, for production remove the localhost.

import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;

@Configurable
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    private String url = "http://localhost:4200";

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/chat-websocket")
        .setAllowedOrigins(url)
        .withSockJS();

    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.enableSimpleBroker("/chat/");
        registry.setApplicationDestinationPrefixes("/app");
    }

    @Bean
    WebMvcConfigurer corsConfig() {
        return new WebMvcConfigurer() {

            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/ws/**")
                .allowedMethods("GET", "POST", "PUT", "DELETE")
                .allowedHeaders("*")
                .allowedOrigins(url);
            }
        };
    }

}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.