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

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, 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, 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):

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

For Maven:

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

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, this bean requires a PolicyProvider to load your authorization rules.

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.

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.

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.

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.

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 →