Global request interceptor
@oldergod is already working on this.
Since Feb 7, 2024.
- Dominant language
- Kotlin
- Stars
- 4.4k
- Forks
- 627
- Avg merge
- 3d 15m
- Merged PRs (30d)
- 20
Description
I couldn't find a way in Wire to intercept all the requests and handle their responses. Without that implementing things like authentication is much harder.
The way it works in io.grpc is that you implement and add a io.grpc.ClientInterceptor when creating a io.grpc.Channel. For example, the code authenticating requests might look like this (note that the existing auth token is invalidated on receiving Status.UNAUTHENTICATED from the server):
class GrpcAuthInterceptor (private val authTokenHolder: AuthTokenHolder) : ClientInterceptor {
override fun <ReqT : Any, RespT : Any> interceptCall(
method: MethodDescriptor<ReqT, RespT>,
callOptions: CallOptions,
next: Channel
): ClientCall<ReqT, RespT> = object : ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(
next.newCall<ReqT, RespT>(method, callOptions)
) {
override fun start(responseListener: Listener<RespT>, headers: Metadata) {
val needsAuth = headers.needsAuth()
if (!needsAuth) return super.start(responseListener, headers)
val authToken = runBlocking { authTokenHolder.getAuthToken() }
if (authToken != null) {
headers.authenticate(authToken)
}
super.start(
if (authToken != null) responseListener(authToken, responseListener) else responseListener,
headers
)
}
}
private fun <RespT : Any> responseListener(
authToken: String,
original: ClientCall.Listener<RespT>
) = object : ForwardingClientCallListener.SimpleForwardingClientCallListener<RespT>(original) {
override fun onClose(status: Status, trailers: Metadata) {
super.onClose(status, trailers)
if (status == Status.UNAUTHENTICATED) {
runBlocking {
authTokenHolder.invalidate(authToken)
}
}
}
}
}
However, it's hard to do the same in Wire as there is no single point of request handling.
Here it was suggested to add an OkHttpClient interceptor and set the HTTP headers instead which IMO is not correct as it's a wrong application layer (HTTP vs gRPC). Moreover, it's hard to detect authentication errors as gRPC has its own status codes and always returns HTTP status code 200 (even if the request couldn't be authenticated according to gRPC, for example). This of course could be worked around by checking the grpc-status header but it doesn't look clean to me.
Am I missing something? Or how are you supposed to implement authentication (or any other generic request handling) in Wire?
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.