+1.
I've been working on creating an async version of the Pac4j API (ultimately to be used as the basis of a non-blocking vertx/pac4j implementation, though I wanted to build it in a way that other async implementations could easily consume) and I'm finding CompletableFutures really helpful. In my case the choice was basically Rx vs CompletableFuture and I chose the one that was already present in core Java.
The only slight annoyance for me is that where the CompletableFuture API is doing map/flatMap semantics, it would have been nice to retain naming consistency with the streaming API rather than introduce thenApply/thenCompose as names. However, that's a pretty minor gripe, as once you get the translation in your mind, it becomes second nature.
I've also used Rx in some of my vertx-pac4j tests and there isn't so much to choose between them other than for a general-use API I didn't want to enforce a third-party dependency at the exposed API level.
Out of interest, to the OP, what's your reluctance to adopt the rx-api based on? I'm entirely comfortable using it internally, I just didn't want to define a public API in terms of Observables (the parts which are internal are less of a concern).