Solution: ReactiveSecurityContextHolder empty inside Axon 5 query handlers (Spring WebFlux)

We hit a subtle bug after migrating to Axon 5 with Spring WebFlux and Netflix DGS: ReactiveSecurityContextHolder.getContext() always returns Mono.empty() inside @QueryHandler methods.
Owners couldn’t see their own INACTIVE entities because the auth check silently fell through.

Root cause: Two things break Reactor Context propagation:

  • subscribeOn() shifting to a different thread pool (which turns out to be unnecessary in Axon 5 — SimpleQueryBus is fully non-blocking)
  • Axon’s internal .toFuture() call creating an independent subscription with no knowledge of the original context

Our solution: Extract identity and roles at the edge (DGS layer, where security context still works) and attach them as Axon MetaData via GenericQueryMessage. Query handlers read them
with @MetadataValue:

  @QueryHandler
  public Mono<Venue> handle(FindVenueByIdQuery query,
          @MetadataValue(value = "userId", required = false) String callerId,
          @MetadataValue(value = "roles", required = false) String roles) {
      // pure function — no ReactiveSecurityContextHolder needed
  }

The key API insight: QueryGateway doesn’t expose a metadata parameter directly, but if you pass a GenericQueryMessage, Axon uses it as-is — metadata included.

Full write-up with implementation details, Mermaid diagram, and Axon 5 migration notes: Propagating User Identity in Axon 5 Query Handlers — SaaSForge

That’s an interesting and important find, @petrmac! Would you perchance be up to write an issue for us so that the team, or a contributor, can work on an AF-solution towards this?

Furthermore, what strikes me as interesting, is that this happens for queries you say. Does that mean the security context works fine for commands?

Hi Steven, ticket raised: ReactiveSecurityContextHolder is empty inside @QueryHandler in Spring WebFlux applications · Issue #4207 · AxonFramework/AxonFramework · GitHub

1 Like