Best Practices For Setting Up Cors With Geoserver And Jetty
Understanding CORS
CORS (Cross-Origin Resource Sharing) is a mechanism that allows resources on a web page to be requested from another domain outside of the domain the resource originated from. This is necessary for GeoServer since web maps served by GeoServer are often consumed by web apps on different domains.
Without CORS, browsers restrict cross-origin HTTP requests initiated from scripts for security reasons under the same-origin policy. CORS provides a secure way to allow servers to relax this restriction.
In GeoServer, CORS works by adding new HTTP headers that indicate the server explicitly allows cross-origin access to certain resources. When a browser receives these headers, it knows it is safe to allow the web app to access the GeoServer resources and make cross-origin AJAX requests.
How CORS Works in GeoServer
When a browser loads a web page from Domain A but the page contains a script that makes an AJAX request to Domain B, the following CORS communication happens:
- The script in Domain A initiates a cross-origin request to a resource in Domain B. This initial request contains no special CORS headers.
- The server at Domain B checks if the origin domain making the request is allowed. If so, the response contains an
Access-Control-Allow-Origin
header listing Domain A as allowed. - The browser sees Domain A is allowed, and lets the script access the response. Any future requests also contain an
Origin
header indicating which domain initiated it. - If any preflight OPTIONS requests are needed, the script sends them with
Origin
andAccess-Control-Request-Method
headers. The server approves them by sending back appropriate CORS response headers before the actual request is sent.
This handshake allows cross-origin requests to be made safely while protecting resources from unauthorized access by malicious sites. GeoServer can be configured to enable CORS access to some or all its web resources.
Enabling CORS in GeoServer
By default CORS is disabled in GeoServer. To enable it globally, set the CORS flag to true in geoserver/WEB-INF/web.xml
:
<context-param>
<param-name>ENABLE_CORS</param-name>
<param-value>true</param-value>
</context-param>
With CORS enabled globally, the Access-Control-Allow-Origin
header will contain a ‘*’ allowing all origins by default. This can be restricted by providing a comma-separated list of allowed origins instead:
<context-param>
<param-name>ALLOWED_ORIGINS</param-name>
<param-value>http://app.example.com,http://www.example.com</param-value>
</context-param>
The allowed methods and headers can also be configured. See the GeoServer CORS docs for details.
Configuring CORS with Jetty
If GeoServer is running on the Jetty server, Jetty provides additional CORS configuration options. A web app can create a org.eclipse.jetty.servlets.CrossOriginFilter
to explicitly control CORS headers.
For example, this filter allows GET and POST requests from any origin to paths starting with /api
:
<webApp>
<filter>
<filter-name>cross-origin</filter-name>
<filter-class>org.eclipse.jetty.servlets.CrossOriginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>cross-origin</filter-name>
<url-pattern>/api/*</url-pattern>
</filter-mapping>
</webApp>
The filter can then be configured for allowed origins, methods, headers and other CORS options:
<init-param>
<param-name>allowedOrigins</param-name>
<param-value>http://api.example.com</param-value>
</init-param>
<init-param>
<param-name>allowedMethods</param-name>
<param-value>GET,POST</param-value>
</init-param>
See Jetty’s CORS filter docs for details on all the available options.
Example Configuration Code
Here is an example CORS configuration in Jetty’s web.xml
allowing the origin http://app.example.com
to make GET and POST requests to /api
endpoints:
<filter>
<filter-name>CORS</filter-name>
<filter-class>org.eclipse.jetty.servlets.CrossOriginFilter</filter-class>
<init-param>
<param-name>allowedOrigins</param-name>
<param-value>http://app.example.com</param-value>
</init-param>
<init-param>
<param-name>allowedMethods</param-name>
<param-value>GET,POST</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CORS</filter-name>
<url-pattern>/api/*</url-pattern>
</filter-mapping>
The allowedOrigins
and allowedMethods
can also use wildcards for flexible filtering rules:
<init-param>
<param-name>allowedOrigins</param-name>
<param-value>http://*.example.com</param-value>
</init-param>
<init-param>
<param-name>allowedMethods</param-name>
<param-value>*</param-value>
</init-param>
Troubleshooting CORS Issues
If you have enabled CORS but web apps are still blocked from accessing GeoServer cross-origin, check for the following issues:
- Verify all endpoints require CORS headers. APIs usually need it but basic HTML pages may not.
- Check the browser console for CORS errors. Preflight request failures will be reported.
- Try allowing all origins and methods temporarily to test. Add restrictions later once it works.
- Set the allowed methods to GET/POST/OPTIONS instead of just GET/POST.
- Make sure custom headers and request types are allowed if used.
- If using sessions cookies, additional headers may be needed.
- For Jetty, ensure filter URL patterns match request paths.
See Common CORS Errors and Fixes for more troubleshooting tips.
Best Practices for CORS Security
While CORS enables useful cross-domain integrations, additional security practices should be used:
- Only allow trusted origins, not open access with *. Avoid NULL origin.
- Restrict CORS Origins to authorized domains and protocols only.
- Use short preflight cache duration headers for sensitive APIs.
- Require authentication for APIs exposed cross-origin.
- Set
Access-Control-Max-Age
as short as possible. - Limit use of wildcards in allowed origins and methods.
- Consider using CSRF tokens if exposing write operations.
- Avoid enabling CORS on pages with sensitive data.
Following these precautions ensures CORS remains secure. Test APIs thoroughly after configuring CORS to prevent policy weaknesses or logic issues being exposed cross-origin.