CORS
Cross-Origin Resource Sharing allows to control
which resources browsers are allowed to access and how they are allowed to do so. For example, if you would like
to access a webservice from a website hosted on another domain, the browser will
send the Origin header along with requests to the webservice and analyze the response to determine, whether the server
allows clients to access the resource from this origin.
To allow all clients to access a resource with no restrictions, you can add a permissive policy to your handler:
import org.genhttp.modules.layouting.Layout
import org.genhttp.modules.security.CorsPolicy
import org.genhttp.modules.webservices.ResourceMethod
import org.genhttp.modules.webservices.addService
class BookResource {
@ResourceMethod
fun list(): List<String> = listOf("Dune", "Hyperion")
}
class AuthorResource {
@ResourceMethod
fun list(): List<String> = listOf("Frank Herbert", "Dan Simmons")
}
val api = Layout.create()
.addService<BookResource>("books")
.addService<AuthorResource>("authors")
.add(CorsPolicy.permissive())This will set the required headers for requests as well as preflight requests (which are answered
with 204 No Content). By default, the permissive policy allows the Authorization header to be sent -
pass allowAuthorization = false to leave it out. To restrict the access
to a specific origin, create a restrictive() policy and add the configuration for the desired origin:
val policy = CorsPolicy.restrictive()
.add("https://mydomain.com", allowedMethods = null, allowedHeaders = null, exposedHeaders = null, allowCredentials = true)
val api = Layout.create()
.add(policy)Passing null for the methods or headers allows any of them. Instead of these arguments, you may also
pass an OriginPolicy, which additionally specifies how long browsers may cache the policy (maxAge
in seconds, a day by default).
This way, browsers will deny requests that do not originate from https://mydomain.com. For development
purposes, you may combine the snippets above - as Kotlin has no preprocessor directives, decide at runtime,
e.g. by an environment variable:
val development = System.getenv("APP_ENVIRONMENT") == "development"
val policy = if (development) {
CorsPolicy.permissive()
} else {
CorsPolicy.restrictive().add("https://mydomain.com", null, null, null, true)
}