mannodermaus
05/22/2026, 4:17 AMAlexander Sysoev
05/28/2026, 1:35 PMmannodermaus
05/28/2026, 3:14 PMGrpcCall itself is an object created from the service with its own requestMetadata. The call is then "executed" with the request payload. I suppose that OkHttp's Call interface may have been the role model for it.
// Wire:
// Declare gRPC service somewhere
val grpcClient = GrpcClient.Builder().build()
val service = grpcClient.create(MyService::class)
// Create a "call" object
val call = service.SomeMethod()
// Prepare request and generate an auth key at the call site
val request = SomeRequest(device_id = "test")
val authKey = calculateAuthKey()
// Attach call-specific headers as metadata
call.requestMetadata += mapOf("x-auth-key" to authKey)
// Execute the call and return the response
val response = call.execute(request)
return response
In kotlinx-rpc, the request is provided directly to the service without a "Call-type object" in the middle. Metadata can be given exclusively through the GrpcClient configuration, but I can't influence that at the call site.
// kotlinx-rpc:
// Declare gRPC service somewhere
val grpcClient = GrpcClient(...)
val service = grpcClient.withService<MyService>()
// Prepare request and generate an auth key at the call site
val request = SomeRequest { this.deviceId = "test" }
val authKey = calculateAuthKey()
// Q: How to attach call-specific headers as metadata?
// Execute the call and return response
val response = service.SomeMethod(request)
return response
Since posting my question, I have experimented with GrpcClientInterceptor and its callOptions.callCredentials setter. Since the GrpcCallCredentials interface method has a suspending context, I'm trying to grab the relevant info from a coroutine context element. Something like the below. Is that encouraged or a hard no from your POV?
// Define a coroutine context element that stores/provides the auth key...
class AuthContext(val authKey: String) : AbstractCoroutineContextElement(AuthContext) {
companion object : CoroutineContext.Key<AuthContext>
}
// ...and the callCredentials to attach to the GrpcClient
class MyCallCredentials : GrpcCallCredentials {
override suspend fun GrpcCallCredentials.Context.getRequestMetadata(): GrpcMetadata {
// Grab coroutine context element, if it's there
val auth = currentCoroutineContext()[AuthContext]
return GrpcMetadata {
auth?.let {
// Attach if present
append("x-auth-key", it.authKey)
}
}
}
}
// At the call site, provide the context element around the authenticated call
val response = withContext(AuthContext(authKey)) {
service.SomeMethod(request)
}
return response
Looking forward to your feedback. Thanks again!