0

According to the documentation a signing key resolver can fetch a key dynamically: https://github.com/jwtk/jjwt#signing-key-resolver

The following code does call a kotlin suspending function which retrieves the public key in a non blocking way:

val parser =
            Jwts.parserBuilder()
                .setSigningKeyResolver(object : SigningKeyResolverAdapter() {
                    override fun resolveSigningKey(header: JwsHeader<out JwsHeader<*>>, claims: Claims?): Key {
                        return runBlocking {
                            retrievePublicKey(header["kid"])
                        }
                    }
                }).build()
        val claims = parser.parseClaimsJws(jwtString).body

Here is the definition of the suspending function

suspend fun retrievePublicKey(key:String):PublicKey {
...
}

The problem is that this code needs to block the thread(runBlocking). Otherwise it can't work.

This challenge also exists for all other async frameworks (rxjava, listenablefuture, completablefuture, ...)

David Michael Gang
  • 7,107
  • 8
  • 53
  • 98
  • `build()` method returns a thread-safe `JwtParser`. I guess `resolveSigningKey()` method is invoked in background thread (you can check it adding `Thread.currentThread()` to the logs), so the thread can be blocked. – Sergio Jun 18 '20 at 14:40
  • i don't think so: https://github.com/jwtk/jjwt/blob/72973f9b9ba72438d97834db2bd56e36d3c48592/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java#L251 I think they leave threading to us. – David Michael Gang Jun 18 '20 at 18:44

1 Answers1

1

It looks like the jwtk library is mostly synchronous, so it is not possible to directly use suspend to avoid blocking.

Rather you should probably wrap the library so the parse* calls are done on the IO dispatcher which is designed to handle blocking IO. In addition if you design your retrievePublicKey suspend function to rely on the caller to handle threading you could make it do the neccesary blocking IO in the same thread without consuming more resources.

val parser = /* create parser with runBlocking */
val claims = withContext(Dispatchers.IO) {
    // This will end up synchronously calling runBlocking, if the
    //  suspend function does not explicitly switch context it will do its work
    //  on the same thread.
    parser.parseClaimsJws(jwtString)
}.body

Kiskae
  • 24,655
  • 2
  • 77
  • 74