Adding JWT MtM Authentication

Overview

Atoti Limits includes native support for JSON Web Tokens. We can utilize this support to send MtM requests using the Authorization: Jwt ... header.

note

This is the default authentication mechanism in Atoti Limits, but we will show how it is implemented nonetheless to provide a sample extension mechanism.

Using the default support

To use the native support, specify the following properties in both Atoti Limits and your connected server:

limits:
  autoconfiguration:
    service-principal: admin // this specifies the principal user designated to invoke MtM request with JWT MtM authentication

How it works

As described in Adding Custom Machine-to-Machine (MtM) Authentication, we need to add some custom implementations to our code.

1. Add a custom ILimitsRestClientBuilder bean in the Connected Server and Atoti Limits.

This example is an implementation of ILimitsRestClientBuilder, which uses JWT authentication:

@Getter
public class LimitsJwtRestClientBuilder implements ILimitsRestClientBuilder {

  protected final RestClient.Builder restClientBuilder;

  // We inject any services we need into our provider
  public LimitsJwtRestClientBuilder(
      // this is used to get or generate the JWT
      IJwtService jwtService, 
      UserDetailsService userDetailsService, 
      // this is used to get the authorities of the service user
      // we use this class to pull in properties, but you could use any property extraction mechanism
      LimitsConnectionConfigurationProperties limitsConnectionConfigurationProperties
  ) {

    // we build the client builder to be used for requests
    this.restClientBuilder =
        buildRestClient(jwtService, userDetailsService, limitsConnectionConfigurationProperties);
  }

  private RestClient.Builder buildRestClient(
      IJwtService jwtService,
      UserDetailsService userDetailsService,
      LimitsConnectionConfigurationProperties limitsConnectionConfigurationProperties) {
    String servicePrincipal =
        limitsConnectionConfigurationProperties.getAutoconfiguration().getServicePrincipal();
    if (servicePrincipal == null) {
      throw new LimitsRuntimeException(
          "You must specify the `limits.autoconfiguration.service-principal` property if you are using JWT machine-to-machine authentication!");
    }
    Collection<String> authorities =
        userDetailsService.loadUserByUsername(servicePrincipal).getAuthorities().stream()
            .map(GrantedAuthority::getAuthority)
            .collect(Collectors.toSet());
    String jwt = jwtService.getToken(servicePrincipal, authorities);
    // here is where we set the `Authorization: Jwt ...` header
    return RestClient.builder().defaultHeader(AUTHORIZATION, "Jwt " + jwt);
  }
}

2. Expose your custom ILimitsRestClientBuilder bean in the Spring context

Once you have written your bean you can expose it to the Spring context.