Class VertxSecurityHelper

java.lang.Object
org.a2aproject.sdk.server.common.quarkus.VertxSecurityHelper

@Singleton public final class VertxSecurityHelper extends Object
CDI helper for integrating Quarkus security with Vert.x Web routes.

When using @Observes Router to register Vert.x routes (instead of Quarkus Reactive Routes), the standard Quarkus HTTP authentication flow is bypassed. This helper provides utilities to manually trigger authentication and activate the CDI request context so that @Authenticated interceptors work correctly.

Background

Quarkus Reactive Routes (using @Route) automatically:

  • Trigger HTTP authentication mechanisms (Basic, OAuth, etc.)
  • Activate the CDI request context
  • Populate CurrentIdentityAssociation with the authenticated identity

However, when using @Observes Router to register raw Vert.x Web routes, none of this happens automatically. This helper bridges the gap by:

  • Triggering authentication via HttpAuthenticator
  • Activating the CDI request context
  • Populating CurrentIdentityAssociation with the authenticated identity
  • Executing @Authenticated methods within the active context

Usage Pattern


 @Inject VertxSecurityHelper securityHelper;

 void setupRoutes(@Observes Router router) {
     router.post("/api/endpoint")
         .blockingHandler(ctx -> {
             try {
                 // Authenticate and execute within request context
                 securityHelper.runInRequestContext(ctx, () -> {
                     myAuthenticatedMethod(); // Has @Authenticated annotation
                 });
             } catch (UnauthorizedException | ForbiddenException e) {
                 securityHelper.handleAuthError(ctx, e);
             } catch (Exception e) {
                 VertxSecurityHelper.handleGenericError(ctx);
             }
         });
 }
 
See Also:
  • HttpAuthenticator
  • CurrentIdentityAssociation
  • Constructor Summary

    Constructors
    Constructor
    Description
     
  • Method Summary

    Modifier and Type
    Method
    Description
    void
    handleAuthError(io.vertx.ext.web.RoutingContext ctx, Exception e)
    Handles authentication or authorization errors by sending the appropriate HTTP error response.
    static void
    handleGenericError(io.vertx.ext.web.RoutingContext ctx)
    Handles generic errors by sending a 500 Internal Server Error response.
    void
    runInRequestContext(io.vertx.ext.web.RoutingContext ctx, Runnable task)
    Authenticates the request and executes a task within an active CDI request context.
    void
    runInRequestContextDeferred(io.vertx.ext.web.RoutingContext ctx, Runnable task)
    Authenticates the request and executes a task, deferring CDI context destruction to the HTTP response lifecycle.

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Constructor Details

    • VertxSecurityHelper

      public VertxSecurityHelper()
  • Method Details

    • runInRequestContext

      public void runInRequestContext(io.vertx.ext.web.RoutingContext ctx, Runnable task)
      Authenticates the request and executes a task within an active CDI request context.

      This method performs the full authentication and context setup flow required for Vert.x Web routes registered via @Observes Router:

      1. Triggers HTTP authentication via HttpAuthenticator.attemptAuthentication(io.vertx.ext.web.RoutingContext)
      2. Activates the CDI request context if needed
      3. Sets the authenticated identity in CurrentIdentityAssociation
      4. Executes the task (which may call @Authenticated methods)
      5. Terminates the request context if it was activated by this method

      Thread Safety: This must be called on a Vert.x worker thread (e.g., from a blockingHandler), not the event loop thread. The authentication call blocks the worker thread using await().indefinitely(), which is safe on worker threads but would block the event loop on event loop threads.

      Context cleanup: Unlike runInRequestContextDeferred(io.vertx.ext.web.RoutingContext, java.lang.Runnable), this method calls terminate() immediately in the finally block, so there is no need to register endHandler/closeHandler callbacks — the context and its beans are destroyed before this method returns. Use this for non-streaming requests where the task runs synchronously on the calling thread.

      Parameters:
      ctx - the Vert.x routing context containing the HTTP request
      task - the code to execute within the authenticated request context
      Throws:
      io.quarkus.security.UnauthorizedException - if authentication fails
      io.quarkus.security.ForbiddenException - if authorization fails
      RuntimeException - if the task throws an exception
      See Also:
    • runInRequestContextDeferred

      public void runInRequestContextDeferred(io.vertx.ext.web.RoutingContext ctx, Runnable task)
      Authenticates the request and executes a task, deferring CDI context destruction to the HTTP response lifecycle.

      Unlike runInRequestContext(io.vertx.ext.web.RoutingContext, java.lang.Runnable), this method does not terminate the CDI request context when the task completes. Instead, it:

      1. Activates the CDI request context (or captures the existing active state)
      2. Triggers HTTP authentication
      3. Executes the task
      4. Deactivates the context on the calling thread (without destroying beans) — this prevents any external lifecycle manager (e.g. Quarkus's request filter) from calling terminate() and destroying beans while the agent thread is still running
      5. Destroys the context state when the HTTP response ends or the connection closes

      This is required for streaming (SSE) requests where the task dispatches work to a background thread (via CompletableFuture.runAsync with a ManagedExecutor) and returns immediately. The ManagedExecutor captures the CDI context at submit time and propagates it to the agent thread via AsyncManagedExecutorProducer — but only if the context hasn't been destroyed yet. By deactivating (not destroying) in the finally block and deferring destruction to the response lifecycle, the agent thread can access all @RequestScoped beans (including OIDC token credentials for token propagation).

      When the CDI context is already active (e.g. activated by a Quarkus request filter), this method takes ownership of its destruction lifecycle to ensure it is not prematurely terminated when the blocking handler thread returns. The context is destroyed by the SSE response endHandler / closeHandler instead.

      This method is also safe for non-streaming requests: response.end() is called synchronously inside the task, and the endHandler fires the cleanup shortly after.

      Parameters:
      ctx - the Vert.x routing context containing the HTTP request
      task - the code to execute within the authenticated request context
      Throws:
      io.quarkus.security.UnauthorizedException - if authentication fails
      io.quarkus.security.ForbiddenException - if authorization fails
      RuntimeException - if the task throws an exception
      See Also:
    • handleAuthError

      public void handleAuthError(io.vertx.ext.web.RoutingContext ctx, Exception e)
      Handles authentication or authorization errors by sending the appropriate HTTP error response.

      This should be called when catching UnauthorizedException or ForbiddenException thrown by @Authenticated interceptors or authentication mechanisms.

      • ForbiddenException → HTTP 403 Forbidden
      • All other auth errors → delegates to HttpAuthenticator.getChallenge(io.vertx.ext.web.RoutingContext) to obtain the correct WWW-Authenticate header for the configured auth mechanism (Basic, Bearer, etc.) and sends HTTP 401 with the challenge header
      Parameters:
      ctx - the routing context
      e - the authentication or authorization exception
    • handleGenericError

      public static void handleGenericError(io.vertx.ext.web.RoutingContext ctx)
      Handles generic errors by sending a 500 Internal Server Error response.
      Parameters:
      ctx - the routing context