0

I'm trying to handle JWT-authentication in gRPC on my backend. I can extract the JWT in an interceptor but how do I access it in my service? I think it should be done with a CoroutineContextServerInterceptor but this doesn't work:

val jwtKey: Context.Key<String> = Context.key("jwtKey")

fun main() {
    ServerBuilder.forPort(8980).intercept(UserInjector).addService(MyService).build().start().awaitTermination()
}

object UserInjector : CoroutineContextServerInterceptor() {
    override fun coroutineContext(call: ServerCall<*, *>, headers: Metadata): CoroutineContext {
        val jwtString = headers.get(Metadata.Key.of("jwt", Metadata.ASCII_STRING_MARSHALLER))
        println("coroutineContext: $jwtString")
        return GrpcContextElement(Context.current().withValue(jwtKey, jwtString))
    }
}

object MyService : MyServiceGrpcKt.MyServiceCoroutineImplBase() {
    override suspend fun testingJWT(request: Test.MyRequest): Test.MyResponse {
        println("testingJWT: ${jwtKey.get()}")
        return Test.MyResponse.getDefaultInstance()
    }
}

Output:

coroutineContext: something
testingJWT: null
linust
  • 25
  • 4

1 Answers1

2

I think you'll need to propagate that in its own coroutine context element.

class JwtElement(val jwtString: String) : CoroutineContext.Element {
  companion object Key : CoroutineContext.Key<JwtElement>
  override val key: CoroutineContext.Key<JwtElement>
    get() = Key
}

object UserInjector : CoroutineContextServerInterceptor() {
  override fun coroutineContext(call: ServerCall<*, *>, headers: Metadata): CoroutineContext {
    val jwtString = headers.get(Metadata.Key.of("jwt", Metadata.ASCII_STRING_MARSHALLER))
    println("coroutineContext: $jwtString")
    return JwtElement(jwtString)
  }
}

object MyService : MyServiceGrpcKt.MyServiceCoroutineImplBase() {
  override suspend fun testingJWT(request: Test.MyRequest): Test.MyResponse {
    println("testingJWT: ${coroutineContext[JwtElement]}")
    return Test.MyResponse.getDefaultInstance()
  }
}
Louis Wasserman
  • 191,574
  • 25
  • 345
  • 413
  • coroutineContext return empty context by default, you should get currentCoroutineContext – z0mb1ek Mar 05 '22 at 21:53
  • @z0mb1ek: No. They're the [same thing](https://github.com/Kotlin/kotlinx.coroutines/blob/master/kotlinx-coroutines-core/common/src/CoroutineScope.kt#L316). – Louis Wasserman Mar 05 '22 at 22:57
  • see this https://github.com/Kotlin/kotlinx.coroutines/blob/master/kotlinx-coroutines-core/common/src/CoroutineScope.kt#L220 and this https://github.com/Kotlin/kotlinx.coroutines/blob/master/kotlinx-coroutines-core/common/src/CoroutineScope.kt#L323 You variant does not work, I tested – z0mb1ek Mar 06 '22 at 14:38