How to get bearer token from header of a request in java spring boot?
Asked Answered
K

9

30

Hi what trying to achieve is to get bearer token that submited from front end in java spring boot RESTApi controller and do another request using feign client to another microservices? here is what i do

enter image description here

image above is how i do my request from postman, and here is my controller code :

@Operation(summary = "Save new")
@PostMapping("/store")
public ResponseEntity<ResponseRequest<TransDeliveryPlanning>> saveNewTransDeliveryPlanning(
        @Valid @RequestBody InputRequest<TransDeliveryPlanningDto> request) {

    TransDeliveryPlanning newTransDeliveryPlanning = transDeliveryPlanningService.save(request);

    ResponseRequest<TransDeliveryPlanning> response = new ResponseRequest<TransDeliveryPlanning>();

    if (newTransDeliveryPlanning != null) {
        response.setMessage(PESAN_SIMPAN_BERHASIL);
        response.setData(newTransDeliveryPlanning);
    } else {
        response.setMessage(PESAN_SIMPAN_GAGAL);
    }

    return ResponseEntity.ok(response);
}

and here is how my service look like :

public TransDeliveryPlanning save(InputRequest<TransDeliveryPlanningDto> request) {
       Future<List<PartnerDto>> initPartners = execs.submit(getDataFromAccount(transDeliveryPlanningDtSoDtoPartnerIdsSets));

}

public Callable<List<PartnerDto>> getDataFromAccount(Set<Long> ids) {

    String tokenString = "i should get the token from postman, how do i get it to here?";
    List<PartnerDto> partnerDtoResponse = accountFeignClient.getData("Bearer " + tokenString, ids);
    
    return () -> partnerDtoResponse;
}

as you can see, in "tokenString" there i put a string that i questioned about, how do i get it to there from postman?

Kellikellia answered 26/11, 2020 at 10:5 Comment(5)
ohk got now what problem are you facing?Licking
How do i get the bearer token value that submitted from postman (client)? As get it as string to replace "tokenString" value so i can use it to submit to another requestKellikellia
Are you using this token for any other purpose? For instance, for authenticating users in the application that calls the Feign client?Influent
yes i use it to call another microservice using feign client, and in the same gateway which is require same token because it's behind the same spring securityKellikellia
Do I understand correctly, that your first microservice, exposing '/store' endpoint, is using the token for authentication? If so, is it a standard authentication sceme (for example OAuth2) or a custom one (a custom JWT token authentication)?Politician
H
34

Although the suggested answers work, passing the token each time to FeignClient calls still not the best way to do it. I would suggest to create an interceptor for feign requests and there you can extract the token from RequestContextHolder and add it to request header directly. like this:

    @Component
    public class FeignClientInterceptor implements RequestInterceptor {
    
      private static final String AUTHORIZATION_HEADER = "Authorization";

      public static String getBearerTokenHeader() {
        return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getHeader("Authorization");
      }
    
      @Override
      public void apply(RequestTemplate requestTemplate) {

          requestTemplate.header(AUTHORIZATION_HEADER, getBearerTokenHeader());
       
      }
    }

this way you have a clean solution for your issue

Habsburg answered 3/12, 2020 at 14:58 Comment(0)
I
18

You have several options here.

For example, you can use a request scoped bean and, as you suggest, one MVC interceptor.

Basically, you need to define a wrapper for the token value:

public class BearerTokenWrapper {
   private String token;

   // setters and getters
}

Then, provide an implementation of an MVC HandlerInterceptor:

public class BearerTokenInterceptor extends HandlerInterceptorAdapter {

  private BearerTokenWrapper tokenWrapper;

  public BearerTokenInterceptor(BearerTokenWrapper tokenWrapper) {
    this.tokenWrapper = tokenWrapper;
  }

  @Override
  public boolean preHandle(HttpServletRequest request,
          HttpServletResponse response, Object handler) throws Exception {
    final String authorizationHeaderValue = request.getHeader("Authorization");
    if (authorizationHeaderValue != null && authorizationHeaderValue.startsWith("Bearer")) {
      String token = authorizationHeaderValue.substring(7, authorizationHeaderValue.length());
      tokenWrapper.setToken(token);
    }
    
    return true;
  }
}

This interceptor should be registered in your MVC configuration. For instance:

@EnableWebMvc
@Configuration
public class WebConfiguration extends WebConfigurer { /* or WebMvcConfigurerAdapter for Spring 4 */

  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(bearerTokenInterceptor());
  }

  @Bean
  public BearerTokenInterceptor bearerTokenInterceptor() {
      return new BearerTokenInterceptor(bearerTokenWrapper());
  }

  @Bean
  @Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
  public BearerTokenWrapper bearerTokenWrapper() {
    return new BearerTokenWrapper();
  }

}

With this setup, you can use the bean in your Service autowiring the corresponding bean:

@Autowired
private BearerTokenWrapper tokenWrapper;

//...


public TransDeliveryPlanning save(InputRequest<TransDeliveryPlanningDto> request) {
       Future<List<PartnerDto>> initPartners = execs.submit(getDataFromAccount(transDeliveryPlanningDtSoDtoPartnerIdsSets));

}

public Callable<List<PartnerDto>> getDataFromAccount(Set<Long> ids) {

    String tokenString = tokenWrapper.getToken();
    List<PartnerDto> partnerDtoResponse = accountFeignClient.getData("Bearer " + tokenString, ids);
    
    return () -> partnerDtoResponse;
}

Similar solutions has been provided here in stack overflow. See, for instance, this related question.

In addition to this Spring based approach, you can try something similar to the solution exposed in this other stackoverflow question.

Honestly I have never tested it, but it seems that you can provide the request header value right in the Feign client definition, in your case something like:

@FeignClient(name="AccountFeignClient")
public interface AccountFeignClient {    
    @RequestMapping(method = RequestMethod.GET, value = "/data")
    List<PartnerDto> getData(@RequestHeader("Authorization") String token, Set<Long> ids);
}

Of course, you can also a common Controller that other Controllers can extend. This Controller will provide the logic necessary to obtain the bearer token from the Authorization header and the HTTP request provided, but in my opinion any of the aforementioned solutions are better.

Influent answered 29/11, 2020 at 18:31 Comment(6)
@KeVin Could you try any of the proposed solutions?Influent
wait i trying another solution, but if the bounty expired before i can pick one of the solution here, i will start the bounty again to reward one of youKellikellia
Thank you very much @KeVin, I really appreciate that.Influent
This was a very helpful answer.. I've got a more complicated problem as I'm using Feign Hystrix with Spring Boot. For those with similar problems to solve, checkout this write up on Hystrix and Threadlocals medium.com/@saurav24081996/… and Hystrix plugins - github.com/Netflix/Hystrix/wiki/Plugins#concurrencystrategyGutturalize
Thank you very much @TonyMurphy, I really appreciate the comment.Influent
welcome @jccampanero.. just an extra update, solution with feign hystrix seems quite easy - just need to use Servlet filter to initiate the context, retrieve the bearer token from the servlet request header and then use HystrixRequestVariableDefault to store the token for later use github.com/Netflix/Hystrix/issues/92#issuecomment-260548068Gutturalize
S
14

An easy way to get Bearer Token from the header is to use @RequestHeader with the header name.

See code sample below

@PostMapping("/some-endpoint")
public ResponseEntity<String> someClassNmae(@RequestHeader("Authorization") String bearerToken) {

   System.out.println(bearerToken); // print out bearer token

   // some more code
}
Spinode answered 1/6, 2022 at 23:18 Comment(0)
K
4

Use this annotations to get the header information returned by the front end: @RequestHeader("Authorization") String token

Example:

@GetMapping("/hello")
    public void hello(@RequestHeader("Authorization") String token){
Kilk answered 19/9, 2022 at 3:44 Comment(0)
M
3

I had a similar case. I was intercepting the requests from one microservice, getting the token and setting it my new ApiClient and calling endpoint from another microservice using this ApiClient. But I really don't know if there is possibility to pre-configure feign client. One thing that you can do is to create DefaultApiFilter, intercept the request, save the token in your database (or set it to some static variable, some singleton class or something similar) and then call in it your service method when trying to use the FeignClient:

package com.north.config;

import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

@Component
public class DefaultApiFilter implements Filter {


@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, 
FilterChain filterChain) throws IOException, ServletException {
    HttpServletRequest req = (HttpServletRequest) servletRequest;

    String auth = req.getHeader("Authorization");

    //TODO if you want you can persist your token here and use it on other place

    //TODO This may be used for verification if it comes from the right endpoint and if you should save the token
    final String requestURI = ((RequestFacade) servletRequest).getRequestURI();

    filterChain.doFilter(servletRequest, servletResponse);
    }
}

This doFilter method will always be executed before any endpoint is called, and later the endpoint will be called.

And later use it when calling the accountFeignClient.getData("Bearer " + tokenString, ids); you can get it from your database (or from any other place that you kept it) and set it here.

Maul answered 29/11, 2020 at 19:6 Comment(0)
K
2

i got the answer but i think there i will still wait for better option, since my answer here is i have to add @RequestHeader in every controller to get the value of my token and get the token with String token = headers.getFirst(HttpHeaders.AUTHORIZATION);, and here is my complete controller :

@Operation(summary = "Save new")
@PostMapping("/store")
public ResponseEntity<ResponseRequest<TransDeliveryPlanning>> saveNewTransDeliveryPlanning(@RequestHeader HttpHeaders headers, 
        @Valid @RequestBody InputRequest<TransDeliveryPlanningDto> request) {

    String token = headers.getFirst(HttpHeaders.AUTHORIZATION);

    TransDeliveryPlanning newTransDeliveryPlanning = transDeliveryPlanningService.save(token, request);

    ResponseRequest<TransDeliveryPlanning> response = new ResponseRequest<TransDeliveryPlanning>();

    if (newTransDeliveryPlanning != null) {
        response.setMessage(PESAN_SIMPAN_BERHASIL);
        response.setData(newTransDeliveryPlanning);
    } else {
        response.setMessage(PESAN_SIMPAN_GAGAL);
    }

    return ResponseEntity.ok(response);
}

and i read somewhere there is something called Interceptor so we don't have to type @RequestHeader in every controller i think, but i dunno if that the solution or how to use it properly. if someone can do this with something better, i will accept yours as answer

Kellikellia answered 29/11, 2020 at 13:53 Comment(0)
E
0

I think the answer below from @stacker is correct but also I think is somehow incomplete and missing the "how to use it in Feign".

For the sake of the example, I will provide a real use case where you can intercept the User-Agent of the caller to your service and forward this in the Feign call

Assuming that you use Feign clients based on annotations this is how you can use the interceptor in all your Feign clients calls without any extra code

@Configuration
@EnableFeignClients(
    defaultConfiguration = DefaultFeignConfiguration.class
)
public class FeignConfig
{
}
@Configuration
@Import(FeignClientsConfiguration.class)
public class DefaultFeignConfiguration
{
    @Bean
    public RequestInterceptor userAgentHeaderInterceptor() {
        return UserAgentHeaderInterceptor();
    } 
}

This is the User-Agent interceptor class

public class UserAgentHeaderInterceptor extends BaseHeaderInterceptor
{

    private static final String USER_AGENT = "User-Agent";


    public UserAgentHeaderInterceptor()
    {
        super(USER_AGENT);
    }
}
public class BaseHeaderInterceptor implements RequestInterceptor
{

    private final String[] headerNames;


    public BaseHeaderInterceptor(String... headerNames)
    {
        this.headerNames = headerNames;
    }


    @Override
    public void apply(RequestTemplate template)
    {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

        if (attributes != null)
        {
            HttpServletRequest httpServletRequest = attributes.getRequest();

            for (String headerName : headerNames)
            {
                String headerValue = httpServletRequest.getHeader(headerName);
                if (headerValue != null && !headerValue.isEmpty())
                {
                    template.header(headerName, headerValue);
                }
            }
        }
    }
}

In your case, you just need to either take this base class and create your own interceptor the same way as the UserAgentHeaderInterceptor

Edora answered 4/12, 2020 at 18:19 Comment(0)
V
0

You can obtain a token from the security context using the following Java code:

import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.jwt.Jwt;
 ...

Jwt authenticationToken = (Jwt) SecurityContextHolder.getContext()
                                                     .getAuthentication()
                                                     .getCredentials();
String tokenString = authenticationToken.getTokenValue();
Vivi answered 20/9, 2023 at 16:29 Comment(0)
B
-2

You could create this simple static method in a utility class, and reuse this method directly.

import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

public class BearerTokenUtil {

  public static String getBearerTokenHeader() {
    return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getHeader("Authorization");
  }
}

Your service would then look like this

public TransDeliveryPlanning save(InputRequest<TransDeliveryPlanningDto> request) {
       Future<List<PartnerDto>> initPartners = execs.submit(getDataFromAccount(transDeliveryPlanningDtSoDtoPartnerIdsSets));
}

public Callable<List<PartnerDto>> getDataFromAccount(Set<Long> ids) {
    List<PartnerDto> partnerDtoResponse = accountFeignClient.getData(BearerTokenUtil.getBearerTokenHeader(), ids);
    return () -> partnerDtoResponse;
}
Bedford answered 2/12, 2020 at 7:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.