Hi, has anyone implemented a solution for access t...
# apollo-kotlin
p
Hi, has anyone implemented a solution for access token expired or in general access denied that doesn't rely on gql returning http code 401? My current solution is to handle the token expired error in each GQL request. But is prompt to errors since new devs may forget to add the error in the GQL query. Perhaps is there a way of doing GQL query inheritance? Where I could have a based query with this error and not having to repeat it in every query.
m
ApolloInterceptor
?
Add an interceptor that checks
response.errors
(assuming this is where the server signals the expired token) and retry the downstream chain
since new devs may forget to add the error in the GQL query.
Wait, the error is actually part of your schema looks like?
That's an interesting design decision
But even if it's part of your schema, there must be a
response.errors
entry for missing data
I think?
p
Yes correct. The service sends a list of errors. I have to take a look into the ApolloInterceptor, I haven't heard of it. Right now we use an okhttp Authenticator that relies on the service sending back the 401. But we are evaluating to move from the 401 status code and okhttp Authenticator to a pure gql response error handler. Which will take care of refreshing the token.
m
I think
ApolloInterceptor
is what you want. It's like OkHttp
Interceptor
but works at the GraphQL layer so you'll have access to
response.errors
🎉 1
p
Great 👍 I will check then
m
If you're using the normalized cache, make sure to call
.addInterceptor()
after
.normalizedCache()
to only run your interceptor if network is required
d
Copy code
class ReauthApolloInterceptor : ApolloInterceptor {

    override fun <D : Operation.Data> intercept(
        request: ApolloRequest<D>,
        chain: ApolloInterceptorChain
    ): Flow<ApolloResponse<D>> = chain.proceed(request).map { response ->

        if (!request.operation.requiresAuth()) {
            return@map response
        }

        val authorised = response.errors.doesNotContainUnAuthorised()

        if (authorised) {
            return@map response
        }

        val newToken = getNewToken()

        chain.proceed(request.newBuilder().addNewToken(newToken).build())
    }
}
Some half-working code to help you (sorry can't quite share exact code because it's private but this is the general idea)
👍 2
p
I appreciate it, thanks so much. That's super helpful 🙂