I’m really struggling with the CORS plugin and pre...
# ktor
j
I’m really struggling with the CORS plugin and preflight requests, OPTION calls give me
403
. 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:
Copy code
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:
Copy code
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-plugin
Another weird problem that seems to be related is this: If you do a regular POST request to the API but include the Origin-header, a
403
is returned. Remove the Origin-header and everything works as expected:
Copy code
# 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"}'
Copy code
# 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"}'
I have tried adding every header under the sun to the CORS-configuration, nothing seems to work.
a
You can solve your latter problem by allowing
localhost:8081
:
Copy code
install(CORS) {
    allowHost("localhost:8081")
    allowHost("0.0.0.0:8081")
    allowHost("127.0.0.1:8081")
    allowHeader(HttpHeaders.ContentType)
}
To solve your former problem you need to allow the
Origin
and
X-Requested-With
headers:
Copy code
allowHeader("X-Requested-With")
allowHeader(HttpHeaders.Origin)
j
Cool, I’ll try it out and see if my problem is resolved 👍
So I have changed the code to this:
Copy code
fun 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>
Ahh, got it working, it was a problem with localhost vs 0.0.0.0 vs 127.0.0.1. Thanks 👍
843 Views