# How to Add Bearer Token Authentication to CoApi Clients

> Add Bearer token authentication to CoApi clients by implementing ExpirableTokenProvider and registering BearerTokenFilter. Secure your API requests automatically.

- Repository: [Ahoo Wang/coapi](https://github.com/ahoo-wang/coapi)
- Tags: how-to-guide
- Published: 2026-02-23

---

**Implement `ExpirableTokenProvider` to supply tokens and register `BearerTokenFilter` as a Spring bean to automatically inject `Authorization: Bearer <token>` headers into every outbound request.**

CoApi, the Spring-based open-source API client framework from the `ahoo-wang/coapi` repository, provides a lightweight, pluggable authentication mechanism built around reactive filters and token providers. Adding Bearer token authentication to your CoApi clients requires implementing a token supply interface and exposing a filter bean that the framework automatically wires into the `WebClient` request pipeline.

## Understanding CoApi's Authentication Architecture

CoApi's authentication system centers on two core components in the `me.ahoo.coapi.spring.client.reactive.auth` package: the `ExpirableTokenProvider` interface and the `BearerTokenFilter` class.

### The ExpirableTokenProvider Interface

The `ExpirableTokenProvider` interface defines the contract for supplying authentication tokens that may expire and require refresh. Located in [`spring/src/main/kotlin/me/ahoo/coapi/spring/client/reactive/auth/ExpirableTokenProvider.kt`](https://github.com/ahoo-wang/coapi/blob/main/spring/src/main/kotlin/me/ahoo/coapi/spring/client/reactive/auth/ExpirableTokenProvider.kt), this interface extends `HeaderValueProvider` and provides the raw token value that filters inject into HTTP headers.

### The BearerTokenFilter Filter

`BearerTokenFilter`, defined in [`spring/src/main/kotlin/me/ahoo/coapi/spring/client/reactive/auth/BearerTokenFilter.kt`](https://github.com/ahoo-wang/coapi/blob/main/spring/src/main/kotlin/me/ahoo/coapi/spring/client/reactive/auth/BearerTokenFilter.kt), extends `HeaderSetFilter` to automatically set the `Authorization` header on every request. The filter uses `BearerHeaderValueMapper` (an inner object within the same file) to prefix the raw token with `Bearer ` before injection. When `WebClientFactoryBean` constructs the reactive client, it automatically detects and applies any `HeaderSetFilter` beans registered in the Spring context.

## Implementing Bearer Token Authentication in CoApi

Follow these steps to add Bearer token authentication to your CoApi reactive client.

### Step 1: Create a Token Provider

Implement `ExpirableTokenProvider` to handle token retrieval, caching, and refresh logic. For simple use cases, extend `CachedExpirableTokenProvider` from [`spring/src/main/kotlin/me/ahoo/coapi/spring/client/reactive/auth/CachedExpirableTokenProvider.kt`](https://github.com/ahoo-wang/coapi/blob/main/spring/src/main/kotlin/me/ahoo/coapi/spring/client/reactive/auth/CachedExpirableTokenProvider.kt) to reuse caching semantics.

```kotlin
import me.ahoo.coapi.spring.client.reactive.auth.ExpirableTokenProvider
import java.time.Instant

class MyBearerTokenProvider : ExpirableTokenProvider {
    private var cachedToken: String? = null
    private var expiry: Instant = Instant.MIN

    override fun getHeaderValue(): String {
        if (Instant.now().isAfter(expiry)) {
            cachedToken = fetchNewToken()
            expiry = Instant.now().plusSeconds(3600)
        }
        return cachedToken ?: ""
    }

    private fun fetchNewToken(): String {
        // Replace with your OAuth2 server call or secret retrieval
        return "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
    }
}

```

### Step 2: Register the BearerTokenFilter

Expose your token provider and the `BearerTokenFilter` as Spring beans. The filter constructor accepts an `ExpirableTokenProvider` and automatically coordinates with `WebClientFactoryBean` to insert the header.

```kotlin
import me.ahoo.coapi.spring.client.reactive.auth.BearerTokenFilter
import me.ahoo.coapi.spring.client.reactive.auth.ExpirableTokenProvider
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration
class CoApiAuthConfig {

    @Bean
    fun bearerTokenProvider(): ExpirableTokenProvider = MyBearerTokenProvider()

    @Bean
    fun bearerTokenFilter(bearerTokenProvider: ExpirableTokenProvider): BearerTokenFilter {
        return BearerTokenFilter(bearerTokenProvider)
    }
}

```

With these beans registered, `WebClientFactoryBean` in [`spring/src/main/kotlin/me/ahoo/coapi/spring/client/reactive/WebClientFactoryBean.kt`](https://github.com/ahoo-wang/coapi/blob/main/spring/src/main/kotlin/me/ahoo/coapi/spring/client/reactive/WebClientFactoryBean.kt) automatically adds the filter to the client builder, ensuring every request includes the `Authorization` header.

### Step 3: Consume the Authenticated Client

Inject `WebClientFactoryBean` into your service to create fully configured `WebClient` instances. All outgoing requests automatically carry the Bearer token.

```kotlin
import me.ahoo.coapi.spring.client.reactive.WebClientFactoryBean
import org.springframework.stereotype.Service

@Service
class GitHubService(
    private val webClientFactoryBean: WebClientFactoryBean
) {
    suspend fun listRepos(user: String): String {
        val client = webClientFactoryBean.create()
        return client.get()
            .uri("https://api.github.com/users/$user/repos")
            .retrieve()
            .bodyToMono(String::class.java)
            .awaitSingle()
    }
}

```

The resulting HTTP requests include the header:

```text
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

```

## Synchronous Client Support

For synchronous clients using `RestClientFactoryBean` from [`spring/src/main/kotlin/me/ahoo/coapi/spring/client/sync/RestClientFactoryBean.kt`](https://github.com/ahoo-wang/coapi/blob/main/spring/src/main/kotlin/me/ahoo/coapi/spring/client/sync/RestClientFactoryBean.kt), use a `ClientHttpRequestInterceptor` instead of a reactive filter. The pattern remains identical: implement the interceptor to read from the same `ExpirableTokenProvider` and manually set the `Authorization` header.

```kotlin
import me.ahoo.coapi.spring.client.reactive.auth.ExpirableTokenProvider
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpRequest
import org.springframework.http.client.ClientHttpRequestExecution
import org.springframework.http.client.ClientHttpRequestInterceptor
import org.springframework.http.client.ClientHttpResponse

class BearerAuthInterceptor(
    private val tokenProvider: ExpirableTokenProvider
) : ClientHttpRequestInterceptor {
    
    override fun intercept(
        request: HttpRequest,
        body: ByteArray,
        execution: ClientHttpRequestExecution
    ): ClientHttpResponse {
        request.headers.set(
            HttpHeaders.AUTHORIZATION,
            "Bearer ${tokenProvider.getHeaderValue()}"
        )
        return execution.execute(request, body)
    }
}

```

Register this interceptor in your Spring configuration to apply Bearer authentication to synchronous CoApi clients.

## Summary

- **CoApi** uses `BearerTokenFilter` in [`spring/src/main/kotlin/me/ahoo/coapi/spring/client/reactive/auth/BearerTokenFilter.kt`](https://github.com/ahoo-wang/coapi/blob/main/spring/src/main/kotlin/me/ahoo/coapi/spring/client/reactive/auth/BearerTokenFilter.kt) to inject `Authorization` headers automatically.
- Implement `ExpirableTokenProvider` to supply tokens with refresh logic, or reuse `CachedExpirableTokenProvider` for built-in caching.
- Exposing `BearerTokenFilter` as a Spring bean enables automatic discovery by `WebClientFactoryBean`, requiring no manual client configuration.
- For synchronous clients, implement `ClientHttpRequestInterceptor` using the same token provider pattern.
- The `BearerHeaderValueMapper` automatically prefixes tokens with `Bearer `, ensuring RFC 6750 compliance.

## Frequently Asked Questions

### How does BearerTokenFilter automatically add the Authorization header?

`BearerTokenFilter` extends `HeaderSetFilter`, which implements Spring's `ExchangeFilterFunction`. When declared as a bean, `WebClientFactoryBean` automatically collects all `HeaderSetFilter` instances and adds them to the `WebClient` builder. The filter invokes your `ExpirableTokenProvider` for each request, maps the value through `BearerHeaderValueMapper` to add the `Bearer ` prefix, and sets the `Authorization` header before the request executes.

### Can I use synchronous RestTemplate-based clients with CoApi Bearer authentication?

Yes. While `BearerTokenFilter` is designed for reactive `WebClient` instances, synchronous clients built via `RestClientFactoryBean` support authentication through `ClientHttpRequestInterceptor`. Implement an interceptor that references your `ExpirableTokenProvider`, manually construct the `Bearer ` prefixed header value, and add it to the request headers via `HttpHeaders.AUTHORIZATION`. Register the interceptor as a bean to apply it to the sync client.

### How do I handle token expiration and caching in CoApi?

Implement `ExpirableTokenProvider` to track expiration timestamps and refresh logic, or extend `CachedExpirableTokenProvider` which provides a template for caching tokens until expiry. Your implementation of `getHeaderValue()` should check the current time against the expiry instant, fetch a new token from your OAuth2 server or secret manager when expired, and return the valid token string. The filter calls this method on every request, ensuring tokens are refreshed transparently.