Last active
January 7, 2024 11:14
-
-
Save NyCodeGHG/12e8eddfd53e1f4d8e44b79957c1e319 to your computer and use it in GitHub Desktop.
ktor JWT testing blog post
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package dev.nycode.ktor.jwt.testing | |
import com.auth0.jwt.JWT | |
import com.auth0.jwt.JWTVerifier | |
import com.auth0.jwt.algorithms.Algorithm | |
import org.junit.jupiter.api.extension.ExtensionContext | |
import org.junit.jupiter.api.extension.ParameterContext | |
import org.junit.jupiter.api.extension.ParameterResolver | |
class JWTExtension : ParameterResolver { | |
private val algorithm = Algorithm.HMAC256("my cool secret") | |
override fun supportsParameter( | |
parameterContext: ParameterContext, | |
extensionContext: ExtensionContext, | |
): Boolean { | |
return parameterContext.parameter.type == JWTVerifier::class.java || | |
parameterContext.parameter.type == String::class.java && | |
parameterContext.isAnnotated(TestJWT::class.java) | |
} | |
override fun resolveParameter( | |
parameterContext: ParameterContext, | |
extensionContext: ExtensionContext, | |
): Any { | |
return when (parameterContext.parameter.type.kotlin) { | |
JWTVerifier::class -> { | |
JWT.require(algorithm).build() | |
} | |
String::class -> { | |
JWT.create() | |
.sign(algorithm) | |
} | |
else -> error("Invalid type.") | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import assertk.assertThat | |
import assertk.assertions.isEqualTo | |
import com.auth0.jwt.JWTVerifier | |
import dev.nycode.ktor.auth.PermissionBuilder | |
import dev.nycode.ktor.jwt.testing.TestJWT | |
import io.ktor.client.request.* | |
import io.ktor.client.statement.* | |
import io.ktor.http.* | |
import io.ktor.server.application.* | |
import io.ktor.server.auth.* | |
import io.ktor.server.auth.jwt.* | |
import io.ktor.server.response.* | |
import io.ktor.server.routing.* | |
import io.ktor.server.testing.* | |
import org.junit.jupiter.api.Test | |
internal class JWTTests { | |
@Test | |
fun `Request with valid token succeeds`( | |
verifier: JWTVerifier, | |
@TestJWT("test") token: String, | |
) = testApplicationWithJWT(verifier = verifier, token = token) | |
@Test | |
fun `Request without token fails with Unauthorized`(verifier: JWTVerifier) = | |
testApplicationWithJWT( | |
verifier = verifier, | |
token = null, | |
expectedCode = HttpStatusCode.Unauthorized | |
) | |
} | |
internal fun testApplicationWithJWT( | |
verifier: JWTVerifier, | |
token: String?, | |
routing: Routing.() -> Unit = { | |
authenticate { | |
handle { | |
call.respond(HttpStatusCode.OK) | |
} | |
} | |
}, | |
expectedCode: HttpStatusCode = HttpStatusCode.OK, | |
request: HttpRequestBuilder.() -> Unit = { | |
token?.let(::bearerAuth) | |
}, | |
block: suspend ApplicationTestBuilder.(HttpResponse) -> Unit = {}, | |
) = testApplication { | |
install(Authentication) { | |
jwt { | |
validate { JWTPrincipal(it.payload) } | |
verifier(verifier) | |
} | |
} | |
routing(routing) | |
val response = client.get("/", request) | |
assertThat(response.status).isEqualTo(expectedCode) | |
block(response) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package dev.nycode.ktor.jwt.testing | |
@Retention(AnnotationRetention.RUNTIME) | |
@Target(AnnotationTarget.VALUE_PARAMETER) | |
annotation class TestJWT |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment