How CoSec Handles Reactive Authorization Flows in Spring WebFlux

TLDR: CoSec implements reactive authorization flows using Spring WebFlux and Project Reactor, where ReactiveAuthorizationFilter delegates to ReactiveSecurityFilter.filterInternal to parse requests and return non-blocking Mono<AuthorizeResult> decisions through a fully asynchronous pipeline.

CoSec is a cloud-native security framework designed for high-performance reactive applications. Understanding how CoSec authorization reactive flows work is essential for building scalable, non-blocking security layers on Spring WebFlux. The framework ensures that every security check—from token parsing to policy evaluation—operates without blocking threads.

The Reactive Authorization Architecture

CoSec's reactive stack leverages Spring WebFlux and Project Reactor to ensure zero thread-blocking during security decisions. The entire pipeline returns reactive types, allowing the framework to handle thousands of concurrent connections with minimal resource consumption.

Entry Point - ReactiveAuthorizationFilter

The flow begins at ReactiveAuthorizationFilter, a standard WebFilter implementation located in cosec-webflux/src/main/kotlin/me/ahoo/cosec/webflux/ReactiveAuthorizationFilter.kt. This filter intercepts every HTTP request entering the WebFlux chain and delegates to the shared security logic.

class ReactiveAuthorizationFilter(...) : WebFilter {
    override fun filter(exchange, chain): Mono<Void> =
        filterInternal(exchange) { serverExchange, request ->
            chain.filter(serverExchange)
        }
}

Request Parsing and Security Context Extraction

Inside ReactiveSecurityFilter.filterInternal at cosec-webflux/src/main/kotlin/me/ahoo/cosec/webflux/ReactiveSecurityFilter.kt, the framework performs two critical operations. First, RequestParser transforms the ServerWebExchange into a CoSec Request object. Second, SecurityContextParser extracts authentication details from the request headers.

If token verification fails with a TokenVerificationException, the system gracefully falls back to an anonymous SimpleSecurityContext rather than terminating the reactive flow.

Non-Blocking Authorization Decisions

The core authorization logic resides in the Authorization functional interface at cosec-api/src/main/kotlin/me/ahoo/cosec/api/authorization/Authorization.kt. This interface defines a single method that returns a Mono<AuthorizeResult>:

authorization.authorize(request, securityContext)   // returns Mono<AuthorizeResult>

This non-blocking call allows the framework to defer the decision until underlying data sources—such as databases, caches, or external policy engines—respond asynchronously.

Processing Authorization Results

The Mono<AuthorizeResult> undergoes transformation via flatMap operations within ReactiveSecurityFilter. The framework handles three distinct outcomes:

  • Allowed: When authorizeResult.authorized == true, the filter enriches the exchange with the security principal via securityContext.principal.toMono() and continues the chain using chain.filter(serverExchange).
  • Denied: For unauthorized access, the filter sets HTTP status codes (401 for unauthenticated, 403 for forbidden) and writes a JSON response body containing the AuthorizeResult.
  • Rate Limiting: On TooManyRequestsException, the filter returns HTTP 429 using writeWithAuthorizeResult(AuthorizeResult.TOO_MANY_REQUESTS).

Core Source Files and Components

Understanding the reactive authorization flow requires familiarity with these key source files:

Implementing Custom Reactive Authorizers

Developers can extend CoSec's reactive capabilities by implementing the Authorization interface. Because the method returns Mono<AuthorizeResult>, you can integrate asynchronous data sources such as reactive databases or remote policy services.

@Component
class MyReactiveAuthorizer : Authorization {
    override fun authorize(request: Request, context: SecurityContext): Mono<AuthorizeResult> {
        return policyRepository.findPolicy(request.path, context.principal.id)
            .map { policy -> 
                if (policy.allows(request.action)) AuthorizeResult.ALLOW
                else AuthorizeResult.EXPLICIT_DENY
            }
            .defaultIfEmpty(AuthorizeResult.IMPLICIT_DENY)
    }
}

The framework automatically incorporates custom implementations into the reactive pipeline without blocking threads.

OpenTelemetry Integration for Reactive Streams

CoSec provides optional distributed tracing through the TracingAuthorization decorator. This component wraps the authorization Mono with CoSecMonoTrace, creating OpenTelemetry spans that start when the Mono subscribes and end when it completes or errors.

This integration ensures observability across asynchronous boundaries, allowing developers to trace authorization decisions through complex reactive call chains.

Summary

  • CoSec authorization reactive flows begin at ReactiveAuthorizationFilter, a WebFilter that intercepts all incoming requests.
  • The ReactiveSecurityFilter.filterInternal method handles request parsing and security context extraction without blocking.
  • Authorization decisions return Mono<AuthorizeResult>, enabling fully non-blocking policy evaluation.
  • Results are processed reactively: allowed requests continue down the chain, while denied requests return appropriate HTTP status codes with JSON bodies.
  • Optional OpenTelemetry tracing via TracingAuthorization and CoSecMonoTrace provides visibility into asynchronous authorization operations.

Frequently Asked Questions

What is the entry point for CoSec reactive authorization?

The entry point is ReactiveAuthorizationFilter located in cosec-webflux/src/main/kotlin/me/ahoo/cosec/webflux/ReactiveAuthorizationFilter.kt. This class implements Spring WebFlux's WebFilter interface and intercepts every HTTP request, delegating to ReactiveSecurityFilter.filterInternal to begin the security evaluation.

How does CoSec handle token verification failures in reactive flows?

When SecurityContextParser throws a TokenVerificationException, ReactiveSecurityFilter.filterInternal catches the exception and creates an anonymous SimpleSecurityContext instead of blocking the request. This allows the authorization flow to continue, where the subsequent authorization check will typically deny access with a 401 status if authentication is required.

Can I use CoSec reactive authorization with custom authentication providers?

Yes. Implement the Authorization interface from cosec-api/src/main/kotlin/me/ahoo/cosec/api/authorization/Authorization.kt and return a Mono<AuthorizeResult>. Because the interface is designed for reactive programming, you can integrate with any asynchronous data source, such as reactive Redis, MongoDB, or external HTTP services, without blocking the WebFlux event loop.

How does OpenTelemetry tracing work with CoSec's reactive streams?

CoSec's TracingAuthorization decorator wraps the authorization Mono with CoSecMonoTrace (found in cosec-opentelemetry/src/main/kotlin/me/ahoo/cosec/opentelemetry/AuthorizationMono.kt). This wrapper creates an OpenTelemetry span when the Mono is subscribed and ends it upon completion or error, ensuring distributed traces capture the full latency of asynchronous authorization decisions.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →