Henry Hargreaves
Henry Hargreaves

Reputation: 315

How to get the SecurityContext from within a DataFetcher (WebFlux + DGS GraphQL)

I am wondering if it is possible to obtain the Authentication from within the onField function contained in a SchemaDirectiveWiring.

I've looked into using the ReactiveSecurityContextHolder and SecurityContextHolder.getContext().getAuthentication() and ReactiveSecurityContextHolder.getContext().block().getAuthentication(), but both return null (which does make sense since its being called from within an asynchronous thread).

I therefore looked into using the [ReactiveDgsContext][1] which looks promising as when debugging the code, I can see within the reactorContext that there is a SecurityContext key/value, but I don't know how to access it/retrieve it properly.

Currently, my code looks as follows:

DataFetcher<?> authDataFetcher = DataFetcherFactories
                .wrapDataFetcher(originalFetcher, ((dataFetchingEnvironment, value) -> {
                    ReactiveDgsContext context = ReactiveDgsContext.from(dataFetchingEnvironment);
                    if(context != null){
                        ContextView reactiveContext = context.getReactorContext();
...
                    }

Any help would be much appreciated!

enter image description here

Upvotes: 0

Views: 753

Answers (1)

Henry Hargreaves
Henry Hargreaves

Reputation: 315

I wasn't able to figure out a way of getting the Authentication out of the ReactiveDgsContext object, but as a workaround, I created a custom context.

public record CustomContext(ServerRequest webExchange, SecurityContext securityContext) {
}

And then registered it as follows:

@Configuration
public class DgsConfiguration {

    @Bean
    public DgsReactiveCustomContextBuilderWithRequest<CustomContext> dgsReactiveCustomContextBuilder() {
        return (map, httpHeaders, serverRequest) -> ReactiveSecurityContextHolder.getContext()
                .map(securityContext -> new CustomContext(serverRequest, securityContext))
                .defaultIfEmpty(new CustomContext(serverRequest, null));
    }

}

Then you can access it as follows:

DataFetcher<?> authDataFetcher = DataFetcherFactories
                .wrapDataFetcher(originalFetcher, ((dataFetchingEnvironment, value) -> {
                    ReactiveDgsContext context = ReactiveDgsContext.from(dataFetchingEnvironment);
                    if (context != null) {
                        CustomContext customContext = (CustomContext) context.getCustomContext();
                        if (customContext != null) {
                            Authentication authentication = customContext.securityContext().getAuthentication();
                            ....
                        }
                    }

Alternatively, you can also get the JWT token from the headers and check it again, but given this has already been done, I didn't want to do it again (using Firebase so would be multiple calls to the oauth server).

Credit to ChatGPT for the help on this one - if anyone has a better way to do this (maybe using ReactiveDgsContext I would be interested in seeing it!)

Upvotes: 1

Related Questions