How CoSec Handles Authentication: JWT, OAuth2, and Custom Providers
CoSec handles authentication through a generic, type-safe Authentication<C, P> interface that transforms credentials into a CoSecPrincipal, supporting JWT tokens, OAuth2 social logins, and custom providers as injectable Spring beans.
CoSec (Context-Oriented Security) is a policy-based authorization framework for Spring applications that cleanly separates authentication from authorization. Whether you are securing reactive gateways or traditional MVC services, understanding how CoSec handles authentication allows you to integrate JWT validation, social logins, or proprietary credential schemes using the same extensible contract defined in the cosec-api module.
Core Authentication Architecture
The foundation of CoSec authentication is the Authentication<C, P> interface located in cosec-api/src/main/kotlin/me/ahoo/cosec/api/authentication/Authentication.kt. This contract is intentionally generic, allowing any credential type (C) to be verified and mapped to a principal type (P).
The Authentication Contract
All authentication providers implement the following signature:
interface Authentication<C : Credentials, out P : CoSecPrincipal> {
val supportCredentials: Class<C>
fun authenticate(credentials: C): Mono<out P>
}
Implementations are stateless Spring beans. The framework selects the appropriate provider by matching the supportCredentials property to the credential type extracted from the incoming request (e.g., JwtCredentials, SocialCredentials). This design allows multiple authentication strategies to coexist without coupling.
Security Context Population
Once a provider successfully authenticates the credentials, it returns a CoSecPrincipal containing the user identity and granted authorities. The principal is immediately stored in a SecurityContext that downstream components—such as the policy engine and business controllers—access to enforce authorization decisions.
Built-in Authentication Methods
CoSec provides auto-configuration for two primary authentication mechanisms, controlled via application.yml properties.
JWT Token Authentication
When you provide a signing key, CoSec automatically configures JWT validation. Enable this by setting:
cosec:
authentication:
jwt:
secret: <base64-encoded-secret>
issuer: my-app
The JwtAuthenticationProvider (located in the cosec-jwt module) implements Authentication<JwtCredentials, CoSecPrincipal>. It extracts the token from the Authorization: Bearer <token> header, validates the signature and claims, and maps the JWT payload to a CoSecPrincipal. Because its supportCredentials returns JwtCredentials::class.java, it is automatically selected for requests containing Bearer tokens.
Social OAuth2 Authentication
CoSec integrates with JustAuth to provide out-of-the-box support for Google, GitHub, and other OAuth2 providers. This is orchestrated by CoSecSocialAuthenticationAutoConfiguration in cosec-spring-boot-starter/src/main/kotlin/me/ahoo/cosec/spring/boot/starter/authentication/social/CoSecSocialAuthenticationAutoConfiguration.kt.
Configure providers in your YAML:
cosec:
authentication:
social:
registration:
google:
type: google
client-id: <client-id>
client-secret: <client-secret>
redirect-uri: https://my-app.com/oauth/callback/google
github:
type: github
client-id: <client-id>
client-secret: <client-secret>
The flow works as follows:
- Auto-configuration creates a
JustAuthProviderfor each registration and registers them withSocialProviderManager. - Login request redirects to
/oauth/authorize/{provider}, returning aSocialCredentialsobject containing the authorization code. - Authentication is handled by
SocialAuthenticationincosec-social/src/main/kotlin/me/ahoo/cosec/social/SocialAuthentication.kt, which exchanges the code for an access token and fetches the user profile. - Principal conversion occurs via
SocialUserPrincipalConverter, transforming theSocialUserinto aCoSecPrincipalfor the security context.
Implementing Custom Authentication Providers
For non-standard requirements—such as API keys or LDAP—you can implement the Authentication interface directly. CoSec will automatically detect and register your bean.
@Component
class ApiKeyAuthenticationProvider : Authentication<ApiKeyCredentials, CoSecPrincipal> {
override val supportCredentials = ApiKeyCredentials::class.java
override fun authenticate(credentials: ApiKeyCredentials): Mono<CoSecPrincipal> {
// Validate against database or cache
return if (isValidKey(credentials.key)) {
Mono.just(CoSecPrincipal(
id = credentials.key,
roles = setOf("API_USER")
))
} else {
Mono.error(InvalidCredentialsException("Invalid API Key"))
}
}
}
No additional configuration is required; Spring’s component scanning injects your provider into the authentication chain.
Request Flow and Filter Integration
Authentication executes early in the request lifecycle, before the policy engine evaluates authorization rules. In reactive applications, ReactiveAuthorizationFilter (cosec-webflux/src/main/kotlin/me/ahoo/cosec/webflux/ReactiveAuthorizationFilter.kt) intercepts the request. For gateway scenarios, AuthorizationGatewayFilter (cosec-gateway/src/main/kotlin/me/ahoo/cosec/gateway/AuthorizationGatewayFilter.kt) performs the same role.
These filters:
- Extract credentials from headers or request parameters.
- Locate the matching
Authenticationbean viasupportCredentials. - Execute
authenticate()and populate theSecurityContext. - Proceed to authorization only if authentication succeeds.
Your controllers then access the principal directly:
@RestController
@RequestMapping("/api")
class ProfileController {
@GetMapping("/profile")
suspend fun getProfile(context: ReactiveSecurityContext): ProfileDto {
val principal = context.authentication.principal as CoSecPrincipal
return profileService.getById(principal.id)
}
}
Summary
- Pluggable Interface: All authentication flows implement
Authentication<C, P>incosec-api/src/main/kotlin/me/ahoo/cosec/api/authentication/Authentication.kt, enabling type-safe credential handling. - Auto-configuration: JWT and OAuth2 providers are instantiated automatically based on property files, with logic centralized in
CoSecSocialAuthenticationAutoConfiguration.kt. - Social Login: JustAuth integration via
SocialAuthentication.kthandles OAuth2 flows and converts social profiles toCoSecPrincipalobjects. - Custom Extensions: Implement the interface as a Spring component to add API-key, LDAP, or proprietary authentication without modifying core code.
- Filter Chain:
AuthorizationGatewayFilterandReactiveAuthorizationFiltertrigger authentication before policy evaluation, ensuring the security context is populated for downstream authorization.
Frequently Asked Questions
How do I enable JWT authentication in CoSec?
Enable JWT authentication by adding a signing key to your application.yml under cosec.authentication.jwt.secret. The auto-configuration in the cosec-jwt module then creates a JwtAuthenticationProvider bean that validates Authorization: Bearer headers and maps claims to a CoSecPrincipal.
Can I use multiple authentication methods at the same time?
Yes. CoSec supports simultaneous authentication strategies because each provider declares its supported credential type via the supportCredentials property. The framework selects the appropriate Authentication bean based on the credential type present in the request, allowing JWT and social login to coexist.
How does CoSec convert a social login to an internal principal?
The SocialAuthentication class delegates to a SocialUserPrincipalConverter (default: DirectSocialUserPrincipalConverter). This converter transforms the SocialUser object returned by JustAuth into a CoSecPrincipal containing the user ID and roles, which is then stored in the security context for authorization checks.
Where does authentication occur in the CoSec request pipeline?
Authentication occurs in the filter layer before authorization. AuthorizationGatewayFilter (for gateways) or ReactiveAuthorizationFilter (for WebFlux applications) invokes the configured Authentication bean immediately after credential extraction. Only after successful authentication does the request proceed to the policy engine for authorization decisions.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →