Adriano Júnior
← Artigos

Spring Boot

Contornando erro de CORS no Java com Spring Boot

Por que o navegador bloqueia chamadas entre origens diferentes, o que CORS realmente é (e não é), riscos de abrir tudo em produção — e como configurar CORS no Spring Boot com WebMvcConfigurer.

Você já estava montando um projeto pessoal, um MVP ou um teste para vaga e, ao ligar o front na API local, apareceu CORS?

O erro no console costuma ser parecido com:

Access to fetch at http://localhost:8080/api/... from origin http://127.0.0.1:5500 has been blocked by CORS policy: No Access-Control-Allow-Origin header is present on the requested resource.

Se estiver com prazo curto, pode ir direto à seção Spring Boot e depois volta aqui com calma para o “porquê”.

O que é CORS?

CORS (Cross-Origin Resource Sharing) é um mecanismo em que o servidor declara quais outras origens podem chamar a API a partir do navegador. O bloqueio que você vê é a política de mesma origem do browser + a ausência (ou restrição) desses cabeçalhos na resposta.

Ou seja: não é “bug do Java” nem “bug do React” primeiro — é o navegador exigindo que a API diga explicitamente quem pode consumir aquele recurso em requisições cross-origin.

Exemplo clássico

  • Front: http://localhost:3000 (ex.: React)
  • API: http://localhost:8080 (Spring Boot)

Origens diferentes (scheme, host ou porta mudou) ⇒ para fetch/XHR o browser faz o fluxo CORS (incluindo preflight em muitos casos). Se o backend não responder com as permissões corretas, a requisição falha no cliente mesmo que a API “funcione” se você chamar com Postman ou curl.

CORS “não é um erro”?

Em sentido estrito: é uma camada de segurança. O console chama de erro, mas o que acontece é o browser recusando expor a resposta ao seu JS porque o servidor não autorizou aquela origem.

Isso não diminui a dor no desenvolvimento — só ajuda a lembrar que a correção é configurar o servidor (e a política) com consciência, não “desligar segurança” no escuro.

Same-Origin Policy em uma frase

Por padrão, o browser limita o que uma página pode ler de outra origem. CORS é o jeito controlado de o servidor dizer: “estas origens podem acessar estes recursos, com estes métodos e cabeçalhos”.

Por que isso importa em produção?

Abrir CORS para “qualquer um” (* ou lista gigante sem critério) não substitui autenticação/autorização e pode aumentar superfície de abuso quando combinado com sessões/credenciais mal modeladas.

Pontos que o artigo original trazia e que continuam válidos:

  • CSRF e uso indevido de cookies/sessão em outro site — mitigação de verdade costuma envolver tokens anti-CSRF, SameSite, CORS restrito e desenho de API; CORS sozinho não “fecha” o problema.
  • Exposição de dados: se qualquer origem puder consumir endpoints sensíveis só porque o CORS está folgado, você facilita cenários ruins.
  • APIs sem camada de auth adequada: CORS não é substituto de JWT, OAuth, políticas de autorização, etc.

Em produção, o ideal é listar apenas origens confiáveis (ex.: https://www.seudominio.com).

Atenção

Não use Access-Control-Allow-Origin: * em produção quando há credenciais (cookies, Authorization em cenários sensíveis) — e, de modo geral, evite * para API que entrega dado sensível. Prefira origens explícitas.

Para origens dinâmicas (vários subdomínios, ambientes), dá para usar allowedOriginPatterns (Spring) com critério claro, em vez de “liberar o mundo”.


Como configurar CORS no Spring Boot

Crie uma classe de configuração que implementa WebMvcConfigurer e sobrescreva addCorsMappings.

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

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

O que cada parte faz:

  • addMapping: path da API (/** para tudo, ou prefixos como /api/**).
  • allowedOrigins: origens do front que podem chamar a API (troque pelos seus hosts reais).
  • allowedMethods: verbos HTTP permitidos no CORS.
  • allowedHeaders: cabeçalhos que o browser pode enviar (em dev, * é comum; em produção você pode restringir).
  • allowCredentials(true): necessário quando você usa cookies ou cenários que exigem credenciais na requisição cross-origin — lembre-se da regra: não combine * em Allow-Origin com credenciais; use origem explícita (como no exemplo).

Variante com padrão de origem (Spring Boot 2.4+)

Quando fizer sentido validar por padrão (ex.: subdomínios de um domínio seu), use allowedOriginPatterns em vez de listar dezenas de URLs fixas — ainda assim com critério, não *.

registry.addMapping("/api/**")
        .allowedOriginPatterns("https://*.seudominio.com")
        .allowedMethods("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS")
        .allowedHeaders("*")
        .allowCredentials(true);

Considerações finais

API costuma ser última linha antes do dado sensível: CORS é só uma peça do desenho — authN/authZ, validação, rate limit e modelo de sessão/token importam tanto quanto.

O objetivo aqui foi ir além de “copiar config e seguir”: entender por que o browser bloqueia, o que configurar no Spring e por que em produção a lista de origens deve ser enxuta e intencional.