According documentation need use AuthorizedClientServiceOAuth2AuthorizedClientManager instead of DefaultOAuth2AuthorizedClientManager

When operating outside of the context of a HttpServletRequest, use AuthorizedClientServiceOAuth2AuthorizedClientManager instead.

Answer from hellnn on Stack Overflow
🌐
Baeldung
baeldung.com › home › spring › spring cloud › provide an oauth2 token to a feign client
Provide an OAuth2 Token to a Feign Client | Baeldung
March 26, 2025 - For this, we add and configure the interceptor to OpenFeign. The interceptor manages the OAuth2 client and adds the access token to the request. The code backing this article is available on GitHub.
🌐
GitHub
github.com › int128 › feign-oauth2-example › blob › master › README.md
feign-oauth2-example/README.md at master · int128/feign-oauth2-example
Make a request without an access token and the server will return 401. ... {"error":"unauthorized", "error_description":"Full authentication is required to access this resource"} Acquire an access token. curl -v -u theId:theSecret \ http://localhost:8081/oauth/token \ -d grant_type=password \ -d username=theUser1 \ -d password=theResourceOwnerPassword \ -d scope=foo · {"access_token":"50480ab0-4616-449c-823b-e5eb41ebe44f", "token_type":"bearer", "refresh_token":"3c526955-848c-4c85-b22f-ef4879d4a2be", "expires_in":43199, "scope":"foo"}
Author: int128
🌐
GitHub
github.com › spring-attic › spring-cloud-security › issues › 87
Feign request interceptor and security context · Issue #87 · spring-attic/spring-cloud-security
December 23, 2015 - @Bean public RequestInterceptor requestTokenBearerInterceptor() { return new RequestInterceptor() { @Override public void apply(RequestTemplate requestTemplate) { OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) SecurityContextHolder.getContext().getAuthentication().getDetails(); requestTemplate.header("Authorization", "bearer " + details.getTokenValue()); } }; } This one executs, but it seems that this is triggered in different thread and context does not have any authentication. Line before invoking my feign client context is present.
Author: spring-attic
🌐
GitHub
github.com › loesak › spring-security-openfeign
GitHub - loesak/spring-security-openfeign: Bringing back Spring Security support for OpenFeign until they do
See https://docs.spring.io/spring-security/site/docs/5.3.2.RELEASE/reference/html5/#bearer-token-propagation · In addition to configuring your Spring Security OAuth Resource server, you can add a custom configuration to your OpenFeign clients to add a Feign Request Interceptor.
Author: loesak
Top answer
1 of 2
6

According documentation need use AuthorizedClientServiceOAuth2AuthorizedClientManager instead of DefaultOAuth2AuthorizedClientManager

When operating outside of the context of a HttpServletRequest, use AuthorizedClientServiceOAuth2AuthorizedClientManager instead.

2 of 2
5

So. I was playing with your solution in my free time. And found the simple solution:

just add SecurityContextHolder.getContext().authentication principle to your code OAuth2AuthorizeRequest request = OAuth2AuthorizeRequest.withClientRegistrationId(appClientId).build();

Should be like this:

val request = OAuth2AuthorizeRequest
                .withClientRegistrationId("keycloak") // <-- here your registered client from application.yaml
                .principal(SecurityContextHolder.getContext().authentication)
                .build()

Used packages:

implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.cloud:spring-cloud-starter-openfeign")
implementation("org.springframework.boot:spring-boot-starter-oauth2-client")

application.yaml:

spring:
  security:
    oauth2:
      client:
        registration:
          keycloak: # <--- It's your custom client. I am using keycloak
            client-id: ${SECURITY_CLIENT_ID}
            client-secret: ${SECURITY_CLIENT_SECRET}
            authorization-grant-type: client_credentials
            scope: openid # your scopes
        provider:
          keycloak: # <--- Here Registered my custom provider
            authorization-uri: ${SECURITY_HOST}/auth/realms/${YOUR_REALM}/protocol/openid-connect/authorize
            token-uri: ${SECURITY_HOST}/auth/realms/${YOUR_REALM}/protocol/openid-connect/token

feign:
  compression:
    request:
      enabled: true
      mime-types: application/json
    response:
      enabled: true
  client.config.default:
    connectTimeout: 1000
    readTimeout: 60000
    decode404: false
    loggerLevel: ${LOG_LEVEL_FEIGN:basic}

SecurityConfiguration:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
class SecurityConfiguration() : WebSecurityConfigurerAdapter() {

    @Throws(Exception::class)
    override fun configure(http: HttpSecurity) {
        // @formatter:off
        http
                .authorizeRequests { authorizeRequests ->
                    authorizeRequests
                            .antMatchers(HttpMethod.GET, "/test").permitAll() // Here my public endpoint which do logic with secured client enpoint
                            .anyRequest().authenticated()
                }.cors().configurationSource(corsConfigurationSource()).and()
                .csrf().disable()
                .cors().disable()
                .httpBasic().disable()
                .formLogin().disable()
                .logout().disable()
                .oauth2Client()
        // @formatter:on
    }

    @Bean
    fun authorizedClientManager(
            clientRegistration: ClientRegistrationRepository?,
            authorizedClient: OAuth2AuthorizedClientRepository?
    ): OAuth2AuthorizedClientManager? {
        val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder
                .builder()
                .clientCredentials()
                .build()
        val authorizedClientManager = DefaultOAuth2AuthorizedClientManager(clientRegistration, authorizedClient)
        authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
        return authorizedClientManager
    }

}

FeignClientConfiguration:

private val logger = KotlinLogging.logger {}

class FeignClientConfiguration(private val authorizedClientManager: OAuth2AuthorizedClientManager) {

    @Bean
    fun requestInterceptor(): RequestInterceptor = RequestInterceptor { template ->
        if (template.headers()["Authorization"].isNullOrEmpty()) {
            val accessToken = getAccessToken()
            logger.debug { "ACCESS TOKEN TYPE: ${accessToken?.tokenType?.value}" }
            logger.debug { "ACCESS TOKEN: ${accessToken?.tokenValue}" }
            template.header("Authorization", "Bearer ${accessToken?.tokenValue}")
        }
    }

    private fun getAccessToken(): OAuth2AccessToken? {
        val request = OAuth2AuthorizeRequest
                .withClientRegistrationId("keycloak") // <- Here you load your registered client
                .principal(SecurityContextHolder.getContext().authentication)
                .build()
        return authorizedClientManager.authorize(request)?.accessToken
    }

}

TestClient:

@FeignClient(
        name = "test",
        url = "http://localhost:8080",
        configuration = [FeignClientConfiguration::class]
)
interface TestClient {
    @GetMapping("/test")
    fun test(): ResponseEntity<Void> // Here my secured resource server endpoint. Expect 204 status
}
🌐
Medium
medium.com › @IlyasKeser › feignclient-interceptor-for-bearer-token-oauth-f45997673a1
FeignClient Interceptor for Bearer Token/OAuth | by Ilyas Keser | Medium
October 20, 2019 - Here an example for an interceptor as a Spring component. @Component public class FeignClientInterceptor implements RequestInterceptor { private static final String AUTHORIZATION_HEADER="Authorization"; private static final String TOKEN_TYPE = "Bearer"; @Override public void apply(RequestTemplate requestTemplate) { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (authentication != null && authentication.getDetails() instanceof OAuth2AuthenticationDetails) { OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) authentication.getDetails(); requestTemplate.header(AUTHORIZATION_HEADER, String.format("%s %s", TOKEN_TYPE, details.getTokenValue())); } } }
🌐
GitHub
github.com › spring-cloud › spring-cloud-netflix › issues › 159
Request Interceptors can't be add to the Feign builder · Issue #159 · spring-cloud/spring-cloud-netflix
January 18, 2015 - I want to use Feign together with spring cloud security especially with @EnableOAuth2Resource. When I request a resource with feign I got a 401. The reason is, that feign didn't include a token in the header. I created a request intercep...
Author: spring-cloud
🌐
GitHub
github.com › int128 › feign-oauth2-example
GitHub - int128/feign-oauth2-example: Example of Spring Cloud Feign and Spring Security OAuth2 · GitHub
December 10, 2016 - Make a request without an access token and the server will return 401. ... {"error":"unauthorized", "error_description":"Full authentication is required to access this resource"} Acquire an access token. curl -v -u theId:theSecret \ http://localhost:8081/oauth/token \ -d grant_type=password \ -d username=theUser1 \ -d password=theResourceOwnerPassword \ -d scope=foo · {"access_token":"50480ab0-4616-449c-823b-e5eb41ebe44f", "token_type":"bearer", "refresh_token":"3c526955-848c-4c85-b22f-ef4879d4a2be", "expires_in":43199, "scope":"foo"}
Find elsewhere
Top answer
1 of 3
7

If your JWT token provider is OAuth 2.0 compliant, you can configure the OAuth2FeignRequestInterceptor, with an OAuth2ProtectedResourceDetails object. This object is the base class for all OAuth 2.0 grant type information. In your case, I recommend using ResourceOwnerPasswordResourceDetails instead. This will allow you to configure an interceptor using a username and password.

@Configuration
public class OAuth2RequestInterceptorConfiguration {

    @Bean
    public OAuth2FeignRequestInterceptor requestInterceptor() {
        OAuth2ClientContext clientContext = new DefaultOAuth2ClientContext();
        OAuth2ProtectedResourceDetails resourceDetails =
            new ResourceOwnerPasswordResourceDetails();
        resourceDetails.setUsername("username");
        resourceDetails.setPassword("password");
        return new OAuth2FeignRequestInterceptor(clientContext, resourceDetails);
    }
}

For other cases, you will need to create your own RequestInterceptor

public class MyRequestInterceptor implements RequestInterceptor {

    private String jwt;
    private LocalDateTime expirationDate;

    @Override
    public void apply(RequestTemplate requestTemplate) {
        /* validate and refresh your token, this sample is not thread safe */
        if (LocalDateTime.now().isAfter(expirationDate)) {
            requestToken();
        }

        /* use the token */
        requestTemplate.header("Authorization: Bearer " + this.jwt);
    }
}
2 of 3
4

You can try with something like:

public class FeignConfiguration {

    @Value("${security.jwt.token}")
    private String jwtToken;

    @Bean
    public RequestInterceptor requestInterceptor() {
        @Override
        public void apply(RequestTemplate requestTemplate) {
            requestTemplate.header("Authorization", jwtToken);
        }
    }
}
🌐
Ordina-jworks
ordina-jworks.github.io › microservices › 2018 › 11 › 02 › Inter-service-communication.html
Communication in a distributed system with OpenFeign: Tips & Tricks - Kevin Van Houtte &mdash; Ordina JWorks Tech Blog
November 2, 2018 - When you want to send basic credentials you can just add an interceptor for the OpenFeign client and add the username and password. For only Bearer token communication, you can just pass it down in the request header of your method call.
🌐
Medium
zdenek-papez.medium.com › spring-boot-using-multiple-openfeign-clients-to-authenticate-rest-api-calls-52c74285ce3f
Spring Boot Using Multiple OpenFeign Clients To Authenticate REST API Calls | by Zdenek Papez | Medium
November 23, 2020 - Use configuration to define a RequestInterceptor that adds Authorization header with Bearer token to all Slack requests. In this article’s sample GitHub project, you can use SLACK_AUTH_TOKEN environment variable to provide the token.
🌐
Baeldung
baeldung.com › home › rest › setting request headers using feign
Setting Request Headers Using Feign | Baeldung
March 25, 2026 - 18:06:06.135 [main] DEBUG c.b.f.c.h.staticheader.BookClient - [BookClient#findByIsbn] Authorisation: Bearer 629e0af7-513d-4385-a5ef-cb9b341cedb5 · Multiple Request interceptors can also be applied to the Feign client. Though no guarantees are given concerning the order that they are applied. In this article, we’ve discussed how Feign client supports setting request headers. We implemented that using the @Headers, @HeaderMaps annotation, and request interceptors. The code backing this article is available on GitHub.
🌐
GitHub
github.com › spring-attic › spring-cloud-security › issues › 173
OAuth2FeignRequestInterceptor support for Spring Security 5 OAuth · Issue #173 · spring-attic/spring-cloud-security
January 25, 2019 - I'm upgrading from Spring Security OAuth to the OAuth support in Spring Security 5. My micro-services previously was using Feign to connect with other micro-services (micro-services are both resource servers and clients) and I was using OAuth2FeignRequestInterceptor to either obtain an token, use an existing token, or pass on a token that the calling micro-service itself received (Token Relay).
Author: spring-attic
🌐
GitHub
github.com › spring-cloud › spring-cloud-openfeign › issues › 417
Replacement for OAuth2FeignRequestInterceptor from spring-cloud-security? · Issue #417 · spring-cloud/spring-cloud-openfeign
October 21, 2020 - For my Feign Clients I need to add an RequestInterceptor which enhances the requests with an OAuth Bearer Token. I still use the OAuth2FeignRequestInterceptor. But it simply states @deprecated will move to Spring Cloud Openfeign in next major release · I need quite it's features as the oAuth provider Auth0 requires a non standard attribute "audience" - so I configure the interceptor with customized versions of DefaultOAuth2ClientContext, DefaultAccessTokenRequest, DefaultRequestEnhancer, ClientCredentialsAccessTokenProvider (which themselves all get @deprecated - but the Migration Guide doesn't really help me yet)
Author: spring-cloud
🌐
Springcloud
springcloud.io › post › 2022-01 › feign-token-relay
Spring Cloud Feign implements JWT token relay to deliver authentication information - Spring Cloud
January 12, 2022 - If we don’t turn on fault tolerance we can extract the authentication object JwtAuthenticationToken from the Spring Security provided SecurityContext object to the resource server which contains the JWT token and then we can implement Feign’s interceptor interface RequestInterceptor to place the token in the request header, with the following pseudo-code.
🌐
Medium
medium.com › @sachinsindhu › auth-token-refesh-using-feign-error-decoder-and-retryer-398368cf15a6
Auth Token refesh using feign error decoder , retryer and request interceptor | by Sachin Sindhu | Medium
September 19, 2023 - @RequiredArgsConstructor public class CustomRequestInterceptor implements RequestInterceptor { private final TokenRepository tokenRepository; private final LoginService loginService; @Override public void apply(RequestTemplate template) { // we can provide intercepting logic factory to handle each feign client seperately // here we are considering only single client so hard coding to work for ServiceAClient client only if (template.feignTarget().type().equals(ServiceAClient.class)) { Token token = tokenRepository.findToken("unique token identifier here"); if (token == null || Status.Expired.equals(token.getStatus())) { token = loginService.login(); } template.header("Authorization", "Bearer " + token.getToken()); } } }
🌐
OneUptime
oneuptime.com › home › blog › how to implement custom feign interceptors
How to Implement Custom Feign Interceptors
January 30, 2026 - Feign interceptors let you centralize ... request before it leaves your service. Key patterns include: Propagate authentication tokens from incoming requests...
Top answer
1 of 1
2

Edit

@FeignClient is now in maintenance mode, replaced by RestClient and HttpServiceProxyFactory. See below.

Authorizing @FeignClient requests

Use a RequestInterceptor to automatically add the authorization header.

With OAuth2, two strategies:

  • use the token already in the security context, but this requires that the following two conditions are met:
    1. the application sending the REST call is an oauth2ResourceServer - not an app configured with oauth2Login, the security of which is based on session cookies, not on Bearer tokens
    2. the request is sent on behalf of the resource owner of the "parent" request
  • configure the calling application as an OAuth2 client (additionally to OAuth2 resource server if it is a REST API with requests authorized with Bearer tokens) and use the OAuth2AuthorizedClientManager to get a new token

In Spring Boot apps, request interceptors decorated with @Component in the same package or any sub-package of the @Configuration with @EnableFeignClients are auto-detected: no need for explicit conf.

@FeignClient reusing the access token in the security context of an oauth2ResourceServer application

@Component
public class ForwardingBearerRequestInterceptor implements RequestInterceptor {

    @Override
    public void apply(RequestTemplate template) {
        final var auth = SecurityContextHolder.getContext().getAuthentication();
        if (auth instanceof JwtAuthenticationToken jwtAuth) {
            template.header(HttpHeaders.AUTHORIZATION, "Bearer %s".formatted(jwtAuth.getToken().getTokenValue()));
        }
    }
}

@FeignClient getting a new access token using an OAuth2 client registration

This applies in two scenarios:

  • the calling application is configured with oauth2Login. As a reminder, such applications are OAuth2 clients and the request they receive are authorized with session cookies. So there is no access token to forward in the security context. Tokens are in session and we access them using the OAuth2AuthorizedClientManager.
  • the calling application is configured with oauth2ResourceServer, but we need to use another client registration than the one used to get the token authorizing the incoming request. This happens for instance when the calling service uses the same client credentials, whoever sent the original request.
@Component
@RequiredArgsConstructor
public class OAuth2RegistrationRequestInterceptor implements RequestInterceptor {
    private final OAuth2AuthorizedClientManager authorizedClientManager;

    @Override
    public void apply(RequestTemplate template) {
        final var auth = SecurityContextHolder.getContext().getAuthentication();
        OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId("some-registration-id").principal(auth).build();
        final var authorizedClient = Optional.ofNullable(authorizedClientManager.authorize(authorizeRequest));
        authorizedClient.ifPresent(ac -> template.header(HttpHeaders.AUTHORIZATION, "Bearer %s".formatted(ac.getAccessToken().getTokenValue())));
    }
}

Using RestClient and HttpServiceProxyFactory

Spring Cloud put @FeignClient in maintenance mode when Spring Core introduced the HttpServiceProxyFactory for RestClient and WebClient, which serves the same purpose for declarative REST clients.

Configuration for OAuth2 authorization is a little more verbose. For this reason, I created a tiny Boot starter for it. Sample usage:

Provided that we have the following @HttpExchange describing the REST service to consume (I have those generated from OpenAPI specs):

@HttpExchange(accept = MediaType.APPLICATION_JSON_VALUE)
public interface KeycloakAdminApi {

    @GetExchange(url = "/{realm}/users/count")
    Long getTotalUsersCount(@PathVariable(name = "realm") String realm);
}

We can have the implementation generated to consume the remote REST service with the following:

@Bean
KeycloakAdminApi keycloakAdminApi(SpringAddonsRestClientSupport restSupport) {
    return restSupport.service("keycloak-admin-api", KeycloakAdminApi.class);
}

The configuration for the endpoint base-URL, authorization (Basic or OAuth2), and optionally for HTTP proxy, is done in application properties:

com:
  c4-soft:
      rest:
        client:
          keycloak-admin-api:
            base-url: ${keycloak-base-uri}/admin/realms
            authorization:
              oauth2:
                forward-bearer: true

The above re-uses the incoming Bearer token on an oauth2ResourceServer. See the doc for using a new token issued for any registration.

It is published on maven-central:

<dependency>
    <groupId>com.c4-soft.springaddons</groupId>
    <artifactId>spring-addons-starter-rest</artifactId>
    <version>7.8.10</version>
</dependency>