Jonas Helgemo
10/25/2022, 6:23 AM403
. A simple way to recreate the problem is running the example from the docs: https://github.com/ktorio/ktor-documentation/tree/main/codeSnippets/snippets/cors-backend:
package com.example
import io.ktor.http.*
import io.ktor.serialization.kotlinx.json.*
import io.ktor.server.application.*
import io.ktor.server.plugins.contentnegotiation.*
import io.ktor.server.plugins.cors.routing.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import kotlinx.serialization.*
import kotlinx.serialization.json.*
@Serializable
data class Customer(val id: Int, val firstName: String, val lastName: String)
fun Application.main() {
install(CORS) {
allowHost("0.0.0.0:8081")
allowHeader(HttpHeaders.ContentType)
}
val customerStorage = mutableListOf<Customer>()
install(ContentNegotiation) {
json(Json)
}
routing {
post("/customer") {
val customer = call.receive<Customer>()
customerStorage.add(customer)
call.respondText("Customer stored correctly", status = HttpStatusCode.Created)
}
}
}
and then run the following:
curl -H "Origin: <http://0.0.0.0:8081>" -H "Access-Control-Request-Method: POST" -H "Access-Control-Request-Headers: Origin, X-Requested-With" -X OPTIONS --verbose <http://localhost:8080/customer>
I don’t understand why this doesn’t give me a 2XX
response with correct preflight headers. I have looked everywhere for a solution, but to no avail. A similar thread and issue was discussed here: https://kotlinlang.slack.com/archives/C0A974TJ9/p1655722302810509, but this seems to be a slightly different case as the CORS-plugin is installed inside the routing-block where this is a known issue.
My current workaround is to add a catch-all OPTIONS-block, but this feels like a dirty hack as the response headers will not be correct in different cases. Any tips on how to fix this? Using 2.1.2 of Ktor and CORS-pluginJonas Helgemo
10/25/2022, 6:26 AM403
is returned. Remove the Origin-header and everything works as expected:
# Broken returns 403 🤔
curl --verbose -X "POST" "<http://localhost:8080/customer>" \
-H 'Origin: <http://localhost:8081>' \
-H 'Content-Type: application/json; charset=utf-8' \
-d '{"id": 1, "firstName": "Jonas", "lastName": "H"}'
# Works returns 201 🤯
curl --verbose -X "POST" "<http://localhost:8080/customer>" \
-H 'Content-Type: application/json; charset=utf-8' \
-d '{"id": 1, "firstName": "Jonas", "lastName": "H"}'
Jonas Helgemo
10/25/2022, 6:32 AMAleksei Tirman [JB]
10/25/2022, 8:01 AMlocalhost:8081
:
install(CORS) {
allowHost("localhost:8081")
allowHost("0.0.0.0:8081")
allowHost("127.0.0.1:8081")
allowHeader(HttpHeaders.ContentType)
}
Aleksei Tirman [JB]
10/25/2022, 8:10 AMOrigin
and X-Requested-With
headers:
allowHeader("X-Requested-With")
allowHeader(HttpHeaders.Origin)
Jonas Helgemo
10/25/2022, 10:36 AMJonas Helgemo
10/25/2022, 10:44 AMfun Application.main() {
install(CORS) {
allowHeader("X-Requested-With")
allowHeader(HttpHeaders.Origin)
allowHost("0.0.0.0:8081")
allowHeader(HttpHeaders.ContentType)
}
...
I still get a 403
with this: curl -H "Origin: <http://0.0.0.0:8081>" -H "Access-Control-Request-Method: POST" -H "Access-Control-Request-Headers: Origin, X-Requested-With" -X OPTIONS --verbose <http://localhost:8080/customer>
Jonas Helgemo
10/25/2022, 10:49 AM