# Complete Guide to Built-in ConditionMatchers in CoSec

> Discover CoSec's 16 built-in ConditionMatchers for path matching, RBAC, rate limiting, and more. Learn how to leverage these powerful tools for enhanced security and control.

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

---

**CoSec provides 16 built-in ConditionMatchers ranging from path matching and role-based access control to rate limiting and expression evaluation, all implementing the `ConditionMatcherFactory` interface and auto-registered via `ConditionMatcherFactoryProvider`.**

The **ahoo-wang/cosec** repository ships with a comprehensive set of built-in ConditionMatchers that enable developers to express complex authorization policies without writing custom Kotlin or Java code. Each matcher is instantiated through a factory pattern and automatically discovered by the Spring Boot starter, allowing immediate use in JSON or YAML policy definitions.

## Logical Combinators and Context Matchers

These matchers handle boolean logic and security context validation, forming the foundation for role-based and multi-tenant access control policies.

### AllConditionMatcher

**Type:** `all`

The `AllConditionMatcher` (implemented in [`AllConditionMatcherFactory.kt`](https://github.com/ahoo-wang/cosec/blob/main/AllConditionMatcherFactory.kt)) returns `true` for every request. Use this as a catch-all or default policy condition.

```json
{
  "type": "all"
}

```

### BoolConditionMatcher

**Type:** `bool`

The `BoolConditionMatcher` (implemented in [`BoolConditionMatcherFactory.kt`](https://github.com/ahoo-wang/cosec/blob/main/BoolConditionMatcherFactory.kt)) provides logical composition via `and` and `or` arrays, allowing nested conditions without custom code.

```json
{
  "type": "bool",
  "and": [
    { "type": "authenticated" },
    { "type": "path", "path": "/api/**" }
  ]
}

```

### AuthenticatedConditionMatcher

**Type:** `authenticated`

Located in [`AuthenticatedConditionMatcherFactory.kt`](https://github.com/ahoo-wang/cosec/blob/main/AuthenticatedConditionMatcherFactory.kt), this matcher verifies that the current `SecurityContext` contains an authenticated principal.

```json
{
  "type": "authenticated"
}

```

### InTenantConditionMatcher

**Type:** `inTenant`

Implemented in [`InTenantConditionMatcherFactory.kt`](https://github.com/ahoo-wang/cosec/blob/main/InTenantConditionMatcherFactory.kt), this matcher checks if the current tenant ID exists within a configured list.

```json
{
  "type": "inTenant",
  "tenants": ["tenant-a", "tenant-b"]
}

```

### InRoleConditionMatcher

**Type:** `inRole`

The `InRoleConditionMatcher` (source: [`InRoleConditionMatcherFactory.kt`](https://github.com/ahoo-wang/cosec/blob/main/InRoleConditionMatcherFactory.kt)) validates that the authenticated principal possesses at least one role from the supplied array.

```json
{
  "type": "inRole",
  "roles": ["ADMIN", "OPERATOR"]
}

```

## HTTP Request Part Matchers

These matchers operate on specific attributes of the HTTP request, such as the URI path or header values.

### PathConditionMatcher

**Type:** `path`

Defined in [`PathConditionMatcherFactory.kt`](https://github.com/ahoo-wang/cosec/blob/main/PathConditionMatcherFactory.kt), this matcher supports Ant-style patterns (e.g., `/admin/**`) and regular expressions against the request URI.

```json
{
  "type": "path",
  "path": "/admin/**"
}

```

### StartsWithConditionMatcher

**Type:** `startsWith`

Located in [`StartsWithConditionMatcherFactory.kt`](https://github.com/ahoo-wang/cosec/blob/main/StartsWithConditionMatcherFactory.kt), this checks whether a string part (path, header, etc.) begins with a configured value. Supports case-insensitive matching via a boolean flag.

```json
{
  "type": "startsWith",
  "part": "path",
  "value": "/api/v1",
  "ignoreCase": true
}

```

### EndsWithConditionMatcher

**Type:** `endsWith`

Implemented in [`EndsWithConditionMatcherFactory.kt`](https://github.com/ahoo-wang/cosec/blob/main/EndsWithConditionMatcherFactory.kt), this matcher verifies suffix matches on request parts.

```json
{
  "type": "endsWith",
  "part": "uri",
  "value": ".json"
}

```

### ContainsConditionMatcher

**Type:** `contains`

The `ContainsConditionMatcher` (source: [`ContainsConditionMatcherFactory.kt`](https://github.com/ahoo-wang/cosec/blob/main/ContainsConditionMatcherFactory.kt)) checks for substring presence within a request attribute.

```json
{
  "type": "contains",
  "part": "userAgent",
  "value": "Mobile"
}

```

### EqConditionMatcher

**Type:** `eq`

Located in [`EqConditionMatcherFactory.kt`](https://github.com/ahoo-wang/cosec/blob/main/EqConditionMatcherFactory.kt), this performs strict equality checks with optional case insensitivity.

```json
{
  "type": "eq",
  "part": "method",
  "value": "GET",
  "ignoreCase": false
}

```

### InConditionMatcher

**Type:** `in`

Implemented in [`InConditionMatcherFactory.kt`](https://github.com/ahoo-wang/cosec/blob/main/InConditionMatcherFactory.kt), this matcher checks if a string part exists within a supplied set of values.

```json
{
  "type": "in",
  "part": "header:X-Client-Type",
  "values": ["web", "mobile", "api"]
}

```

### RegularConditionMatcher

**Type:** `regex`

The `RegularConditionMatcher` (source: [`RegularConditionMatcherFactory.kt`](https://github.com/ahoo-wang/cosec/blob/main/RegularConditionMatcherFactory.kt)) applies Java regular expressions to request parts for complex pattern matching.

```json
{
  "type": "regex",
  "part": "path",
  "pattern": "^/api/v[0-9]+/.*$"
}

```

## Expression Evaluation Matchers

For scenarios requiring dynamic evaluation beyond static pattern matching, CoSec integrates two expression languages.

### SpELConditionMatcher

**Type:** `spel`

The `SpELConditionMatcher` (implemented in [`SpelConditionMatcherFactory.kt`](https://github.com/ahoo-wang/cosec/blob/main/SpelConditionMatcherFactory.kt)) evaluates Spring Expression Language expressions against the request context and security attributes.

```json
{
  "type": "spel",
  "expression": "#request.headers['X-Api-Key'] == 'secret'"
}

```

### OGNLConditionMatcher

**Type:** `ognl`

Located in [`OgnlConditionMatcherFactory.kt`](https://github.com/ahoo-wang/cosec/blob/main/OgnlConditionMatcherFactory.kt), this matcher uses OGNL (Object-Graph Navigation Language) for expression-based matching in non-Spring environments or legacy integrations.

```json
{
  "type": "ognl",
  "expression": "request.method == 'POST'"
}

```

## Rate Limiting and Throttling Matchers

These matchers enforce traffic control policies at the policy level, independent of external gateway configurations.

### RateLimiterConditionMatcher

**Type:** `rateLimiter`

Implemented in [`RateLimiterConditionMatcherFactory.kt`](https://github.com/ahoo-wang/cosec/blob/main/RateLimiterConditionMatcherFactory.kt), this matcher restricts requests per time window based on a configurable key extractor (e.g., client IP).

```json
{
  "type": "rateLimiter",
  "key": "clientIp",
  "limit": 100,
  "duration": "1m"
}

```

### GroupedRateLimiterConditionMatcher

**Type:** `groupedRateLimiter`

The `GroupedRateLimiterConditionMatcher` (source: [`GroupedRateLimiterConditionMatcherFactory.kt`](https://github.com/ahoo-wang/cosec/blob/main/GroupedRateLimiterConditionMatcherFactory.kt)) extends rate limiting to support distinct limits per group (tenant, user, or custom attribute).

```json
{
  "type": "groupedRateLimiter",
  "groupKey": "tenantId",
  "limit": 1000,
  "duration": "1h"
}

```

## How Built-in Matchers Are Registered and Executed

Understanding the lifecycle of ConditionMatchers ensures proper debugging and extension.

### Factory Registration

Upon Spring context startup, `MatcherFactoryRegister` (located in [`cosec-spring-boot-starter/src/main/kotlin/me/ahoo/cosec/spring/boot/starter/policy/MatcherFactoryRegister.kt`](https://github.com/ahoo-wang/cosec/blob/main/cosec-spring-boot-starter/src/main/kotlin/me/ahoo/cosec/spring/boot/starter/policy/MatcherFactoryRegister.kt)) scans for all beans implementing `ConditionMatcherFactory`. It registers each discovered factory with the `ConditionMatcherFactoryProvider` singleton using the factory's `type` constant as the lookup key.

### Policy Deserialization

When parsing policy JSON or YAML, `JsonConditionMatcherSerializer` (in [`cosec-core/src/main/kotlin/me/ahoo/cosec/serialization/JsonConditionMatcherSerializer.kt`](https://github.com/ahoo-wang/cosec/blob/main/cosec-core/src/main/kotlin/me/ahoo/cosec/serialization/JsonConditionMatcherSerializer.kt)) extracts the `type` field, retrieves the corresponding factory via `ConditionMatcherFactoryProvider.getRequired(type)`, and invokes the factory's `create` method to instantiate the matcher.

### Runtime Evaluation

At request time, the `AuthorizationGatewayFilter` (or servlet filter) calls `ConditionMatcher.match(request, securityContext)`. The concrete implementation—whether `PathConditionMatcher`, `InRoleConditionMatcher`, or `SpelConditionMatcher`—executes its specific logic against the request attributes and returns a boolean result.

## Practical Policy Configuration Examples

### Complex Boolean Logic

Combine multiple matchers using the `bool` type to enforce multi-factor authorization:

```json
{
  "policyId": "secure-admin-api",
  "condition": {
    "type": "bool",
    "and": [
      { "type": "authenticated" },
      {
        "type": "bool",
        "or": [
          { "type": "inRole", "roles": ["ADMIN"] },
          { "type": "inRole", "roles": ["SUPERUSER"] }
        ]
      },
      { "type": "path", "path": "/admin/api/**" }
    ]
  },
  "action": {
    "type": "allow"
  }
}

```

### Multi-Tenant Rate Limiting

Apply per-tenant request throttling using the grouped rate limiter:

```json
{
  "policyId": "tenant-throttle",
  "condition": {
    "type": "groupedRateLimiter",
    "groupKey": "tenantId",
    "limit": 500,
    "duration": "5m"
  },
  "action": {
    "type": "allow"
  }
}

```

### SpEL-Based Dynamic Checks

Use Spring expressions for header validation without custom code:

```json
{
  "policyId": "api-key-check",
  "condition": {
    "type": "spel",
    "expression": "#request.headers['X-API-Version'] matches '2\\\\.0'"
  },
  "action": {
    "type": "allow"
  }
}

```

## Summary

- **CoSec includes 16 built-in ConditionMatchers** covering logical operations, context validation, string pattern matching, expression evaluation, and rate limiting.
- **Each matcher follows the Factory pattern**, implementing `ConditionMatcherFactory` and registering automatically via `ConditionMatcherFactoryProvider`.
- **Source files are organized by function**: context matchers reside in `policy/condition/context/`, part matchers in `policy/condition/part/`, and limiters in `policy/condition/limiter/`.
- **Policy definitions use the `type` field** to reference factories, with configuration parameters specific to each matcher implementation.
- **Extension is straightforward**: implement `ConditionMatcherFactory` as a Spring bean to add custom matchers alongside built-ins.

## Frequently Asked Questions

### How do I create a custom ConditionMatcher in CoSec?

Implement the `ConditionMatcherFactory` interface and define a unique `type` constant. Register your implementation as a Spring bean (e.g., using `@Component`). The `MatcherFactoryRegister` will automatically discover and register it with `ConditionMatcherFactoryProvider`, making it available in policy JSON using your custom type.

### What is the difference between the `bool` and `all` matchers?

The `all` matcher (type: `all`) is a constant matcher that always returns `true`, useful for default allow/deny policies. The `bool` matcher (type: `bool`) is a logical combinator that evaluates nested `and` or `or` arrays of other matchers, enabling complex boolean logic without writing code.

### When should I use SpEL versus OGNL expression matchers?

Use **SpEL** (type: `spel`) when running CoSec within a Spring ecosystem, as it provides tight integration with Spring's bean context and security expressions. Use **OGNL** (type: `ognl`) for lightweight deployments or non-Spring environments where you need expression evaluation without Spring dependencies.

### How does `groupedRateLimiter` differ from the standard `rateLimiter`?

The standard `rateLimiter` (type: `rateLimiter`) applies a single global limit based on a key (like client IP). The `groupedRateLimiter` (type: `groupedRateLimiter`) maintains separate rate-limit counters per distinct group value (like tenant ID or user ID), allowing you to enforce "100 requests per minute per user" rather than "100 requests per minute total."