https://kotlinlang.org logo
#ktor
Title
# ktor
a

Amaan

12/16/2021, 10:09 PM
Is there a way to bypass JWT authentication during a small integration/unit test? I tried using the
createTestEnvironment
in which I install Authentication but use a mockk for the verifier and validator, but that doesn't work. I also tried using
JWT.require(NoneAlgorithm).build()
but that didn't work either since NoneAlgorithm can't be used outside of its package.
e

Emirhan Emmez

12/17/2021, 12:50 PM
I created an extension for all requests about this situation:
Copy code
fun TestApplicationEngine.handleRequestWithToken(
    method: HttpMethod,
    uri: String,
    setup: TestApplicationRequest.() -> Unit = {}
): TestApplicationCall {
    val token = handleRequest(<http://HttpMethod.Post|HttpMethod.Post>, "/login") {
        addHeader(HttpHeaders.ContentType, ContentType.Application.Json.toString())
        addHeader(HttpHeaders.Accept, ContentType.Application.Json.toString())
        setBody(Json.encodeToString(UserRequest("emirhan", "1234")))
    }.response.content

    val requestSetup: TestApplicationRequest.() -> Unit = {
        addHeader(HttpHeaders.ContentType, ContentType.Application.Json.toString())
        addHeader(HttpHeaders.Accept, ContentType.Application.Json.toString())
        addHeader(HttpHeaders.Authorization, "Bearer $token")
        setup.invoke(this)
    }
    return handleRequest(method, uri, requestSetup)
}
And the test method:
Copy code
withBaseTestApplication {
        handleRequestWithToken(HttpMethod.Get, "/user/1") {
            addHeader(HttpHeaders.UserAgent, "EMIRHAN-PC")
        }.apply {
            assertEquals("EMIRHAN-PC", response.headers[HttpHeaders.UserAgent])
            assertEquals(HttpStatusCode.OK, response.status())
    }
}
As you can see you can set default headers for all requests with this extension
and my withBaseTestApplication method for configuring features before all tests
Copy code
fun <T> withBaseTestApplication(test: TestApplicationEngine.() -> T) {
    withTestApplication {
        application.testModule()
    }
}
a

Amaan

12/17/2021, 7:29 PM
Thank you so much! This is exactly what I was looking for, and I just forgot about extension functions to provide this type of help. this is what I ended up with:
Copy code
fun <R> withTestMyApplication(
    moduleFunction: Application.() -> Unit,
    test: TestApplicationEngine.() -> R,
): R {
    return withTestApplication {
        application.apply {
            install(Authentication) {
                jwt("auth-jwt") {
                    verifier(Authenticator.verifier())
                    validate { Authenticator.validate(it) }
                }
            }

            moduleFunction()
        }
        test()
    }
}


fun TestApplicationEngine.handleAuthRequest(
    method: HttpMethod,
    uri: String,
    setup: TestApplicationRequest.() -> Unit = {},
): TestApplicationCall {

    val token = Authenticator.createToken()

    val requestSetup: TestApplicationRequest.() -> Unit = {
        addHeader(HttpHeaders.ContentType, ContentType.Application.Json.toString())
        addHeader(HttpHeaders.Accept, ContentType.Application.Json.toString())
        addHeader(HttpHeaders.Authorization, "Bearer $token")
        this.setup()
    }
    return this.handleRequest(method, uri, requestSetup)
👍 1
e

Emirhan Emmez

12/18/2021, 10:05 AM
I just wrote an article about this maybe it helps another developers: https://medium.com/@emirhanemmez/write-test-for-authenticated-requests-in-ktor-630f2fd0ca25
6 Views