CoSec Security Extensions: JWT Authentication and OpenTelemetry Observability Explained

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:

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:

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

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:

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

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 →