https://kotlinlang.org logo
Title
j

Julius

05/27/2022, 2:53 PM
Is there an example on how to do websockets with authentication on ktor 2.0.0 somewhere? 🙂 I'm using Firebase authentication in a custom plugin right now (it uses a Baerer Token), I'm currently assuming I have to do a http call first to establish session authentication?
To iterate, it seems it was possible before to add headers to the initial websocket http request according to this stackoverflow post. But my code doing the same isn't sending the headers (I'm looking at the request data with wireshark):
client.webSocket(
                method = HttpMethod.Get,
                host = "localhost",
                port = 8080,
                path = "/ws",
                request = {
                    header(
                        "My-Test-Header",
                        "My-Test-Header-Value"
                    )
                }
            ) {
                send(Frame.Text("Hello from client"))
                while (true) {
                    val othersMessage = incoming.receive() as? Frame.Text
                    println(othersMessage?.readText())
                    val othersMessageText = othersMessage?.readText()
                    if (othersMessageText == "close") {
                        break
                    }
                    val myMessage = "Answer"
                    send(Frame.Text(myMessage))
                }
            }
It should at least allow the
Sec-WebSocket-Protocol
header since that's part of the spec it seems.
a

Aleksei Tirman [JB]

05/30/2022, 9:15 AM
I’ve checked that the
My-Test-Header
header is actually sent while using the code from your example. I observe the same behavior with the
Sec-WebSocket-Protocol
header.
j

Julius

05/30/2022, 12:53 PM
@Aleksei Tirman [JB] Thanks a lot! Could you send me the code you used? It must mean I'm doing something wrong at a different place 😔
a

Aleksei Tirman [JB]

05/30/2022, 12:55 PM
I’ve used this part of your code:
client.webSocket(
                method = HttpMethod.Get,
                host = "localhost",
                port = 8080,
                path = "/ws",
                request = {
                    header(
                        "My-Test-Header",
                        "My-Test-Header-Value"
                    )
                }
            )
j

Julius

05/30/2022, 12:59 PM
@Aleksei Tirman [JB] Oh I meant the complete code example, just in case I messed up imports or dependencies, but I can also try to make a minimal reproducible example ✌️
@Aleksei Tirman [JB] I made a reproducible example: https://github.com/MinmoTech/ktor-websockets-test It's run with
./gradlew browserDevelopmentRun
and automatically creates the websocket connection on browser load
Wireshark capture of the request
Could the issue be that I'm making the request from the browser?
a

Aleksei Tirman [JB]

05/30/2022, 5:19 PM
Yes. There is no way to send custom headers with an initial Websockets request in the browser environment. Also, there is this bug in Ktor that prevents from sending protocols via the
Sec-WebSocket-Protocol
header.
j

Julius

05/30/2022, 6:35 PM
Thanks! Then I'll look into transmitting the info that I need through cookies ✌️
On that note, is it possible to send arbitrary cookies with the initial websockets request in the browser environment?
a

Aleksei Tirman [JB]

05/30/2022, 6:46 PM
I don’t think you can send arbitrary cookies.
j

Julius

05/30/2022, 6:52 PM
fun createWebsocket() {
    GlobalScope.launch {
        val client = HttpClient(
            {
                install(WebSockets) {
                }
            }
        )
        println("Starting websocket")
        client.webSocket(
            method = HttpMethod.Get,
            host = "localhost",
            port = 8080,
            path = "/ws",
            request = {
                cookie(
                    name = "user_name",
                    value = "jetbrains",
                    expires =
                    GMTDate(
                        seconds = 0,
                        minutes = 0,
                        hours = 10,
                        dayOfMonth = 1,
                        month = Month.APRIL,
                        year = 2023
                    )
                )
            }
        ) {}
    }
}
Indeed this does not send the specified cookie. It does send all the cookies that are set in the browser session. Is that a requirement for sending cookies with websocket requests?
a

Aleksei Tirman [JB]

05/30/2022, 6:53 PM
I guess It’s a browser security restriction.
j

Julius

05/30/2022, 6:55 PM
A pity, since it now requires different implementations in my multiplatform project But thanks again for your help and sorry to take up so much of your time!