How to have JWT authentication between micro services in kubernetes cluster

11/25/2019

We have 8 java microservices talking to each other in kubeneters cluster. Each microservice is bundled with auth library which intercepts and validates/renews JWT token for each REST request to controllers.

Scenario: From Frontend, we get access token for the first time, Authentication gets successful. Lets say

  1. Frontend hit 'Microservice A' with access token - Successful
  2. 'Microservice A' internally hits 'Microservice B' via restTemplate. My 'Microservice B' also needs logged in user details.

Issue: I have to pass same access token from 'A' to 'B' but I am not able to get access token in Controller/Service logic but can get only in filters where token is being validated. I can get token in Rest Controllers by adding following argument in all rest methods in controller:

@RequestHeader (name="Authorization") String token

But I dont want to go with this approach as I have to pass this token to everywhere till end and have to declare this argument in all APIS.

I want to get token from TokenStore by passing authentication object. We are using Oauth2 and I checked the code in library, There are many tokenStore providers.

In DefaultTokenServices.java class, I am calling

Authentication auth = SecurityContextHolder.getContext().getAuthentication() // Passed this auth to tokenStore
String token = tokenStore.getAccessToken(auth).getValue(); // NullPointerException

My code is going through JWTTokenStore provider which is returning null. I checked, there is a provider called InMemoryTokenStore.class which actually extrActs token from store. But my flow is not going into in memory implementation.

Is there any way I can get token afterwards without grabbing it in controller via arguments? or how can I enable/use inMemoryTokenStore?

Also recommend something better for kubernetes intercommunication authentication?

TIA

-- Roobal Jindal
authentication
java
jwt
kubernetes
microservices

1 Answer

11/25/2019

It looks like you're using Spring (and Spring Security), so I believe the relevant part of the docs is the part on Bearer Token Propagation.

Its recommendation is to use a WebClient (the recommended replacement for RestTemplate as of Spring 5) that uses the provided ServletBearerExchangeFilterFunction to automagically propagate the JWT token from the incoming request into the outgoing request:

@Bean
public WebClient rest() {
    return WebClient.builder()
            .filter(new ServletBearerExchangeFilterFunction())
            .build();
}

On RestTemplate, the docs say:

"There is no dedicated support for RestTemplate at the moment, but you can achieve propagation quite simply with your own interceptor"

and the following example is provided:

@Bean
RestTemplate rest() {
    RestTemplate rest = new RestTemplate();
    rest.getInterceptors().add((request, body, execution) -> {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null) {
            return execution.execute(request, body);
        }

        if (!(authentication.getCredentials() instanceof AbstractOAuth2Token)) {
            return execution.execute(request, body);
        }

        AbstractOAuth2Token token = (AbstractOAuth2Token) authentication.getCredentials();
        request.getHeaders().setBearerAuth(token.getTokenValue());
        return execution.execute(request, body);
    });
    return rest;
}

I don't believe you need to be looking at TokenStores if all you're trying to do is propagate the token. Remember everything relevant about a JWT should be inside the token itself. (Which is why the doc for the JwtTokenStore explains that it doesn't actually store anything, but just pulls info out of the token, and will return null for some methods, including the getAccessToken() method you're calling.)

-- Graham Lea
Source: StackOverflow