# How CoSec Handles Reactive Authorization Flows in Spring WebFlux

> Discover how CoSec handles reactive authorization flows in Spring WebFlux. Learn about its non-blocking Mono approach for asynchronous security decisions.

- Repository: [Ahoo Wang/cosec](https://github.com/ahoo-wang/cosec)
- Tags: how-to-guide
- Published: 2026-02-23

---

**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`](https://github.com/ahoo-wang/cosec/blob/main/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.

```kotlin
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`](https://github.com/ahoo-wang/cosec/blob/main/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`](https://github.com/ahoo-wang/cosec/blob/main/cosec-api/src/main/kotlin/me/ahoo/cosec/api/authorization/Authorization.kt). This interface defines a single method that returns a `Mono<AuthorizeResult>`:

```kotlin
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:

- **`ReactiveAuthorizationFilter`** ([`cosec-webflux/src/main/kotlin/me/ahoo/cosec/webflux/ReactiveAuthorizationFilter.kt`](https://github.com/ahoo-wang/cosec/blob/main/cosec-webflux/src/main/kotlin/me/ahoo/cosec/webflux/ReactiveAuthorizationFilter.kt)): The WebFlux entry filter that triggers the security pipeline.

- **`ReactiveSecurityFilter`** ([`cosec-webflux/src/main/kotlin/me/ahoo/cosec/webflux/ReactiveSecurityFilter.kt`](https://github.com/ahoo-wang/cosec/blob/main/cosec-webflux/src/main/kotlin/me/ahoo/cosec/webflux/ReactiveSecurityFilter.kt)): Contains shared logic for parsing, token verification, and result handling. Lines 89-94 implement `ServerHttpResponse.writeWithAuthorizeResult` for JSON serialization.

- **`Authorization`** ([`cosec-api/src/main/kotlin/me/ahoo/cosec/api/authorization/Authorization.kt`](https://github.com/ahoo-wang/cosec/blob/main/cosec-api/src/main/kotlin/me/ahoo/cosec/api/authorization/Authorization.kt)): The functional interface defining the contract for authorization providers.

- **`TracingAuthorization`** ([`cosec-opentelemetry/src/main/kotlin/me/ahoo/cosec/opentelemetry/TracingAuthorization.kt`](https://github.com/ahoo-wang/cosec/blob/main/cosec-opentelemetry/src/main/kotlin/me/ahoo/cosec/opentelemetry/TracingAuthorization.kt)): A decorator that adds OpenTelemetry tracing around authorization decisions.

- **`CoSecMonoTrace`** ([`cosec-opentelemetry/src/main/kotlin/me/ahoo/cosec/opentelemetry/AuthorizationMono.kt`](https://github.com/ahoo-wang/cosec/blob/main/cosec-opentelemetry/src/main/kotlin/me/ahoo/cosec/opentelemetry/AuthorizationMono.kt)): A `Mono` wrapper that creates and ends OpenTelemetry spans around the reactive authorization call.

## 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.

```kotlin
@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`](https://github.com/ahoo-wang/cosec/blob/main/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`](https://github.com/ahoo-wang/cosec/blob/main/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`](https://github.com/ahoo-wang/cosec/blob/main/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.