- Using CORS in Built-in Services
Several built-in Helidon services — health, metrics, and OpenAPI — have integrated CORS support. You can include these services in your application and control their CORS behavior.
Understanding CORS Support in Helidon Services
Helidon lets you easily include health, metrics, and OpenAPI services in your Helidon application. These services add endpoints to your application so that clients can retrieve information about it. As with the application endpoints you write, these endpoints represent resources that can be shared across origins.
For example, several websites related to OpenAPI run a web application in your browser. You provide the URL for your application to the browser application. The browser application uses the URL to retrieve the OpenAPI document that describes the application’s endpoints directly from your application. The browser application then displays a user interface that you use to "drive" your application. That is, you provide input, have the web application send requests to your application endpoints, and then view the responses. This scenario is exactly the situation CORS addresses: an application in the browser from one origin — the user interface downloaded from the website — requests a resource from another origin — the /openapi endpoint which Helidon’s OpenAPI built-in service automatically adds to your application.
Integrating CORS support into these built-in services allows such third-party web sites and their browser applications — or more generally, apps from any other origin — to work with your Helidon application.
Because all three of these built-in Helidon services serve only GET endpoints, by default the integrated CORS support in all three services permits any origin to share their resources using GET, HEAD, and OPTIONS HTTP requests. You can customize the CORS set-up for these built-in services independently from each other using either the Helidon API, configuration, or both. You can use this override feature to control the CORS behavior of the built-in services even if you do not add CORS behavior to your own endpoints.
Getting Started
To use built-in services with CORS support and customize the CORS behavior:
- Add the built-in service or services to your application. The health, metrics, and OpenAPI services automatically include default CORS support.
Add a dependency on the Helidon SE CORS artifact to your Maven
pom.xmlfile.If you want the built-in services to support CORS, then you need to add the CORS dependency even if your own endpoints do not use CORS.
The Managing Dependencies page describes how you should declare dependency management for Helidon applications. For CORS support in Helidon SE, you must include the following dependency in your project:
<dependency> <groupId>io.helidon.webserver</groupId> <artifactId>helidon-webserver-cors</artifactId> </dependency>content_copy- Use the Helidon API or configuration to customize the CORS behavior as needed.
The documentation for the individual built-in services describes how to add each service to your application, including adding a Maven dependency and including the service in your application’s routing rules. In your application’s configuration file, the configuration for each service appears under its own key.
The Helidon SE QuickStart example uses these services, so you can use that as a template for your own application, or use the example project itself to experiment with customizing the CORS behavior in the built-in services.
Controlling CORS for Built-in Services Using the API
Although services such as health, metrics, and OpenAPI are built into Helidon, to use them your application must create instances of the services and then use those instances in building your application’s routing rules.
Recall that each service type has a Builder class. To control the CORS behavior of a built-in service using the API, follow these steps:
- Create a
Builderfor the type of service of interest. - Build an instance of
CrossOriginConfigwith the settings you want. - Invoke the
builder.crossOriginConfigmethod, passing thatCrossOriginConfiginstance. - Invoke the builder’s
buildmethod to initialize the service instance. - Use the service instance in preparing the routing rules.
The following excerpt shows changes to the Helidon SE QuickStart example which limit sharing of the /metrics endpoint to http://foo.com.
private static Routing createRouting(Config config) {
CrossOriginConfig.Builder metricsCrossOriginConfigBuilder = CrossOriginConfig.builder()
.allowOrigins("http://foo.com");
RestServiceSettings.Builder restServiceSettingsBuilder = RestServiceSettings.builder()
.crossOriginConfig(metricsCrossOriginConfigBuilder);
MetricsSupport metrics = MetricsSupport.builder()
.restServiceSettings(restServiceSettingsBuilder)
.build();
GreetService greetService = new GreetService(config);
HealthSupport health = HealthSupport.builder()
.addLiveness(HealthChecks.healthChecks()) // Adds a convenient set of checks
.build();
return Routing.builder()
.register(health) // Health at "/health"
.register(metrics) // Metrics at "/metrics"
.register("/greet", greetService)
.build();
}- Create the
CrossOriginConfig.Builderfor metrics, limiting sharing tohttp://foo.com. - Use the
CrossOriginConfig.Builderinstance in constructing theRestServiceSetting.Builder(which assigns common settings such as the CORS configuration and the web context for the service endpoint). - Use the
RestServiceSetting.Builderin preparing theMetricsSupportservice. - Use the
MetricsSupportobject in creating the routing rules.
Configuring CORS for Built-in Services
You can also use configuration to control whether and how each of the built-in services works with CORS.
Your application can pass configuration to the builder for each built-in service. For the health, metrics, and OpenAPI services, your configuration can include a section for CORS.
The following example restricts sharing of the /health resource, provided by the health built-in service, to only the origin http://there.com.
...
health:
cors:
allow-origins: [http://there.com]
...Modify your application to load the health config node and use it to construct the HealthSupport service. The following code shows this change in the the QuickStart SE example.
HealthSupport health = HealthSupport.builder()
.config(config.get("health"))
.addLiveness(HealthChecks.healthChecks()) // Adds a convenient set of checks
.build();- Use the
healthconfig section (if present) to configure the health service.
You have full control over the CORS configuration for a built-in Helidon service. Use a basic CORS config section as described in Using Configuration for CORS.
Accessing the Shared Resources
If you have edited the Helidon SE QuickStart application as described in the previous topics and saved your changes, you can build and run the application. Once you do so you can execute curl commands to demonstrate the behavior changes in the metric and health services with the addition of the CORS functionality. Note the addition of the Origin header value in the curl commands, and the Access-Control-Allow-Origin in the successful responses.
Build and Run the Application
Build and run the QuickStart application as usual.
mvn package
java -jar target/helidon-quickstart-se.jar
...
WEB server is up! http://localhost:8080/greetRetrieve Metrics
The metrics service rejects attempts to access metrics on behalf of a disallowed origin.
curl -i -H "Origin: http://other.com" http://localhost:8080/metrics
HTTP/1.1 403 Forbidden
Date: Mon, 11 May 2020 11:08:09 -0500
transfer-encoding: chunked
connection: keep-aliveBut accesses from foo.com succeed.
curl -i -H "Origin: http://foo.com" http://localhost:8080/metrics
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://foo.com
Content-Type: text/plain
Date: Mon, 11 May 2020 11:08:16 -0500
Vary: Origin
connection: keep-alive
content-length: 6065
# TYPE base_classloader_loadedClasses_count gauge
# HELP base_classloader_loadedClasses_count Displays the number of classes that are currently loaded in the Java virtual machine.
base_classloader_loadedClasses_count 3568
...Retrieve Health
The health service rejects requests from origins not specifically approved.
curl -i -H "Origin: http://foo.com" http://localhost:8080/health
HTTP/1.1 403 Forbidden
Date: Mon, 11 May 2020 12:06:55 -0500
transfer-encoding: chunked
connection: keep-aliveAnd responds successfully only to cross-origin requests from http://there.com.
curl -i -H "Origin: http://there.com" http://localhost:8080/health
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://there.com
Content-Type: application/json
Date: Mon, 11 May 2020 12:07:32 -0500
Vary: Origin
connection: keep-alive
content-length: 461
{"outcome":"UP",...}