Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

graphql-java nested resolvers are executed in different thread have different Spring security contexts

I am using graphql-java, and it executes the different nested resolvers in separate threads.

I have a custom filter on spring security that parses the Bearer token from the Authorization Header and adds that to the current spring security context.

I was temporarily able to solve the issue by listening to the ContextRefreshedEvent and forcing the strategy to Global, as you can see here:

    @EventListener
    fun setupSecurityContext(event: ContextRefreshedEvent) {
        SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_GLOBAL)
    }

I am not happy with this solution because I have to access the tokens on the resolvers with a global static call when I would like to receive it passed as a parameter on the resolver.

SecurityContextHolder.getContext().authentication.principal

I believe this is not a good practice. I guess the data from one request can be exposed to another user by a different thread.

like image 298
Fábio Carneiro Avatar asked Feb 04 '26 19:02

Fábio Carneiro


1 Answers

I faced the same issue using a retrofit client. All I need is just to set spring delegating executor to the okhttp dispatcher like this:

@Bean
DelegatingSecurityContextExecutorService dispatcherExecutor() {
    return new DelegatingSecurityContextExecutorService(
            new ThreadPoolExecutor(
                    0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS,
                    new SynchronousQueue<>(), Util.threadFactory("OkHttp Dispatcher", false)
            )
    );
}

@Bean
OkHttpClient okHttpClient() {
    var interceptor = new HttpLoggingInterceptor();
    interceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);

    return new OkHttpClient.Builder()
            .connectTimeout(retrofitConnectionTimeout, TimeUnit.SECONDS)
            .readTimeout(retrofitConnectionTimeout, TimeUnit.SECONDS)
            .addInterceptor(interceptor)
            .dispatcher(new Dispatcher(dispatcherExecutor()))
            .build();
}

What about graphql, please look at graphql.execution.ExecutorServiceExecutionStrategy. It allows to setup graphql async calls executor service, so you can pass spring delegating executor service here.

like image 147
Евгений Рябов Avatar answered Feb 06 '26 09:02

Евгений Рябов