# CoSec Security Extensions: JWT Authentication and OpenTelemetry Observability Explained

> Explore CoSec Security Extensions for JWT authentication and OpenTelemetry observability. Enhance JVM application security and tracing with these powerful modules.

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

---

**CoSec provides modular security extensions that add JWT-based stateless authentication and OpenTelemetry distributed tracing to the core policy engine, enabling comprehensive security observability in JVM applications.**

The `ahoo-wang/cosec` repository delivers a policy-driven authorization framework designed for reactive and servlet-based Java applications. Its **CoSec security extensions** architecture allows developers to compose specific capabilities—such as JSON Web Token (JWT) verification and OpenTelemetry instrumentation—without bloating the runtime with unused features. These extensions integrate seamlessly with Spring Boot, Spring Cloud Gateway, and standard reactive stacks via interfaces like `SecurityContextParser`.

## JWT Extension: Stateless Token Authentication

The JWT extension implements complete token lifecycle management within the CoSec ecosystem. Located in the `cosec-jwt` module, it provides classes like `me.ahoo.cosec.jwt.Jwts`, `JwtTokenVerifier`, and `JwtTokenConverter` to handle issuance, signature verification, and principal extraction.

### How JWT Authentication Works

When a request arrives with an `Authorization: Bearer <token>` header, the `InjectSecurityContextParser` extracts the token and delegates to `JwtTokenConverter`. This converter uses `JwtTokenVerifier` to validate signatures (supporting HMAC algorithms like HS256) and map claims to a `CoSecPrincipal` object containing the subject, tenant ID, and authorities. The principal then feeds into the core `AuthorizationService` for policy evaluation.

### Issuing Signed JWT Tokens

To generate tokens programmatically, use the `Jwts` builder class as implemented in [`cosec-jwt/src/main/kotlin/me/ahoo/cosec/jwt/Jwts.kt`](https://github.com/ahoo-wang/cosec/blob/main/cosec-jwt/src/main/kotlin/me/ahoo/cosec/jwt/Jwts.kt):

```kotlin
import me.ahoo.cosec.jwt.Jwts
import me.ahoo.cosec.token.TokenAttributes

val attrs = TokenAttributes.builder()
    .subject("alice")
    .tenantId("demo")
    .addAuthority("ROLE_USER")
    .expireAfter(3600)
    .build()

val secret = "my-super-secret-key".toByteArray()
val token = Jwts.builder()
    .setAttributes(attrs)
    .signWith(secret)
    .compact()

println("Bearer $token")

```

This creates a compact JWT string signed with the provided secret key, suitable for returning to clients after successful primary authentication.

### Verifying Bearer Tokens

For resource servers verifying incoming requests, combine `JwtTokenVerifier` and `JwtTokenConverter` as defined in [`cosec-jwt/src/main/kotlin/me/ahoo/cosec/jwt/JwtTokenVerifier.kt`](https://github.com/ahoo-wang/cosec/blob/main/cosec-jwt/src/main/kotlin/me/ahoo/cosec/jwt/JwtTokenVerifier.kt):

```kotlin
import me.ahoo.cosec.jwt.JwtTokenVerifier
import me.ahoo.cosec.jwt.JwtTokenConverter
import me.ahoo.cosec.api.principal.CoSecPrincipal

val secret = "my-super-secret-key".toByteArray()
val verifier = JwtTokenVerifier(secret)
val converter = JwtTokenConverter(verifier)

val authHeader = "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
val principal: CoSecPrincipal = converter.parse(authHeader)

```

The resulting `CoSecPrincipal` contains the authenticated identity and authorization context required by the policy engine.

## OpenTelemetry Extension: Authorization Observability

The OpenTelemetry extension exports coarse-grained authorization traces to any OTLP collector. Implemented in the `cosec-opentelemetry` module, it uses `CoSecInstrumenter` and `CoSecAttributesExtractor` to capture policy evaluation metadata.

### Tracing Authorization Decisions

The `TracingAuthorization` class (from [`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)) wraps the core `AuthorizationService`. When `authorize()` is invoked, it creates an OpenTelemetry `Span` recording the policy name, decision result (`PERMIT` or `DENY`), tenant ID, and actor details. The `AuthorizationMono` utility handles reactive tracing for non-blocking pipelines.

### Manual Configuration

To enable tracing programmatically:

```kotlin
import io.opentelemetry.sdk.OpenTelemetrySdk
import io.opentelemetry.sdk.trace.SdkTracerProvider
import me.ahoo.cosec.opentelemetry.TracingAuthorization
import me.ahoo.cosec.core.AuthorizationService

val tracerProvider = SdkTracerProvider.builder().build()
val openTelemetry = OpenTelemetrySdk.builder()
    .setTracerProvider(tracerProvider)
    .buildAndRegisterGlobal()

val coreAuth: AuthorizationService = // obtain from container
val tracingAuth = TracingAuthorization(coreAuth)

```

### Spring Boot Configuration

Alternatively, use the starter with YAML configuration:

```yaml
cosec:
  opentelemetry:
    enabled: true
  jwt:
    secret: ${JWT_SECRET}

```

The `CoSecOpenTelemetryAutoConfiguration` class (located in [`cosec-spring-boot-starter/src/main/kotlin/me/ahoo/cosec/spring/boot/starter/opentelemetry/CoSecOpenTelemetryAutoConfiguration.kt`](https://github.com/ahoo-wang/cosec/blob/main/cosec-spring-boot-starter/src/main/kotlin/me/ahoo/cosec/spring/boot/starter/opentelemetry/CoSecOpenTelemetryAutoConfiguration.kt)) automatically wires the `TracingAuthorization` bean when `cosec.opentelemetry.enabled` is true and OpenTelemetry classes are present on the classpath.

## Additional Security Extensions

Beyond JWT and OpenTelemetry, CoSec provides several other modular extensions:

- **Social Authentication (JustAuth)**: Integrates OAuth providers like GitHub and Google through `JustAuthProvider` and `SocialUserConverter`, converting social logins into CoSec principals that can optionally flow into JWT tokens.
- **Spring Boot Starter**: The `cosec-spring-boot-starter` module auto-wires all components via `CosecAutoConfiguration`, conditionally loading OpenTelemetry beans only when `ConditionalOnOpenTelemetryEnabled` matches.
- **Gateway Filter**: The `AuthorizationGatewayFilter` enforces policies at the Spring Cloud Gateway layer. Implement it as follows:

```kotlin
import org.springframework.cloud.gateway.filter.GatewayFilterChain
import org.springframework.web.server.ServerWebExchange
import reactor.core.publisher.Mono
import me.ahoo.cosec.gateway.filter.AuthorizationGatewayFilter

class MyGatewayFilter(
    private val authFilter: AuthorizationGatewayFilter
) : GatewayFilter {
    override fun filter(exchange: ServerWebExchange, chain: GatewayFilterChain): Mono<Void> =
        authFilter.filter(exchange, chain)
}

```

## Integration Architecture

The extensions follow a unified request processing pipeline:

1. **Context Extraction**: `SecurityContextParser` (JWT or Social) extracts a `CoSecPrincipal` from incoming requests.
2. **Policy Evaluation**: The core `AuthorizationService` evaluates the principal against configured policies.
3. **Observability**: When enabled, `TracingAuthorization` creates OpenTelemetry spans capturing decision metadata via `CoSecAttributesExtractor`.
4. **Framework Integration**: Spring Boot starters and Gateway filters wire these components into the reactive processing chain without explicit bean configuration.

This modular design ensures that applications only load the bytecode and dependencies they explicitly require, keeping startup times fast while supporting enterprise-grade security patterns.

## Summary

- **CoSec security extensions** provide optional, composable capabilities for JWT authentication and OpenTelemetry observability alongside the core policy engine.
- The JWT extension handles token issuance via `Jwts.builder()`, verification through `JwtTokenVerifier`, and principal conversion using `JwtTokenConverter` located in `cosec-jwt/src/main/kotlin/me/ahoo/cosec/jwt/`.
- OpenTelemetry integration wraps `AuthorizationService` with `TracingAuthorization` to export authorization spans containing policy decisions and tenant context.
- Spring Boot auto-configuration and Gateway filters enable zero-code integration for reactive applications via `CosecAutoConfiguration` and `AuthorizationGatewayFilter`.
- All extensions reside in separate modules (e.g., `cosec-jwt`, `cosec-opentelemetry`) and integrate via standard interfaces like `SecurityContextParser` and `AuthenticationProvider`.

## Frequently Asked Questions

### How do I enable OpenTelemetry tracing in a CoSec Spring Boot application?

Add the `cosec-spring-boot-starter` dependency and set `cosec.opentelemetry.enabled: true` in your [`application.yml`](https://github.com/ahoo-wang/cosec/blob/main/application.yml). The `CoSecOpenTelemetryAutoConfiguration` class automatically creates the `TracingAuthorization` wrapper and `CoSecInstrumenter` beans when OpenTelemetry classes are detected on the classpath.

### What signing algorithms does the CoSec JWT extension support?

The JWT extension supports HMAC-based algorithms including HS256, as demonstrated in the `Jwts.builder().signWith(secret)` method implemented in [`Jwts.kt`](https://github.com/ahoo-wang/cosec/blob/main/Jwts.kt). The `JwtTokenVerifier` validates tokens using the same secret key byte array used during issuance.

### Can I use CoSec extensions without Spring Boot?

Yes. While the Spring Boot starter provides convenient auto-configuration, you can manually instantiate extension classes like `JwtTokenConverter`, `TracingAuthorization`, and `AuthorizationGatewayFilter` in any JVM application using the core `me.ahoo.cosec` APIs and reactive programming models.

### How does the Gateway filter interact with JWT verification?

The `AuthorizationGatewayFilter` extracts the `Authorization` header and delegates to a configured `SecurityContextParser` (typically the JWT converter via `InjectSecurityContextParser`). It then calls the `AuthorizationService` to evaluate policies before allowing the request to proceed to downstream services, effectively enforcing authentication and authorization at the edge.