CORS Servlet Filter Configuration: Complete Setup for Secure Java Web Applications

Quick Answer

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.

Need assistance organizing technical explanations for coursework or documentation?

If you need help refining structure, clarifying Java concepts, or improving explanations under a deadline, an external editor may help streamline the process.

Get structured feedback assistance

Why Browsers Block Cross-Origin Requests (Informational Intent)

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.

What Defines an Origin?

Component Example Must Match?
Protocol https Yes
Host api.example.com Yes
Port 8080 Yes

Changing any of these creates a new origin.

How a Servlet Filter Handles CORS (Informational Intent)

Servlet filters intercept requests before they reach controllers or servlets.

The lifecycle:

  1. Request arrives.
  2. CORS filter checks Origin header.
  3. Headers are attached.
  4. OPTIONS requests are resolved.
  5. Other filters continue execution.
  6. Servlet processes business logic.

Basic Filter Example

@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);
}
}

Understanding Every CORS Header (Informational Intent)

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

Production-Ready Configuration (Informational Intent)

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);

}
}

What Actually Matters When Configuring CORS

Priority 1: Allowed Origins

Never start with wildcards. Explicit domains provide stronger control.

Priority 2: Credentials

Cookies require additional restrictions.

Priority 3: Filter Position

The CORS filter should execute before authentication logic.

Priority 4: OPTIONS Requests

Authentication systems frequently block preflight requests.

Priority 5: Environment Separation

Development and production should use different origin lists.

How Preflight Requests Work (Informational Intent)

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.

Example

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

Development vs Production Environments (Informational Intent)

Environment Allowed Origins Recommendation
Local localhost:3000 Temporary access
Testing staging domain Restrict team access
Production Official domains only Strict validation

Statistics Developers Often Overlook

Working under a deadline and need help polishing technical explanations?

You can get guidance for improving documentation flow, clarifying code examples, or organizing larger assignments.

Get editing and explanation support

Common Mistakes Developers Make (Informational Intent)

Using Wildcards Everywhere

Access-Control-Allow-Origin: *

This is unsafe for authenticated applications.

Forgetting OPTIONS

Requests fail before reaching controllers.

Blocking Authentication Headers

JWT tokens stop working.

Ignoring Vary Header

CDN caching becomes inconsistent.

Running CORS Too Late

Authentication exceptions appear before CORS executes.

What Others Rarely Mention

Checklist: Production Deployment

Checklist: Security Review Before Release

Brainstorming Questions for Architecture Planning

Deep Technical Explanation: How the Entire Flow Works

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.

Combining CORS With JWT Authentication

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.

Reverse Proxy Considerations

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

Five Practical Recommendations

  1. Keep origin lists externalized in properties files.
  2. Avoid wildcards in production.
  3. Cache preflight responses.
  4. Log denied origins.
  5. Review configuration quarterly.

Need complete assistance organizing technical assignments or documentation packages?

When deadlines become difficult, additional support can help with structure, consistency, and final polishing.

Get full workflow assistance

Frequently Asked Questions

1. What is CORS?

CORS is a browser mechanism that controls cross-origin communication.

2. Why use a servlet filter?

It centralizes configuration.

3. Is CORS a security feature?

It protects browser users, not servers.

4. Can Postman bypass CORS?

Yes.

5. Should I use a wildcard?

Not in production.

6. Why do OPTIONS requests appear?

They are preflight validations.

7. Why does JWT authentication fail?

OPTIONS requests may be blocked.

8. Can mobile apps ignore CORS?

Yes.

9. What is the Vary header?

It prevents caching issues.

10. Should localhost exist in production?

No.

11. Where should the filter be placed?

Near the beginning of the chain.

12. Can multiple domains be allowed?

Yes, through a whitelist.

13. Should I cache preflight requests?

Usually yes.

14. What if browsers still block requests?

Inspect response headers and verify Origin values.

15. How do I organize technical explanations for coursework?

Break the system into request flow, security flow, and deployment flow. If additional editorial support is needed, you can continue with structured guidance through technical writing assistance.

16. Is CORS enough to secure APIs?

No. Authentication and authorization remain necessary.