* together with credentials.Applications built with Java Servlets often expose APIs consumed by React, Angular, Vue, mobile applications, or third-party systems. Browsers enforce a same-origin policy that blocks requests coming from unauthorized domains.
Without proper CORS configuration, frontend applications immediately encounter browser errors despite the backend functioning correctly.
A dedicated servlet filter solves this by centralizing cross-origin policies in one place.
If you're building a larger servlet architecture, it's helpful to combine this implementation with the homepage navigation at core servlet resources, JWT security flows at JWT security servlet filter implementation, authentication pipelines at servlet filter authentication examples, and observability through request and response logging filters.
If you need help refining structure, clarifying Java concepts, or improving explanations under a deadline, an external editor may help streamline the process.
Browsers isolate websites from one another for security reasons.
Without restrictions, a malicious website could silently read data from another application where the user is already authenticated.
For example:
These are different origins because the hostname differs.
The browser checks response headers before allowing JavaScript access.
If CORS headers are missing, access is denied.
| Component | Example | Must Match? |
|---|---|---|
| Protocol | https | Yes |
| Host | api.example.com | Yes |
| Port | 8080 | Yes |
Changing any of these creates a new origin.
Servlet filters intercept requests before they reach controllers or servlets.
The lifecycle:
@WebFilter("/*")
public class CorsFilter implements Filter {
@Override
public void doFilter(
ServletRequest req,
ServletResponse res,
FilterChain chain
) throws IOException, ServletException {
HttpServletRequest request =
(HttpServletRequest) req;
HttpServletResponse response =
(HttpServletResponse) res;
response.setHeader(
"Access-Control-Allow-Origin",
"https://frontend.example.com"
);
response.setHeader(
"Access-Control-Allow-Methods",
"GET,POST,PUT,DELETE,OPTIONS"
);
response.setHeader(
"Access-Control-Allow-Headers",
"Content-Type,Authorization"
);
chain.doFilter(request,response);
}
}
| Header | Purpose | Recommendation |
|---|---|---|
| Access-Control-Allow-Origin | Allowed domains | Whitelist origins |
| Access-Control-Allow-Methods | HTTP verbs | List required methods only |
| Access-Control-Allow-Headers | Custom headers | Allow Authorization |
| Access-Control-Allow-Credentials | Cookies/tokens | Enable only when necessary |
| Access-Control-Max-Age | Cache preflight | 3600 seconds |
public class CorsFilter
implements Filter {
private static final Set<String>
ALLOWED_ORIGINS = Set.of(
"https://app.example.com",
"https://admin.example.com"
);
@Override
public void doFilter(
ServletRequest req,
ServletResponse res,
FilterChain chain)
throws IOException,
ServletException {
HttpServletRequest request =
(HttpServletRequest) req;
HttpServletResponse response =
(HttpServletResponse) res;
String origin =
request.getHeader("Origin");
if(ALLOWED_ORIGINS.contains(origin)){
response.setHeader(
"Access-Control-Allow-Origin",
origin
);
response.setHeader(
"Access-Control-Allow-Credentials",
"true"
);
response.setHeader(
"Vary",
"Origin"
);
}
response.setHeader(
"Access-Control-Allow-Methods",
"GET,POST,PUT,PATCH,DELETE,OPTIONS"
);
response.setHeader(
"Access-Control-Allow-Headers",
"Authorization,Content-Type"
);
if("OPTIONS".equalsIgnoreCase(
request.getMethod()
)){
response.setStatus(200);
return;
}
chain.doFilter(request,response);
}
}
Never start with wildcards. Explicit domains provide stronger control.
Cookies require additional restrictions.
The CORS filter should execute before authentication logic.
Authentication systems frequently block preflight requests.
Development and production should use different origin lists.
The browser first sends an OPTIONS request.
This checks whether the server allows the upcoming operation.
The actual request only executes if approval is returned.
Frontend sends:
OPTIONS /api/users Origin: https://frontend.example.com Access-Control-Request-Method: POST Access-Control-Request-Headers: Authorization
The server answers:
Access-Control-Allow-Origin: https://frontend.example.com Access-Control-Allow-Methods: POST Access-Control-Allow-Headers: Authorization
| Environment | Allowed Origins | Recommendation |
|---|---|---|
| Local | localhost:3000 | Temporary access |
| Testing | staging domain | Restrict team access |
| Production | Official domains only | Strict validation |
You can get guidance for improving documentation flow, clarifying code examples, or organizing larger assignments.
Access-Control-Allow-Origin: *
This is unsafe for authenticated applications.
Requests fail before reaching controllers.
JWT tokens stop working.
CDN caching becomes inconsistent.
Authentication exceptions appear before CORS executes.
Imagine a React application hosted separately from the backend.
The browser automatically includes an Origin header.
The servlet filter reads it.
If trusted, the filter writes response headers.
If authentication is required, the browser checks whether credentials are permitted.
OPTIONS requests execute first.
The browser stores approved responses for a limited duration.
The actual request executes afterward.
Without the filter, JavaScript receives an error before application code runs.
This explains why backend logs may show successful processing while the user still sees failures.
JWT filters often execute before servlets.
If JWT blocks OPTIONS requests, browsers cannot proceed.
Always exempt OPTIONS:
if("OPTIONS".equalsIgnoreCase(
request.getMethod()
)){
response.setStatus(200);
return;
}
Then execute authentication afterward.
Systems such as Nginx, Apache, or cloud gateways may duplicate headers.
Avoid configuring CORS in multiple places simultaneously.
Choose one source of truth.
| Layer | Recommended Owner |
|---|---|
| Servlet | Application teams |
| Nginx | Infrastructure teams |
| Cloud Gateway | Platform teams |
When deadlines become difficult, additional support can help with structure, consistency, and final polishing.
CORS is a browser mechanism that controls cross-origin communication.
It centralizes configuration.
It protects browser users, not servers.
Yes.
Not in production.
They are preflight validations.
OPTIONS requests may be blocked.
Yes.
It prevents caching issues.
No.
Near the beginning of the chain.
Yes, through a whitelist.
Usually yes.
Inspect response headers and verify Origin values.
Break the system into request flow, security flow, and deployment flow. If additional editorial support is needed, you can continue with structured guidance through .
No. Authentication and authorization remain necessary.