# How to Integrate CoSec with Spring MVC: Step-by-Step Filter Configuration

> Easily integrate CoSec with Spring MVC. Follow our step-by-step guide to configure filters and security beans for seamless integration with the ahoo-wang/cosec repository.

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

---

**Integrate CoSec with Spring MVC by adding the `cosec-webmvc` dependency and registering `AuthorizationFilter` and `InjectSecurityContextFilter` via `FilterRegistrationBean` with the core beans `SecurityContextParser`, `RequestParser`, and `Authorization`.**

The CoSec framework from the `ahoo-wang/cosec` repository provides a lightweight, policy-driven security layer for JVM applications. When you integrate CoSec with Spring MVC, you embed a filter chain that parses incoming requests, builds a security context, and evaluates authorization policies before your controllers handle the traffic. This guide shows the exact configuration code pulled from the source to get you running in minutes.

## Understanding the CoSec Filter Architecture

CoSec processes every HTTP request through a standardized pipeline implemented in the `cosec-webmvc` module. The framework provides two distinct servlet filters that cover different deployment scenarios.

**`AuthorizationFilter`** performs the complete authorization check for every request. Located at [`cosec-webmvc/src/main/kotlin/me/ahoo/cosec/servlet/AuthorizationFilter.kt`](https://github.com/ahoo-wang/cosec/blob/main/cosec-webmvc/src/main/kotlin/me/ahoo/cosec/servlet/AuthorizationFilter.kt), this filter parses the request into a CoSec `Request` object, builds a `SecurityContext` via `SecurityContextParser`, and runs the policy engine through the `Authorization` interface to produce an `AuthorizeResult`. When a request is denied, the filter writes the result directly to the HTTP response.

**`InjectSecurityContextFilter`** serves downstream microservices that sit behind an API gateway. Located at [`cosec-webmvc/src/main/kotlin/me/ahoo/cosec/servlet/InjectSecurityContextFilter.kt`](https://github.com/ahoo-wang/cosec/blob/main/cosec-webmvc/src/main/kotlin/me/ahoo/cosec/servlet/InjectSecurityContextFilter.kt), this filter assumes the gateway has already performed token validation and authorization. It parses the already-signed token from the request, constructs the `SecurityContext`, and injects it into the thread-local holder without re-running the policy engine.

## Adding the Required Dependency

Add the `cosec-webmvc` artifact to your build file to pull in the filters and core CoSec classes.

For Gradle (Kotlin DSL):

```kotlin
implementation("me.ahoo.cosec:cosec-webmvc:latest.version")

```

For Maven:

```xml
<dependency>
    <groupId>me.ahoo.cosec</groupId>
    <artifactId>cosec-webmvc</artifactId>
    <version>latest.version</version>
</dependency>

```

## Configuring the Three Required Beans

Before registering the filters, you must expose three core beans that the filters depend on. These interfaces are defined in the `cosec-core` module.

**`SecurityContextParser`** parses a CoSec `Request` into a `SecurityContext` containing the principal and attributes. The default implementation is available at [`cosec-core/src/main/kotlin/me/ahoo/cosec/context/SecurityContextParser.kt`](https://github.com/ahoo-wang/cosec/blob/main/cosec-core/src/main/kotlin/me/ahoo/cosec/context/SecurityContextParser.kt).

**`RequestParser`** adapts the servlet-specific `HttpServletRequest` into the CoSec `Request` abstraction. For Spring MVC, use `ServletRequestParser`.

**`Authorization`** is the policy engine that evaluates access decisions. Defined in [`cosec-core/src/main/kotlin/me/ahoo/cosec/api/authorization/Authorization.kt`](https://github.com/ahoo-wang/cosec/blob/main/cosec-core/src/main/kotlin/me/ahoo/cosec/api/authorization/Authorization.kt), this bean requires a `PolicyProvider` to load your authorization rules.

```kotlin
import me.ahoo.cosec.context.SecurityContextParser
import me.ahoo.cosec.context.request.RequestParser
import me.ahoo.cosec.servlet.ServletRequestParser
import me.ahoo.cosec.api.authorization.Authorization
import me.ahoo.cosec.policy.PolicyProvider
import jakarta.servlet.http.HttpServletRequest
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration
class CoSecBeanConfiguration {

    @Bean
    fun securityContextParser(): SecurityContextParser = SecurityContextParser.default()

    @Bean
    fun requestParser(): RequestParser<HttpServletRequest> = ServletRequestParser()

    @Bean
    fun authorization(policyProvider: PolicyProvider): Authorization = 
        Authorization(policyProvider)
}

```

## Registering the Servlet Filters

Use `FilterRegistrationBean` to wire the filters into the Spring MVC filter chain with explicit ordering. The `AuthorizationFilter` must run first at `Ordered.HIGHEST_PRECEDENCE` to protect endpoints, while `InjectSecurityContextFilter` runs immediately after at `Ordered.HIGHEST_PRECEDENCE + 1`.

```kotlin
import me.ahoo.cosec.servlet.AuthorizationFilter
import me.ahoo.cosec.servlet.InjectSecurityContextFilter
import jakarta.servlet.Filter
import org.springframework.boot.web.servlet.FilterRegistrationBean
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.core.Ordered

@Configuration
class CoSecFilterConfiguration(
    private val securityContextParser: SecurityContextParser,
    private val authorization: Authorization,
    private val requestParser: RequestParser<HttpServletRequest>
) {

    @Bean
    fun authorizationFilterRegistration(): FilterRegistrationBean<Filter> {
        val filter = AuthorizationFilter(securityContextParser, authorization, requestParser)
        return FilterRegistrationBean<Filter>(filter).apply {
            order = Ordered.HIGHEST_PRECEDENCE
            urlPatterns = listOf("/*")
            name = "CoSecAuthorizationFilter"
        }
    }

    @Bean
    fun injectSecurityContextFilterRegistration(): FilterRegistrationBean<Filter> {
        val filter = InjectSecurityContextFilter(requestParser, securityContextParser)
        return FilterRegistrationBean<Filter>(filter).apply {
            order = Ordered.HIGHEST_PRECEDENCE + 1
            urlPatterns = listOf("/*")
            name = "CoSecInjectSecurityContextFilter"
        }
    }
}

```

## Loading Policies with FilePolicyProvider

The `Authorization` bean requires a `PolicyProvider` to load rules. The following configuration uses `FilePolicyProvider` to load JSON policy files from the classpath directory `cosec-policy`.

```kotlin
import me.ahoo.cosec.policy.FilePolicyProvider
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import java.nio.file.Paths

@Configuration
class CoSecPolicyConfiguration {

    @Bean
    fun filePolicyProvider(): FilePolicyProvider =
        FilePolicyProvider(Paths.get("classpath:/cosec-policy"))
}

```

Place your policy JSON files (defining resource-action pairs, conditions, and rate limits) in `src/main/resources/cosec-policy/`.

## Accessing the Security Context in Controllers

Once the filters process a request, the `SecurityContext` is stored in a thread-local holder accessible via `SecurityContextHolder`. Controllers can retrieve the principal ID, roles, or custom attributes without parsing tokens manually.

```kotlin
import me.ahoo.cosec.context.SecurityContextHolder
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController

@RestController
@RequestMapping("/api")
class GreetingController {

    @GetMapping("/hello")
    fun hello(): String {
        val ctx = SecurityContextHolder.getContext()
        val principal = ctx.principal?.id ?: "anonymous"
        return "Hello, $principal!"
    }
}

```

## Summary

- **Add the `cosec-webmvc` dependency** to import the servlet filters and core classes.
- **Expose three beans**: `SecurityContextParser`, `RequestParser<HttpServletRequest>`, and `Authorization` with a `PolicyProvider`.
- **Register `AuthorizationFilter`** at `Ordered.HIGHEST_PRECEDENCE` to enforce policies on every request.
- **Optionally register `InjectSecurityContextFilter`** at `Ordered.HIGHEST_PRECEDENCE + 1` for downstream services behind a gateway.
- **Access the principal** in controllers via `SecurityContextHolder.getContext()` without additional boilerplate.

## Frequently Asked Questions

### What is the difference between AuthorizationFilter and InjectSecurityContextFilter?

`AuthorizationFilter` runs the full policy engine to decide allow or deny, making it suitable for edge services that directly face clients. `InjectSecurityContextFilter` skips authorization checks and only parses the existing token to build the `SecurityContext`, which is ideal for internal microservices that trust an upstream API gateway to handle security validation.

### How do I configure CoSec when my service is behind an API gateway?

Remove the `AuthorizationFilter` bean registration and keep only `InjectSecurityContextFilter`. Set its order to `Ordered.HIGHEST_PRECEDENCE` so it runs first, parsing the gateway-verified token from the request headers and populating `SecurityContextHolder` for your business logic.

### Can I use CoSec with Spring Boot 3 and Jakarta EE?

Yes. The `cosec-webmvc` module uses the `jakarta.servlet` namespace and is compatible with Spring Boot 3 and the Jakarta EE 9+ specifications. Ensure you import `jakarta.servlet.http.HttpServletRequest` rather than the legacy `javax.servlet` package in your configuration classes.

### How does CoSec handle CORS and CSRF protection?

CoSec focuses solely on authorization policy evaluation (allow or deny) and does not interfere with CORS or CSRF concerns. Configure these separately using Spring’s `WebMvcConfigurer` or `CorsFilter` as usual; CoSec filters will execute after CORS preflight checks but before your controller logic.